Skip to content

Commit 5493156

Browse files
committed
Clean up native function creation infrastructure
1 parent 0a1d283 commit 5493156

File tree

7 files changed

+95
-500
lines changed

7 files changed

+95
-500
lines changed

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi9BuiltinNode;
5757
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
5858
import com.oracle.graal.python.builtins.objects.PNone;
59-
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.CreateFunctionNode;
59+
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes;
6060
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
6161
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
6262
import com.oracle.graal.python.nodes.HiddenAttr;
@@ -83,19 +83,18 @@ public final class PythonCextMethodBuiltins {
8383
@GenerateCached(false)
8484
abstract static class CFunctionNewExMethodNode extends Node {
8585

86-
abstract Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, Object flags, int wrapper, Object self, Object module, Object cls, Object doc);
86+
abstract Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object self, Object module, Object cls, Object doc);
8787

88-
final Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, Object flags, int wrapper, Object self, Object module, Object doc) {
88+
final Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object self, Object module, Object doc) {
8989
return execute(inliningTarget, methodDefPtr, name, methObj, flags, wrapper, self, module, PNone.NO_VALUE, doc);
9090
}
9191

9292
@Specialization
93-
static Object doNativeCallable(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, Object flags, int wrapper, Object self, Object module, Object cls, Object doc,
93+
static Object doNativeCallable(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object self, Object module, Object cls, Object doc,
9494
@Bind PythonLanguage language,
95-
@Cached CreateFunctionNode createFunctionNode,
9695
@Cached HiddenAttr.WriteNode writeHiddenAttrNode,
9796
@Cached(inline = false) WriteAttributeToPythonObjectNode writeAttrNode) {
98-
Object f = createFunctionNode.execute(inliningTarget, name, methObj, wrapper, PNone.NO_VALUE, flags);
97+
Object f = ExternalFunctionNodes.PExternalFunctionWrapper.createWrapperFunction(name, methObj, PNone.NO_VALUE, flags, wrapper, language);
9998
assert f instanceof PBuiltinFunction;
10099
PBuiltinFunction func = (PBuiltinFunction) f;
101100
writeHiddenAttrNode.execute(inliningTarget, func, METHOD_DEF_PTR, methodDefPtr);

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext;
7373
import com.oracle.graal.python.builtins.objects.cext.capi.CApiMemberAccessNodes.ReadMemberNode;
7474
import com.oracle.graal.python.builtins.objects.cext.capi.CApiMemberAccessNodes.WriteMemberNode;
75-
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.CreateFunctionNode;
7675
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes;
7776
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.GetterRoot;
7877
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper;
@@ -262,9 +261,8 @@ abstract static class NewClassMethodNode extends Node {
262261
static Object classOrStatic(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object type, Object doc,
263262
@Bind PythonLanguage language,
264263
@Exclusive @Cached HiddenAttr.WriteNode writeHiddenAttrNode,
265-
@Cached(inline = false) WriteAttributeToPythonObjectNode writeAttrNode,
266-
@Exclusive @Cached CreateFunctionNode createFunctionNode) {
267-
PythonAbstractObject func = createFunctionNode.execute(inliningTarget, name, methObj, wrapper, type, flags);
264+
@Cached(inline = false) WriteAttributeToPythonObjectNode writeAttrNode) {
265+
PythonAbstractObject func = PExternalFunctionWrapper.createWrapperFunction(name, methObj, type, flags, wrapper, language);
268266
writeHiddenAttrNode.execute(inliningTarget, func, METHOD_DEF_PTR, methodDefPtr);
269267
PythonObject function;
270268
if ((flags & METH_CLASS) != 0) {
@@ -279,10 +277,10 @@ static Object classOrStatic(Node inliningTarget, Object methodDefPtr, TruffleStr
279277

280278
@Specialization(guards = "!isClassOrStaticMethod(flags)")
281279
static Object doNativeCallable(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object type, Object doc,
280+
@Bind PythonLanguage language,
282281
@Cached PyObjectSetAttrNode setattr,
283-
@Exclusive @Cached HiddenAttr.WriteNode writeNode,
284-
@Exclusive @Cached CreateFunctionNode createFunctionNode) {
285-
PythonAbstractObject func = createFunctionNode.execute(inliningTarget, name, methObj, wrapper, type, flags);
282+
@Exclusive @Cached HiddenAttr.WriteNode writeNode) {
283+
PythonAbstractObject func = PExternalFunctionWrapper.createWrapperFunction(name, methObj, type, flags, wrapper, language);
286284
setattr.execute(inliningTarget, func, T___NAME__, name);
287285
setattr.execute(inliningTarget, func, T___DOC__, doc);
288286
writeNode.execute(inliningTarget, func, METHOD_DEF_PTR, methodDefPtr);

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

Lines changed: 2 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@
7373
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
7474
import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached;
7575
import static com.oracle.truffle.api.CompilerDirectives.shouldNotReachHere;
76-
import static com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate;
7776

7877
import java.util.regex.Matcher;
7978
import java.util.regex.Pattern;
@@ -91,7 +90,6 @@
9190
import com.oracle.graal.python.builtins.objects.cext.PythonNativeVoidPtr;
9291
import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext.ModuleSpec;
9392
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory.AsCharPointerNodeGen;
94-
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory.CreateFunctionNodeGen;
9593
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory.FromCharPointerNodeGen;
9694
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory.PyErrFetchNodeGen;
9795
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory.PyErrOccurredNodeGen;
@@ -101,7 +99,6 @@
10199
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.DefaultCheckFunctionResultNode;
102100
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.ExternalFunctionInvokeNode;
103101
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper;
104-
import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.TpSlotWrapper;
105102
import com.oracle.graal.python.builtins.objects.cext.capi.PythonNativeWrapper.PythonAbstractObjectNativeWrapper;
106103
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions;
107104
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.HandlePointerConverter;
@@ -151,9 +148,6 @@
151148
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetMroStorageNode;
152149
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetTypeFlagsNode;
153150
import com.oracle.graal.python.builtins.objects.type.TypeNodes.ProfileClassNode;
154-
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotBuiltin;
155-
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotNative;
156-
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotPython;
157151
import com.oracle.graal.python.lib.PyFloatAsDoubleNode;
158152
import com.oracle.graal.python.lib.PyNumberAsSizeNode;
159153
import com.oracle.graal.python.lib.PyObjectLookupAttr;
@@ -195,7 +189,6 @@
195189
import com.oracle.truffle.api.CompilerDirectives;
196190
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
197191
import com.oracle.truffle.api.RootCallTarget;
198-
import com.oracle.truffle.api.TruffleLogger;
199192
import com.oracle.truffle.api.dsl.Bind;
200193
import com.oracle.truffle.api.dsl.Cached;
201194
import com.oracle.truffle.api.dsl.Cached.Exclusive;
@@ -888,7 +881,7 @@ public static PCallCapiFunction getUncached() {
888881
* <p>
889882
* This method basically implements the native member inheritance that is done by
890883
* {@code inherit_special} or other code in {@code PyType_Ready}. In addition, we do a special
891-
* case for special slots assignment that happens within {@Code type_new_alloc} for heap types.
884+
* case for special slots assignment that happens within {@code type_new_alloc} for heap types.
892885
* </p>
893886
* <p>
894887
* Since it may be that a managed types needs to emulate such members but there is no
@@ -1974,7 +1967,7 @@ static PBuiltinFunction doIt(Node inliningTarget, Object methodDef, int element,
19741967
// CPy-style methods
19751968
// TODO(fa) support static and class methods
19761969
PExternalFunctionWrapper sig = PExternalFunctionWrapper.fromMethodFlags(flags);
1977-
RootCallTarget callTarget = PExternalFunctionWrapper.getOrCreateCallTarget(sig, PythonLanguage.get(inliningTarget), methodName, true, CExtContext.isMethStatic(flags));
1970+
RootCallTarget callTarget = PExternalFunctionWrapper.getOrCreateCallTarget(sig, PythonLanguage.get(inliningTarget), methodName, CExtContext.isMethStatic(flags));
19781971
mlMethObj = ensureCallableNode.execute(inliningTarget, mlMethObj, sig);
19791972
PKeyword[] kwDefaults = ExternalFunctionNodes.createKwDefaults(mlMethObj);
19801973
PBuiltinFunction function = PFactory.createBuiltinFunction(language, methodName, null, PythonUtils.EMPTY_OBJECT_ARRAY, kwDefaults, flags, callTarget);
@@ -2055,165 +2048,6 @@ static void doOther(Object object) {
20552048
}
20562049
}
20572050

2058-
@GenerateUncached
2059-
@GenerateInline
2060-
@GenerateCached(false)
2061-
@ImportStatic({CApiGuards.class, PGuards.class})
2062-
public abstract static class CreateFunctionNode extends Node {
2063-
2064-
private static final TruffleLogger LOGGER = CApiContext.getLogger(CreateFunctionNode.class);
2065-
2066-
public static PythonObject executeUncached(TruffleString name, Object callable, int wrapper, Object type, Object flags) {
2067-
return CreateFunctionNodeGen.getUncached().execute(null, name, callable, wrapper, type, flags);
2068-
}
2069-
2070-
public abstract PythonObject execute(Node inliningTarget, TruffleString name, Object callable, int wrapper, Object type, Object flags);
2071-
2072-
/*
2073-
* Note: this is called from PyTruffleType_AddSlot, which is similar to CPython's
2074-
* add_operators: it creates corresponding Python magic methods from slots, but only from
2075-
* slots declared on given native type and not from inherited slots. So we should not see
2076-
* here pointers to native wrappers of managed slots. However, one could: 1) initialize a
2077-
* type multiple times, in which case we'd see here inherited slots, or 2) "steal" a slot
2078-
* from some existing type. This is why we resolve native closures and handle delegates of
2079-
* type TpSlotBuiltin/Managed in the managed case.
2080-
*/
2081-
2082-
@Specialization(guards = "!isNoValue(type)")
2083-
@TruffleBoundary
2084-
static PythonObject doPythonCallable(TruffleString name, PythonNativeWrapper callable, int signature, Object type, int flags) {
2085-
Object managedCallable = callable.getDelegate();
2086-
PythonContext context = PythonContext.get(null);
2087-
PythonLanguage language = context.getLanguage();
2088-
boolean doArgAndResultConversion = false;
2089-
if (managedCallable instanceof TpSlotBuiltin<?> builtinSlot) {
2090-
var builtin = builtinSlot.createBuiltin(context, type, name, PExternalFunctionWrapper.fromValue(signature));
2091-
if (builtin != null) {
2092-
return builtin;
2093-
}
2094-
assert callable instanceof TpSlotWrapper;
2095-
managedCallable = callable;
2096-
doArgAndResultConversion = true;
2097-
} else if (managedCallable instanceof TpSlotPython pythonSlot) {
2098-
// Someone has "stolen" existing python slot and stashed it into its slot field
2099-
// See TpSlots#fromNative where we need to solve the same issue
2100-
assert callable instanceof TpSlotWrapper;
2101-
TpSlotPython newPythonSlot = pythonSlot.forNewType(type);
2102-
if (newPythonSlot != pythonSlot) {
2103-
managedCallable = ((TpSlotWrapper) callable).cloneWith(newPythonSlot);
2104-
} else {
2105-
managedCallable = callable;
2106-
}
2107-
doArgAndResultConversion = true;
2108-
}
2109-
PythonObject function = PExternalFunctionWrapper.createWrapperFunction(name, managedCallable, type, flags, signature, language, doArgAndResultConversion);
2110-
return function != null ? function : castToPythonObject(managedCallable);
2111-
}
2112-
2113-
@Specialization
2114-
@TruffleBoundary
2115-
static PythonObject doPyCFunctionWrapper(TruffleString name, PyCFunctionWrapper wrapper, int signature, Object type, int flags) {
2116-
Object delegate = wrapper.getDelegate();
2117-
assert !(delegate instanceof PythonAbstractObject);
2118-
PythonContext context = PythonContext.get(null);
2119-
PythonLanguage language = context.getLanguage();
2120-
return PExternalFunctionWrapper.createWrapperFunction(name, delegate, type, flags, signature, language, false);
2121-
}
2122-
2123-
@Specialization(guards = {"!isNativeWrapper(callable)"})
2124-
@TruffleBoundary
2125-
static PythonObject doNativeCallableWithWrapper(TruffleString name, Object callable, int signature, Object type, int flags,
2126-
@CachedLibrary(limit = "3") InteropLibrary lib) {
2127-
PythonContext context = PythonContext.get(null);
2128-
Object resolvedCallable = resolveClosurePointer(context, callable, lib);
2129-
assert !(resolvedCallable instanceof TpSlotNative);
2130-
if (resolvedCallable instanceof TpSlotBuiltin<?> builtinSlot) {
2131-
// CPython also creates a new wrapper descriptor even for slots that already
2132-
// have some wrapper descriptor. We can use the slot itself to create the right
2133-
// descriptor avoiding the delegation
2134-
var builtin = builtinSlot.createBuiltin(context, type, name, PExternalFunctionWrapper.fromValue(signature));
2135-
if (builtin != null) {
2136-
return builtin;
2137-
}
2138-
// Otherwise fallback to wrapping the callable as if it was just opaque native call
2139-
resolvedCallable = null;
2140-
} else if (resolvedCallable instanceof TpSlotPython pythonSlot) {
2141-
// Someone has "stolen" existing python slot and stashed it into its slot field
2142-
// We will delegate to the native closure to be as compatible with whatever
2143-
// native call trickery the user intends to do
2144-
// Note: we do not have a simple way to write back the new slot if it changed,
2145-
// so TpSlots#fromNative will do this again and will write back the new slot to the
2146-
// PyTypeObject slot field
2147-
TpSlotPython newSlot = pythonSlot.forNewType(type);
2148-
try {
2149-
Object wrapper = context.getCApiContext().getClosureExecutable(lib.asPointer(callable));
2150-
if (wrapper instanceof TpSlotWrapper slotWrapper) {
2151-
TpSlotWrapper newWrapper = newSlot != pythonSlot ? slotWrapper.cloneWith(newSlot) : slotWrapper;
2152-
newWrapper.toNative(SignatureLibrary.getUncached());
2153-
callable = context.getCApiContext().getClosureForExecutable(newWrapper);
2154-
}
2155-
resolvedCallable = null;
2156-
} catch (UnsupportedMessageException ignore) {
2157-
// resolveClosurePointer gave non-null result, it must be a pointer
2158-
throw CompilerDirectives.shouldNotReachHere();
2159-
}
2160-
}
2161-
boolean doArgAndResultConversion;
2162-
if (resolvedCallable != null) {
2163-
doArgAndResultConversion = false;
2164-
} else {
2165-
doArgAndResultConversion = true;
2166-
resolvedCallable = callable;
2167-
}
2168-
PythonLanguage language = context.getLanguage();
2169-
PythonObject function = PExternalFunctionWrapper.createWrapperFunction(name, resolvedCallable, type, flags, signature, language, doArgAndResultConversion);
2170-
return function != null ? function : castToPythonObject(resolvedCallable);
2171-
}
2172-
2173-
private static PythonObject castToPythonObject(Object callable) {
2174-
if (callable instanceof PythonObject pythonObject) {
2175-
return pythonObject;
2176-
}
2177-
transferToInterpreterAndInvalidate();
2178-
throw shouldNotReachHere("Unexpected class of callable: " + callable.getClass());
2179-
}
2180-
2181-
/**
2182-
* If possible resolves the pointer to a {@link PBuiltinFunction} (creating a fresh builtin
2183-
* from builtin slots).
2184-
*/
2185-
@TruffleBoundary
2186-
public static Object resolveClosurePointerToBuiltinFun(PythonContext context, Object callable, InteropLibrary lib,
2187-
Object type, TruffleString name, PExternalFunctionWrapper signature) {
2188-
Object delegate = resolveClosurePointer(context, callable, lib);
2189-
if (delegate instanceof TpSlotBuiltin<?> builtinSlot) {
2190-
return builtinSlot.createBuiltin(context, type, name, signature);
2191-
}
2192-
return delegate;
2193-
}
2194-
2195-
/**
2196-
* Returns either {@link PBuiltinFunction} or {@link TpSlotBuiltin}.
2197-
*/
2198-
@TruffleBoundary
2199-
public static Object resolveClosurePointer(PythonContext context, Object callable, InteropLibrary lib) {
2200-
if (lib.isPointer(callable)) {
2201-
long pointer;
2202-
try {
2203-
pointer = lib.asPointer(callable);
2204-
} catch (UnsupportedMessageException e) {
2205-
throw shouldNotReachHere(e);
2206-
}
2207-
Object delegate = context.getCApiContext().getClosureDelegate(pointer);
2208-
if (delegate != null) {
2209-
LOGGER.fine(() -> PythonUtils.formatJString("resolved closure pointer %d 0x%x to %s", pointer, pointer, delegate));
2210-
return delegate;
2211-
}
2212-
}
2213-
return null;
2214-
}
2215-
}
2216-
22172051
/**
22182052
* Similar to CPython's macro {@code Py_VISIT}, this node will call the provided visit function
22192053
* on the item if that item is a native object. This is because we assume that the traverse and

0 commit comments

Comments
 (0)