Skip to content

Commit 01079ea

Browse files
committed
Move NativeCExtSymbol.ensureExecutable to CExtContext; add logging and inline doc
1 parent f997c9f commit 01079ea

File tree

8 files changed

+70
-56
lines changed

8 files changed

+70
-56
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
import com.oracle.graal.python.builtins.objects.cext.common.CArrayWrappers.CArrayWrapper;
8181
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
8282
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext.Store;
83-
import com.oracle.graal.python.builtins.objects.cext.common.NativeCExtSymbol;
8483
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
8584
import com.oracle.graal.python.builtins.objects.dict.PDict;
8685
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
@@ -354,15 +353,15 @@ static GetSetDescriptor createGetSet(Node inliningTarget, TruffleString name, Ob
354353
PBuiltinFunction get = null;
355354
if (!interopLibrary.isNull(getter)) {
356355
RootCallTarget getterCT = getterCallTarget(name, PythonLanguage.get(inliningTarget));
357-
getter = NativeCExtSymbol.ensureExecutable(getter, PExternalFunctionWrapper.GETTER);
356+
getter = CExtContext.ensureExecutable(getter, PExternalFunctionWrapper.GETTER);
358357
get = factory.createBuiltinFunction(name, cls, EMPTY_OBJECT_ARRAY, ExternalFunctionNodes.createKwDefaults(getter, closure), 0, getterCT);
359358
}
360359

361360
PBuiltinFunction set = null;
362361
boolean hasSetter = !interopLibrary.isNull(setter);
363362
if (hasSetter) {
364363
RootCallTarget setterCT = setterCallTarget(name, PythonLanguage.get(inliningTarget));
365-
setter = NativeCExtSymbol.ensureExecutable(setter, PExternalFunctionWrapper.SETTER);
364+
setter = CExtContext.ensureExecutable(setter, PExternalFunctionWrapper.SETTER);
366365
set = factory.createBuiltinFunction(name, cls, EMPTY_OBJECT_ARRAY, ExternalFunctionNodes.createKwDefaults(setter, closure), 0, setterCT);
367366
}
368367

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@
104104
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
105105
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext.ModuleSpec;
106106
import com.oracle.graal.python.builtins.objects.cext.common.GetNextVaArgNode;
107-
import com.oracle.graal.python.builtins.objects.cext.common.NativeCExtSymbol;
108107
import com.oracle.graal.python.builtins.objects.cext.structs.CFields;
109108
import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess;
110109
import com.oracle.graal.python.builtins.objects.cext.structs.CStructs;
@@ -1851,7 +1850,7 @@ static PBuiltinFunction doIt(Object methodDef, int element,
18511850
// TODO(fa) support static and class methods
18521851
PExternalFunctionWrapper sig = PExternalFunctionWrapper.fromMethodFlags(flags);
18531852
RootCallTarget callTarget = PExternalFunctionWrapper.getOrCreateCallTarget(sig, PythonLanguage.get(factory), methodName, true, CExtContext.isMethStatic(flags));
1854-
mlMethObj = NativeCExtSymbol.ensureExecutable(mlMethObj, sig);
1853+
mlMethObj = CExtContext.ensureExecutable(mlMethObj, sig);
18551854
PKeyword[] kwDefaults = ExternalFunctionNodes.createKwDefaults(mlMethObj);
18561855
PBuiltinFunction function = factory.createBuiltinFunction(methodName, null, PythonUtils.EMPTY_OBJECT_ARRAY, kwDefaults, flags, callTarget);
18571856

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ public static PBuiltinFunction createWrapperFunction(TruffleString name, Object
686686
}
687687

688688
// ensure that 'callable' is executable via InteropLibrary
689-
Object boundCallable = NativeCExtSymbol.ensureExecutable(callable, sig);
689+
Object boundCallable = CExtContext.ensureExecutable(callable, sig);
690690
kwDefaults = ExternalFunctionNodes.createKwDefaults(boundCallable);
691691
}
692692

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/common/CExtCommonNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ protected static Object importCAPISymbolUncached(Node location, CExtContext nati
196196
String name = symbol.getName();
197197
try {
198198
Object nativeSymbol = InteropLibrary.getUncached().readMember(llvmLibrary, name);
199-
nativeSymbol = NativeCExtSymbol.ensureExecutable(nativeSymbol, symbol);
199+
nativeSymbol = CExtContext.ensureExecutable(nativeSymbol, symbol);
200200
dynamicObjectLib.put(symbolCache, symbol, nativeSymbol);
201201
return nativeSymbol;
202202
} catch (UnknownIdentifierException e) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/common/CExtContext.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
import com.oracle.truffle.api.source.Source;
9595
import com.oracle.truffle.api.strings.TruffleString;
9696
import com.oracle.truffle.api.strings.TruffleString.CodeRange;
97+
import com.oracle.truffle.nfi.api.SignatureLibrary;
9798

9899
public abstract class CExtContext {
99100

@@ -411,4 +412,60 @@ public static PException wrapJavaException(Throwable e, Node raisingNode) {
411412
PythonUtils.EMPTY_OBJECT_ARRAY);
412413
return ExceptionUtils.wrapJavaException(e, raisingNode, excObject);
413414
}
415+
416+
/**
417+
* Ensures that the given {@code callable} is an executable interop value.
418+
*
419+
* <p>
420+
* <b>NOTE:</b> This method will fail if {@link PythonContext#isNativeAccessAllowed() native
421+
* access} is not allowed and if {@code callable} is yet not
422+
* {@link InteropLibrary#isExecutable(Object) executable}.
423+
* </p>
424+
* <p>
425+
* If the {@code callable} is not {@link InteropLibrary#isExecutable(Object) executable}, the
426+
* provided {@link NativeCExtSymbol signature} will be used to bind the object an executable
427+
* {@code NFI} pointer.
428+
* </p>
429+
*
430+
* @param callable The callable to ensure that it is executable (
431+
* @param sig The signature to bind to if the object is not executable.
432+
* @return An interop object that is {@link InteropLibrary#isExecutable(Object) executable}.
433+
*/
434+
@TruffleBoundary
435+
public static Object ensureExecutable(final Object callable, NativeCExtSymbol sig) {
436+
InteropLibrary lib = InteropLibrary.getUncached(callable);
437+
if (!lib.isExecutable(callable)) {
438+
PythonContext pythonContext = PythonContext.get(null);
439+
if (!pythonContext.isNativeAccessAllowed()) {
440+
getLogger().severe(String.format("Attempting to bind %s to an NFI signature but native access is not allowed", callable));
441+
}
442+
Env env = pythonContext.getEnv();
443+
444+
boolean panama = PythonOptions.UsePanama.getValue(env.getOptions());
445+
446+
assert sig.getSignature() != null && !sig.getSignature().isEmpty();
447+
Object nfiSignature = env.parseInternal(Source.newBuilder("nfi", (panama ? "with panama " : "") + sig.getSignature(), sig.getName()).build()).call();
448+
449+
/*
450+
* Since we mix native and LLVM execution, it happens that 'callable' is an LLVM pointer
451+
* (that is still not executable). To avoid unnecessary indirections, we test
452+
* 'isPointer(callable)' and if so, we retrieve the bare long value using
453+
* 'asPointer(callable)' and wrap it in our own NativePointer.
454+
*/
455+
Object funPtr;
456+
if (lib.isPointer(callable)) {
457+
try {
458+
funPtr = new NativePointer(lib.asPointer(callable));
459+
} catch (UnsupportedMessageException e) {
460+
throw CompilerDirectives.shouldNotReachHere(e);
461+
}
462+
} else {
463+
funPtr = callable;
464+
}
465+
getLogger().finer(() -> String.format("Binding %s (signature: %s) to NFI signature %s", callable, sig.getName(), sig.getSignature()));
466+
return SignatureLibrary.getUncached().bind(nfiSignature, funPtr);
467+
}
468+
// nothing to do
469+
return callable;
470+
}
414471
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,16 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.cext.common;
4242

43-
import com.oracle.graal.python.runtime.PythonContext;
44-
import com.oracle.graal.python.runtime.PythonOptions;
45-
import com.oracle.truffle.api.CompilerDirectives;
46-
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
47-
import com.oracle.truffle.api.TruffleLanguage.Env;
48-
import com.oracle.truffle.api.interop.InteropLibrary;
49-
import com.oracle.truffle.api.interop.UnsupportedMessageException;
50-
import com.oracle.truffle.api.source.Source;
5143
import com.oracle.truffle.api.strings.TruffleString;
52-
import com.oracle.truffle.nfi.api.SignatureLibrary;
5344

5445
public interface NativeCExtSymbol {
5546
String getName();
@@ -60,36 +51,4 @@ public interface NativeCExtSymbol {
6051
* Returns the NFI signature.
6152
*/
6253
String getSignature();
63-
64-
@TruffleBoundary
65-
public static Object ensureExecutable(Object callable, NativeCExtSymbol sig) {
66-
InteropLibrary lib = InteropLibrary.getUncached();
67-
if (!lib.isExecutable(callable)) {
68-
Env env = PythonContext.get(null).getEnv();
69-
boolean panama = PythonOptions.UsePanama.getValue(env.getOptions());
70-
71-
assert sig.getSignature() != null && !sig.getSignature().isEmpty();
72-
Object nfiSignature = env.parseInternal(Source.newBuilder("nfi", (panama ? "with panama " : "") + sig.getSignature(), sig.getName()).build()).call();
73-
74-
/*
75-
* Since we mix native and LLVM execution, it happens that 'callable' is an LLVM pointer
76-
* (that is still not executable). To avoid unnecessary indirections, we test
77-
* 'isPointer(callable)' and if so, we retrieve the bare long value using
78-
* 'asPointer(callable)' and wrap it in our own NativePointer.
79-
*/
80-
Object funPtr;
81-
if (lib.isPointer(callable)) {
82-
try {
83-
funPtr = new NativePointer(lib.asPointer(callable));
84-
} catch (UnsupportedMessageException e) {
85-
throw CompilerDirectives.shouldNotReachHere(e);
86-
}
87-
} else {
88-
funPtr = callable;
89-
}
90-
return SignatureLibrary.getUncached().bind(nfiSignature, funPtr);
91-
}
92-
// nothing to do
93-
return callable;
94-
}
9554
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyNodes.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@
7272
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper;
7373
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.AsNativePrimitiveNode;
7474
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.ConvertPIntToPrimitiveNode;
75+
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
7576
import com.oracle.graal.python.builtins.objects.cext.common.CExtToJavaNode;
7677
import com.oracle.graal.python.builtins.objects.cext.common.CExtToNativeNode;
77-
import com.oracle.graal.python.builtins.objects.cext.common.NativeCExtSymbol;
7878
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyCAccess.ReadGenericNode;
7979
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyCAccess.ReadHPyNode;
8080
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyContext.LLVMType;
@@ -766,14 +766,14 @@ static GetSetDescriptor doGeneric(GraalHPyContext context, Object owner, Object
766766
PythonLanguage lang = PythonLanguage.get(raiseNode);
767767
PBuiltinFunction getterObject = null;
768768
if (!isNullNode.execute(context, getterFunPtr)) {
769-
Object getterFunInteropPtr = NativeCExtSymbol.ensureExecutable(context.nativeToInteropPointer(getterFunPtr), PExternalFunctionWrapper.GETTER);
769+
Object getterFunInteropPtr = CExtContext.ensureExecutable(context.nativeToInteropPointer(getterFunPtr), PExternalFunctionWrapper.GETTER);
770770
getterObject = HPyLegacyGetSetDescriptorGetterRoot.createLegacyFunction(context, lang, owner, getSetDescrName, getterFunInteropPtr, closurePtr);
771771
}
772772

773773
PBuiltinFunction setterObject = null;
774774
boolean hasSetter = !isNullNode.execute(context, setterFunPtr);
775775
if (hasSetter) {
776-
Object setterFunInteropPtr = NativeCExtSymbol.ensureExecutable(context.nativeToInteropPointer(setterFunPtr), PExternalFunctionWrapper.SETTER);
776+
Object setterFunInteropPtr = CExtContext.ensureExecutable(context.nativeToInteropPointer(setterFunPtr), PExternalFunctionWrapper.SETTER);
777777
setterObject = HPyLegacyGetSetDescriptorSetterRoot.createLegacyFunction(context, lang, owner, getSetDescrName, setterFunInteropPtr, closurePtr);
778778
}
779779

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/HPyExternalFunctionNodes.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -59,7 +59,7 @@
5959
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes;
6060
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.CheckFunctionResultNode;
6161
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.GetIndexNode;
62-
import com.oracle.graal.python.builtins.objects.cext.common.NativeCExtSymbol;
62+
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
6363
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyDef.HPyFuncSignature;
6464
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyDef.HPySlotWrapper;
6565
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodes.HPyCloseAndGetHandleNode;
@@ -1412,7 +1412,7 @@ public static PBuiltinFunction createLegacyFunction(GraalHPyContext context, Pyt
14121412
if (rootCallTarget == null) {
14131413
throw CompilerDirectives.shouldNotReachHere("Calling non-native get descriptor functions is not support in HPy");
14141414
}
1415-
target = NativeCExtSymbol.ensureExecutable(target, PExternalFunctionWrapper.GETTER);
1415+
target = CExtContext.ensureExecutable(target, PExternalFunctionWrapper.GETTER);
14161416
return factory.createBuiltinFunction(propertyName, owner, PythonUtils.EMPTY_OBJECT_ARRAY, ExternalFunctionNodes.createKwDefaults(target, closure), 0, rootCallTarget);
14171417
}
14181418
}
@@ -1497,7 +1497,7 @@ public static PBuiltinFunction createLegacyFunction(GraalHPyContext context, Pyt
14971497
if (rootCallTarget == null) {
14981498
throw CompilerDirectives.shouldNotReachHere("Calling non-native get descriptor functions is not support in HPy");
14991499
}
1500-
target = NativeCExtSymbol.ensureExecutable(target, PExternalFunctionWrapper.SETTER);
1500+
target = CExtContext.ensureExecutable(target, PExternalFunctionWrapper.SETTER);
15011501
return factory.createBuiltinFunction(propertyName, owner, PythonUtils.EMPTY_OBJECT_ARRAY, ExternalFunctionNodes.createKwDefaults(target, closure), 0, rootCallTarget);
15021502
}
15031503
}

0 commit comments

Comments
 (0)