Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-52189] Properly propagate NFI exceptions between backends. #8770

Merged
merged 13 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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