Skip to content

Commit

Permalink
[GR-52189] Properly propagate NFI exceptions between backends.
Browse files Browse the repository at this point in the history
PullRequest: graal/17048
  • Loading branch information
rschatz committed May 9, 2024
2 parents 033c93a + e2d259f commit e3d8479
Show file tree
Hide file tree
Showing 42 changed files with 1,110 additions and 212 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -145,8 +145,9 @@ static TruffleObjectHandle getClosureObject(NativeTruffleEnv env, PointerBase cl

@CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished)
@CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class)
static boolean exceptionCheck(@SuppressWarnings("unused") NativeTruffleEnv env) {
return NativeClosure.pendingException.get() != null;
static boolean exceptionCheck(NativeTruffleEnv env) {
Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext context = lookupContext(env.context());
return context.language.getNFIState().hasPendingException;
}

@CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -56,8 +56,6 @@
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
import com.oracle.svm.core.handles.PrimitiveArrayView;
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
import com.oracle.svm.core.threadlocal.FastThreadLocalObject;
import com.oracle.svm.truffle.nfi.LibFFI.ClosureData;
import com.oracle.svm.truffle.nfi.LibFFI.NativeClosureHandle;
import com.oracle.svm.truffle.nfi.NativeAPI.NativeTruffleEnv;
Expand Down Expand Up @@ -222,8 +220,6 @@ private static PointerBase serializeStringRet(Object retValue) {
private static final CGlobalData<CCharPointer> errorMessageThread = CGlobalDataFactory.createCString("Failed to enter by thread for closure.");
private static final CGlobalData<CCharPointer> errorMessageIsolate = CGlobalDataFactory.createCString("Failed to enter by isolate for closure.");

static final FastThreadLocalObject<Throwable> pendingException = FastThreadLocalFactory.createObject(Throwable.class, "NativeClosure.pendingException");

@NeverInline("Prevent (bad) LibC object from being present in any reference map")
@Uninterruptible(reason = "Called while in Native state.")
private static int getErrno() {
Expand Down Expand Up @@ -273,11 +269,7 @@ static void invokeClosureBufferRet(@SuppressWarnings("unused") ffi_cif cif, Poin
private static int invokeClosureBufferRet0(Pointer ret, WordPointer args, ClosureData user, int errno) {
ErrnoMirror.errnoMirror.getAddress().write(errno);

try {
doInvokeClosureBufferRet(ret, args, user);
} catch (Throwable t) {
pendingException.set(t);
}
doInvokeClosureBufferRet(ret, args, user);

return ErrnoMirror.errnoMirror.getAddress().read();
}
Expand Down Expand Up @@ -342,11 +334,7 @@ static void invokeClosureVoidRet(@SuppressWarnings("unused") ffi_cif cif, @Suppr
private static int invokeClosureVoidRet0(WordPointer args, ClosureData user, int errno) {
ErrnoMirror.errnoMirror.getAddress().write(errno);

try {
doInvokeClosureVoidRet(args, user);
} catch (Throwable t) {
pendingException.set(t);
}
doInvokeClosureVoidRet(args, user);

return ErrnoMirror.errnoMirror.getAddress().read();
}
Expand Down Expand Up @@ -392,11 +380,7 @@ static void invokeClosureStringRet(@SuppressWarnings("unused") ffi_cif cif, Word
private static int invokeClosureStringRet0(WordPointer ret, WordPointer args, ClosureData user, int errno) {
ErrnoMirror.errnoMirror.getAddress().write(errno);

try {
doInvokeClosureStringRet(ret, args, user);
} catch (Throwable t) {
pendingException.set(t);
}
doInvokeClosureStringRet(ret, args, user);

return ErrnoMirror.errnoMirror.getAddress().read();
}
Expand Down Expand Up @@ -443,11 +427,7 @@ static void invokeClosureObjectRet(@SuppressWarnings("unused") ffi_cif cif, Word
private static int invokeClosureObjectRet0(WordPointer ret, WordPointer args, ClosureData user, int errno) {
ErrnoMirror.errnoMirror.getAddress().write(errno);

try {
doInvokeClosureObjectRet(ret, args, user);
} catch (Throwable t) {
pendingException.set(t);
}
doInvokeClosureObjectRet(ret, args, user);

return ErrnoMirror.errnoMirror.getAddress().read();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -142,12 +142,6 @@ static void execute(NativeTruffleContext ctx, ffi_cif cif, PointerBase ret, long
}

ffiCall(cif, WordFactory.pointer(functionPointer), ret, argPtrs, ErrnoMirror.errnoMirror.getAddress());

Throwable pending = NativeClosure.pendingException.get();
if (pending != null) {
NativeClosure.pendingException.set(null);
throw rethrow(pending);
}
} finally {
UnmanagedMemory.free(argPtrs);
}
Expand Down Expand Up @@ -176,9 +170,4 @@ private static void doFfiCall(ffi_cif cif, PointerBase fn, PointerBase rvalue, W
errnoMirror.write(LibC.errno());
}
}

@SuppressWarnings({"unchecked"})
private static <E extends Throwable> RuntimeException rethrow(Throwable ex) throws E {
throw (E) ex;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -59,6 +59,8 @@ final class Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext {
@Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = NewEmptyArrayFieldValueTransformer.class) Target_com_oracle_truffle_nfi_backend_libffi_LibFFIType[] arrayTypeMap;
@Alias @RecomputeFieldValue(kind = Kind.Reset) Target_com_oracle_truffle_nfi_backend_libffi_LibFFIType cachedEnvType;

@Alias Target_com_oracle_truffle_nfi_backend_libffi_LibFFILanguage language;

@Alias
native long getNativeEnv();

Expand Down Expand Up @@ -105,6 +107,20 @@ private static void disposeNativeContext(long context) {
UnmanagedMemory.free(ctx);
}

@Substitute
private static long initializeNativeEnvV2(long context, @SuppressWarnings("unused") Target_com_oracle_truffle_nfi_backend_spi_NFIState state) {
/*
* No need to store the state, on SVM thread-local lookups are reasonably fast from the
* native side.
*/
return initializeNativeEnv(context);
}

@Substitute
private static void disposeNativeEnvV2(long env) {
UnmanagedMemory.free(WordFactory.pointer(env));
}

@Substitute
private static long initializeNativeEnv(long context) {
NativeTruffleContext ctx = WordFactory.pointer(context);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -24,9 +24,12 @@
*/
package com.oracle.svm.truffle.nfi;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.TargetClass;

@TargetClass(className = "com.oracle.truffle.nfi.backend.libffi.LibFFILanguage", onlyWith = TruffleNFIFeature.IsEnabled.class)
final class Target_com_oracle_truffle_nfi_backend_libffi_LibFFILanguage {

@Alias
protected native Target_com_oracle_truffle_nfi_backend_spi_NFIState getNFIState();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.truffle.nfi;

import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;

@TargetClass(className = "com.oracle.truffle.nfi.backend.libffi.NativeLibVersion", onlyWith = TruffleNFIFeature.IsEnabled.class)
final class Target_com_oracle_truffle_nfi_backend_libffi_NativeLibVersion {

@Substitute
private static int get() {
return 2;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.truffle.nfi;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.TargetClass;

@TargetClass(className = "com.oracle.truffle.nfi.backend.spi.NFIState", onlyWith = TruffleNFIFeature.IsEnabled.class)
final class Target_com_oracle_truffle_nfi_backend_spi_NFIState {

@Alias boolean hasPendingException;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates.
* Copyright (c) 2017, 2024, Oracle and/or its affiliates.
*
* All rights reserved.
*
Expand Down Expand Up @@ -142,12 +142,20 @@ private static final class SignatureSourceCache {
private final EconomicMap<String, WellKnownFunction> wellKnown;
private int nextIndex;

private final String backend;

SignatureSourceCache() {
this(null);
}

SignatureSourceCache(String backend) {
sigCache = new WeakHashMap<>();
sigCacheSkipStackArg = new WeakHashMap<>();

wellKnown = EconomicMap.create();
nextIndex = 0;

this.backend = backend;
}

Source getSignatureSource(FunctionType type) throws UnsupportedNativeTypeException {
Expand All @@ -158,11 +166,14 @@ Source getSignatureSourceSkipStackArg(FunctionType type) throws UnsupportedNativ
return getSignatureSource(type, sigCacheSkipStackArg, LLVMCallNode.USER_ARGUMENT_OFFSET);
}

private static Source getSignatureSource(FunctionType type, WeakHashMap<FunctionType, Source> map, int skipArgs) throws UnsupportedNativeTypeException {
private Source getSignatureSource(FunctionType type, WeakHashMap<FunctionType, Source> map, int skipArgs) throws UnsupportedNativeTypeException {
synchronized (map) {
Source ret = map.get(type);
if (ret == null) {
String sig = getNativeSignature(type, skipArgs);
if (backend != null) {
sig = "with " + backend + " " + sig;
}
ret = Source.newBuilder("nfi", sig, SIGNATURE_SOURCE_NAME).build();
map.put(type, ret);
}
Expand All @@ -185,10 +196,11 @@ public static final class Factory implements ContextExtension.Factory<NativeCont

// share the SignatureSourceCache between contexts
private final SignatureSourceCache signatureSourceCache = new SignatureSourceCache();
private final EconomicMap<String, SignatureSourceCache> altBackendSignatureSourceCache = EconomicMap.create();

@Override
public NativeContextExtension create(Env env) {
return new NFIContextExtension(env, signatureSourceCache);
return new NFIContextExtension(env, signatureSourceCache, altBackendSignatureSourceCache);
}
}

Expand All @@ -201,15 +213,17 @@ public NativeContextExtension create(Env env) {
private final Env env;

private final SignatureSourceCache signatureSourceCache;
private final EconomicMap<String, SignatureSourceCache> altBackendSignatureSourceCache;
private final EconomicMap<Source, Object> signatureCache = EconomicMap.create(Equivalence.IDENTITY);

// This is an array instead of an ArrayList because it's accessed from the fast-path.
private WellKnownNativeFunctionAndSignature[] wellKnownFunctionCache;

private NFIContextExtension(Env env, SignatureSourceCache signatureSourceCache) {
private NFIContextExtension(Env env, SignatureSourceCache signatureSourceCache, EconomicMap<String, SignatureSourceCache> altBackendSignatureSourceCache) {
assert env.getOptions().get(SulongNativeOption.ENABLE_NFI);
this.env = env;
this.signatureSourceCache = signatureSourceCache;
this.altBackendSignatureSourceCache = altBackendSignatureSourceCache;
this.wellKnownFunctionCache = new WellKnownNativeFunctionAndSignature[WELL_KNOWN_CACHE_INITIAL_SIZE];
}

Expand Down Expand Up @@ -298,8 +312,21 @@ Object doCreateClosure(
}
}

private SignatureSourceCache getSignatureSourceCache(String backend) {
if (backend == null) {
return signatureSourceCache;
} else {
synchronized (this) {
if (!altBackendSignatureSourceCache.containsKey(backend)) {
altBackendSignatureSourceCache.put(backend, new SignatureSourceCache(backend));
}
}
return altBackendSignatureSourceCache.get(backend);
}
}

@Override
public CallTarget createNativeWrapperFactory(LLVMFunctionCode code) {
public CallTarget createNativeWrapperFactory(LLVMFunctionCode code, String backend) {
CompilerAsserts.neverPartOfCompilation();
/*
* We create a CallTarget here instead of directly the native closure so the NFI has a place
Expand All @@ -310,7 +337,7 @@ public CallTarget createNativeWrapperFactory(LLVMFunctionCode code) {
* objects.
*/
try {
Source signatureSource = signatureSourceCache.getSignatureSource(code.getLLVMFunction().getType());
Source signatureSource = getSignatureSourceCache(backend).getSignatureSource(code.getLLVMFunction().getType());
return CreateClosureNodeGen.create(LLVMLanguage.get(null), signatureSource, new LLVMNativeWrapper(code)).getCallTarget();
} catch (UnsupportedNativeTypeException ex) {
// ignore, fall back to tagged id
Expand Down Expand Up @@ -629,6 +656,15 @@ public Object bindSignature(long fnPtr, Source signatureSource) {
return SignatureLibrary.getUncached().bind(signature, LLVMNativePointer.create(fnPtr));
}

@Override
public String getNativeSignature(FunctionType type) {
try {
return getNativeSignature(type, 0);
} catch (UnsupportedNativeTypeException e) {
return null;
}
}

private static String getNativeSignature(FunctionType type, int skipArguments) throws UnsupportedNativeTypeException {
CompilerAsserts.neverPartOfCompilation();
String nativeRet = getNativeType(type.getReturnType());
Expand Down

0 comments on commit e3d8479

Please sign in to comment.