diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/Parser.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/Parser.java index 54341b395d..d7c0846fd0 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/Parser.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/Parser.java @@ -23967,7 +23967,7 @@ private boolean genLookahead__tmp_328_rule(boolean match) { return (result != null) == match; } - + @Override protected SSTNode runParser(InputType inputType) { SSTNode result = null; diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java index d9a12cbd5f..9146b21882 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -51,7 +51,7 @@ private static String getSuffix(boolean isComplex) { static String getSlotBaseClass(Slot s) { return switch (s.value()) { - case nb_bool -> "TpSlotInquiry.TpSlotInquiryBuiltin"; + case nb_bool -> "TpSlotInquiry.TpSlotInquiryBuiltin" + getSuffix(s.isComplex()); case nb_index, nb_int, nb_float, nb_absolute, nb_positive, nb_negative, nb_invert, tp_iter, tp_str, tp_repr, am_aiter, am_anext, am_await -> "TpSlotUnaryFunc.TpSlotUnaryFuncBuiltin"; @@ -128,10 +128,7 @@ static String getUncachedExecuteSignature(SlotKind s) { } static boolean supportsComplex(SlotKind s) { - return switch (s) { - case nb_bool -> false; - default -> true; - }; + return true; } static boolean supportsSimple(SlotKind s) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java index 1e5e81a8f7..fa83888791 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java @@ -1050,10 +1050,10 @@ public long cacheKeyForBytecode(byte[] code) { .build(); @CompilationFinal private Object cachedTRegexLineBreakRegex; - public Object getCachedTRegexLineBreakRegex(PythonContext context) { + public Object getCachedTRegexLineBreakRegex(Node location, PythonContext context) { if (cachedTRegexLineBreakRegex == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - cachedTRegexLineBreakRegex = context.getEnv().parseInternal(LINEBREAK_REGEX_SOURCE).call(); + cachedTRegexLineBreakRegex = context.getEnv().parseInternal(LINEBREAK_REGEX_SOURCE).call(location); } return cachedTRegexLineBreakRegex; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java index 9dbeec9804..bed6d34c7b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java @@ -1389,11 +1389,11 @@ static PTuple doCreate(long arrowArrayAddr, long arrowSchemaAddr, @Cached PythonCextCapsuleBuiltins.PyCapsuleNewNode pyCapsuleNewNode) { var ctx = getContext(inliningTarget); - long arrayDestructor = ctx.arrowSupport.getArrowArrayDestructor(); + long arrayDestructor = ctx.arrowSupport.getArrowArrayDestructor(inliningTarget); var arrayCapsuleName = new CArrayWrappers.CByteArrayWrapper(ArrowArray.CAPSULE_NAME); PyCapsule arrowArrayCapsule = pyCapsuleNewNode.execute(inliningTarget, arrowArrayAddr, arrayCapsuleName, arrayDestructor); - long schemaDestructor = ctx.arrowSupport.getArrowSchemaDestructor(); + long schemaDestructor = ctx.arrowSupport.getArrowSchemaDestructor(inliningTarget); var schemaCapsuleName = new CArrayWrappers.CByteArrayWrapper(ArrowSchema.CAPSULE_NAME); PyCapsule arrowSchemaCapsule = pyCapsuleNewNode.execute(inliningTarget, arrowSchemaAddr, schemaCapsuleName, schemaDestructor); return PFactory.createTuple(ctx.getLanguage(inliningTarget), new Object[]{arrowSchemaCapsule, arrowArrayCapsule}); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java index 28f1726182..aff1a9f536 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java @@ -68,6 +68,7 @@ import static com.oracle.graal.python.util.PythonUtils.EMPTY_BYTE_ARRAY; import static com.oracle.graal.python.util.PythonUtils.EMPTY_OBJECT_ARRAY; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; +import static com.oracle.graal.python.util.PythonUtils.callCallTarget; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import java.io.IOException; @@ -82,8 +83,8 @@ import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; -import com.oracle.graal.python.builtins.modules.PolyglotModuleBuiltinsClinicProviders.RegisterInteropTypeNodeClinicProviderGen; import com.oracle.graal.python.builtins.modules.PolyglotModuleBuiltinsClinicProviders.EnterForeignCriticalRegionNodeClinicProviderGen; +import com.oracle.graal.python.builtins.modules.PolyglotModuleBuiltinsClinicProviders.RegisterInteropTypeNodeClinicProviderGen; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PythonAbstractObject; import com.oracle.graal.python.builtins.objects.bytes.PBytesLike; @@ -287,7 +288,7 @@ Object eval(Object pathObj, Object stringObj, Object languageObj) { if (mimeType != null) { builder = builder.mimeType(mimeType); } - Object result = env.parsePublic(builder.build()).call(); + Object result = callCallTarget(env.parsePublic(builder.build()), this); return PForeignToPTypeNode.getUncached().executeConvert(result); } catch (AbstractTruffleException e) { throw e; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java index 61ecd9c9fc..3fbf8e949e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java @@ -40,6 +40,17 @@ */ package com.oracle.graal.python.builtins.modules.re; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; +import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; +import static com.oracle.graal.python.util.PythonUtils.callCallTarget; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +import org.graalvm.collections.EconomicMap; + import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAcquireLibrary; import com.oracle.graal.python.nodes.ErrorMessages; @@ -57,15 +68,6 @@ import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.strings.TruffleString; -import org.graalvm.collections.EconomicMap; - -import java.nio.charset.StandardCharsets; -import java.util.Objects; - -import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; -import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; -import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; -import static com.oracle.graal.python.util.PythonUtils.tsLiteral; public final class TRegexCache { @@ -302,7 +304,7 @@ public Object compile(Node node, PythonContext context, PythonMethod method, boo Object compiledRegex; try { Source regexSource = Source.newBuilder("regex", options + '/' + pattern + '/' + flags, "re").mimeType("application/tregex").internal(true).build(); - compiledRegex = context.getEnv().parseInternal(regexSource).call(); + compiledRegex = callCallTarget(context.getEnv().parseInternal(regexSource), node); assert !lib.isNull(compiledRegex) : "This shouldn't happen"; } catch (RuntimeException e) { throw handleCompilationError(node, e, lib); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/weakref/ProxyTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/weakref/ProxyTypeBuiltins.java index b274af6df0..e21082fc96 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/weakref/ProxyTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/weakref/ProxyTypeBuiltins.java @@ -40,6 +40,18 @@ */ package com.oracle.graal.python.builtins.modules.weakref; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ReferenceError; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___BYTES__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REVERSED__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___BYTES__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___DELITEM__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REVERSED__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SETITEM__; +import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; + +import java.util.List; + import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.annotations.Slot; @@ -133,18 +145,6 @@ import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; -import java.util.List; - -import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ReferenceError; -import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___BYTES__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REVERSED__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___BYTES__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___DELITEM__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REVERSED__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SETITEM__; -import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; - @CoreFunctions(extendClasses = PythonBuiltinClassType.PProxyType) public final class ProxyTypeBuiltins extends PythonBuiltins { @@ -311,17 +311,15 @@ static Object richCmp(VirtualFrame frame, PProxyType self, Object other, RichCmp } } - @Slot(value = Slot.SlotKind.nb_bool) + @Slot(value = Slot.SlotKind.nb_bool, isComplex = true) @GenerateUncached @GenerateNodeFactory public abstract static class BoolNode extends TpSlotInquiry.NbBoolBuiltinNode { - @Specialization - @TruffleBoundary - static boolean bool(PProxyType self, - @Bind Node inliningTarget) { - Object object = unwrap(self, inliningTarget); - return PyObjectIsTrueNode.executeUncached(object); + static boolean bool(VirtualFrame frame, PProxyType self, + @Bind Node inliningTarget, + @Cached PyObjectIsTrueNode isTrueNode) { + return isTrueNode.execute(frame, unwrap(self, inliningTarget)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java index cb14d670cc..74bb09f3d5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -1502,7 +1502,7 @@ static PList doStringKeepends(Node inliningTarget, TruffleString self, boolean k @Cached TRegexUtil.InvokeGetGroupBoundariesMethodNode getEndNode, @Cached TruffleString.SubstringByteIndexNode substringNode, @Cached AppendNode appendNode) { - Object lineBreakRegex = PythonLanguage.get(inliningTarget).getCachedTRegexLineBreakRegex(PythonContext.get(inliningTarget)); + Object lineBreakRegex = PythonLanguage.get(inliningTarget).getCachedTRegexLineBreakRegex(inliningTarget, PythonContext.get(inliningTarget)); CompilerAsserts.partialEvaluationConstant(lineBreakRegex); PList list = PFactory.createList(PythonLanguage.get(inliningTarget)); int lastEnd = 0; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotInquiry.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotInquiry.java index 2b93495d98..10c6272548 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotInquiry.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotInquiry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,25 +41,31 @@ package com.oracle.graal.python.builtins.objects.type.slots; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___BOOL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___BOOL__; +import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.CheckInquiryResultNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.ExternalFunctionInvokeNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeNode; +import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.type.slots.PythonDispatchers.UnaryPythonSlotDispatcherNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotBuiltinBase; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotNative; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotPythonSingle; -import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotSimpleBuiltinBase; import com.oracle.graal.python.lib.PyBoolCheckNode; import com.oracle.graal.python.lib.PyObjectIsTrueNode; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.call.CallDispatchers; import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.GetThreadStateNode; import com.oracle.graal.python.runtime.PythonContext.PythonThreadState; +import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; +import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateCached; @@ -74,16 +80,44 @@ public abstract class TpSlotInquiry { private TpSlotInquiry() { } - public abstract static class TpSlotInquiryBuiltin extends TpSlotSimpleBuiltinBase { + public abstract static sealed class TpSlotInquiryBuiltin extends + TpSlotBuiltinBase permits TpSlotInquiryBuiltinSimple, TpSlotInquiryBuiltinComplex { + static final BuiltinSlotWrapperSignature SIGNATURE = BuiltinSlotWrapperSignature.UNARY; + protected TpSlotInquiryBuiltin(NodeFactory nodeFactory) { - super(nodeFactory, BuiltinSlotWrapperSignature.UNARY, PExternalFunctionWrapper.INQUIRY); + super(nodeFactory, SIGNATURE, PExternalFunctionWrapper.INQUIRY); } final InquiryBuiltinNode createSlotNode() { return createNode(); } + } + + public abstract static non-sealed class TpSlotInquiryBuiltinSimple extends TpSlotInquiryBuiltin { + protected TpSlotInquiryBuiltinSimple(NodeFactory nodeFactory) { + super(nodeFactory); + } protected abstract boolean executeUncached(Object self); + + @Override + public final void initialize(PythonLanguage language) { + // nop + } + } + + public abstract static non-sealed class TpSlotInquiryBuiltinComplex extends TpSlotInquiryBuiltin { + private final int callTargetIndex = TpSlotBuiltinCallTargetRegistry.getNextCallTargetIndex(); + + protected TpSlotInquiryBuiltinComplex(NodeFactory nodeFactory) { + super(nodeFactory); + } + + @Override + public final void initialize(PythonLanguage language) { + RootCallTarget callTarget = createSlotCallTarget(language, SIGNATURE, getNodeFactory(), J___BOOL__); + language.setBuiltinSlotCallTarget(callTargetIndex, callTarget); + } } @GenerateInline(value = false, inherit = true) @@ -116,13 +150,6 @@ static boolean callCachedBuiltin(VirtualFrame frame, @SuppressWarnings("unused") return slotNode.executeBool(frame, self); } - @Specialization(replaces = "callCachedBuiltin") - static boolean callGenericSimpleBuiltin(TpSlotInquiryBuiltin slot, Object self) { - // All nb_bool builtins are known to be simple enough to not require PE for good - // performance, so we call them uncached - return slot.executeUncached(self); - } - @Specialization static boolean callPython(VirtualFrame frame, TpSlotPythonSingle slot, Object self, @Cached(inline = false) CallNbBoolPythonNode callSlotNode) { @@ -140,6 +167,23 @@ static boolean callNative(VirtualFrame frame, Node inliningTarget, TpSlotNative Object result = externalInvokeNode.call(frame, inliningTarget, threadState, C_API_TIMING, T___BOOL__, slot.callable, toNativeNode.execute(self)); return checkResultNode.executeBool(threadState, T___BOOL__, result); } + + @Specialization(replaces = "callCachedBuiltin") + static boolean callGenericSimpleBuiltin(TpSlotInquiryBuiltinSimple slot, Object self) { + // Most nb_bool builtins are known to be simple enough to not require PE for good + // performance, so we call them uncached + return slot.executeUncached(self); + } + + @Specialization(replaces = "callCachedBuiltin") + @InliningCutoff + static boolean callGenericComplexBuiltin(VirtualFrame frame, Node inliningTarget, TpSlotInquiryBuiltinComplex slot, Object self, + @Cached CallDispatchers.SimpleIndirectInvokeNode invoke) { + Object[] arguments = PArguments.create(1); + PArguments.setArgument(arguments, 0, self); + RootCallTarget callTarget = PythonLanguage.get(inliningTarget).getBuiltinSlotCallTarget(slot.callTargetIndex); + return (boolean) invoke.execute(frame, inliningTarget, callTarget, arguments); + } } @GenerateUncached diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/arrow/InvokeArrowReleaseCallbackNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/arrow/InvokeArrowReleaseCallbackNode.java index 3de2f37c0f..d7986b975d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/arrow/InvokeArrowReleaseCallbackNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/arrow/InvokeArrowReleaseCallbackNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -70,7 +70,7 @@ public final void executeCached(long releaseCallback, long baseStructure) { @Specialization static void doIt(Node inliningTarget, long releaseCallback, long baseStructure, @Bind("getContext(inliningTarget)") PythonContext ctx, - @Cached(value = "createReleaseCallbackSignature(ctx)", allowUncached = true) Object callbackSignature, + @Cached(value = "createReleaseCallbackSignature($node, ctx)", allowUncached = true) Object callbackSignature, @CachedLibrary(limit = "1") SignatureLibrary signatureLibrary) { try { signatureLibrary.call(callbackSignature, new NativePointer(releaseCallback), baseStructure); @@ -80,8 +80,8 @@ static void doIt(Node inliningTarget, long releaseCallback, long baseStructure, } @NeverDefault - static Object createReleaseCallbackSignature(PythonContext context) { - return ArrowUtil.createNfiSignature("(UINT64):VOID", context); + static Object createReleaseCallbackSignature(Node location, PythonContext context) { + return ArrowUtil.createNfiSignature(location, "(UINT64):VOID", context); } @GenerateCached(false) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadFrameNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadFrameNode.java index 804dfcbc4e..331a22c02f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadFrameNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadFrameNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -416,7 +416,7 @@ public StackWalkResult visitFrame(FrameInstance frameInstance) { // calls that may call back into Python code. Look at the Java stack trace and check // if all @TruffleBoundary methods are preceded by BoundaryCallContext.enter/exit assert first || !(PGenerator.unwrapContinuationRoot(rootNode) instanceof PBytecodeDSLRootNode) || !PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER || - callNode != null : rootNode; + callNode != null : String.format("root=%s, i=%d", rootNode, i); first = false; if (!(rootNode instanceof PRootNode pRootNode && pRootNode.setsUpCalleeContext())) { // Note: any non-Python Truffle frames should have been preceded by diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/AsyncHandler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/AsyncHandler.java index 1b3cc41ee5..82e97615d9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/AsyncHandler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/AsyncHandler.java @@ -164,15 +164,14 @@ public final void execute(PythonContext context, Access access) { } Node prev = null; Node location = access.getLocation(); - boolean locationAdoptable = location.isAdoptable(); EncapsulatingNodeReference encapsulatingNodeRef = EncapsulatingNodeReference.getCurrent(); - if (locationAdoptable) { - // If the location is not adoptable, then we are in - // IndirectCallContext and SimpleIndirectInvokeNode below will do - // IndirectCalleeContext.enter and transfer the state from thread state to - // the frame. Otherwise, we were woken-up in middle of Python frame code, we - // will have to do a stack walk if caller frame is needed, but we still need - // the "call" location + boolean resetEncapsulatingNode = false; + if (location.isAdoptable()) { + // If we are woken-up in middle of Python frame code, we will have to do a + // stack walk if caller frame is needed, but we still need the "call" + // location for the SimpleIndirectInvokeNode below, which takes it + // implicitly from the EncapsulatingNodeReference + resetEncapsulatingNode = true; if (location instanceof RootNode root && PBytecodeDSLRootNode.cast(root) != null) { // PBytecodeDSLRootNode is not usable as a location. To resolve the BCI // stored in the frame, we need the currently executing BytecodeNode, @@ -183,13 +182,30 @@ public final void execute(PythonContext context, Access access) { } else { prev = encapsulatingNodeRef.set(location); } + } else { + // If the safepoint location is not adoptable, then we are behind + // TruffleBoundary or in uncached interpreter. If we are woken up in GraalPy + // boundary code, it should have done BoundaryCallContext.enter/exit or + // EncapsulatingNodeReference.get().set(location) + Node node = encapsulatingNodeRef.get(); + if (node == null || !node.isAdoptable()) { + // Missing BoundaryCallContext.enter/exit or + // EncapsulatingNodeReference.get().set(location), + // but also possibly 3rd party code that polls safepoint behind + // TruffleBoundary with uncached/null location. We cannot distinguish + // that, so we use the dummy node to pass our assertions during stack + // walking that "call node" is never null. + encapsulatingNodeRef.set(language.unavailableSafepointLocation); + prev = node; + resetEncapsulatingNode = true; + } } try { CallDispatchers.SimpleIndirectInvokeNode.executeUncached(context.getAsyncHandler().callTarget, args); } catch (PException e) { handleException(e); } finally { - if (locationAdoptable) { + if (resetEncapsulatingNode) { encapsulatingNodeRef.set(prev); } if (debugger != null) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java index a93cb87c69..b1b36a4ec3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java @@ -79,6 +79,7 @@ import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR_BE; import static com.oracle.graal.python.util.PythonUtils.EMPTY_LONG_ARRAY; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; +import static com.oracle.graal.python.util.PythonUtils.callCallTarget; import static com.oracle.truffle.api.CompilerDirectives.SLOWPATH_PROBABILITY; import static com.oracle.truffle.api.CompilerDirectives.injectBranchProbability; import static com.oracle.truffle.api.CompilerDirectives.shouldNotReachHere; @@ -117,7 +118,6 @@ import com.oracle.graal.python.util.FunctionWithSignature; import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; -import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; @@ -419,8 +419,7 @@ private static Object loadLibrary(Node node, NFIPosixSupport posix, String path) loadSrc = Source.newBuilder(J_NFI_LANGUAGE, J_DEFAULT, J_DEFAULT).internal(true).build(); } - CallTarget callTarget = env.parseInternal(loadSrc); - return node != null && node.isAdoptable() ? callTarget.call(node) : callTarget.call(); + return callCallTarget(env.parseInternal(loadSrc), node); } @TruffleBoundary @@ -431,8 +430,7 @@ private static void loadFunction(Node node, NFIPosixSupport posix, Object librar String sig = String.format("with %s %s", posix.nfiBackend, function.signature); Source sigSrc = Source.newBuilder(J_NFI_LANGUAGE, sig, "posix-nfi-signature").internal(true).build(); - CallTarget callTarget = posix.context.getEnv().parseInternal(sigSrc); - Object signature = node != null && node.isAdoptable() ? callTarget.call(node) : callTarget.call(); + Object signature = PythonUtils.callCallTarget(posix.context.getEnv().parseInternal(sigSrc), node); unbound = interop.readMember(library, function.name()); posix.cachedFunctions.set(function.ordinal(), new FunctionWithSignature(signature, unbound)); } catch (UnsupportedMessageException | UnknownIdentifierException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativeLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativeLibrary.java index c14ffba60f..63468877f7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativeLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativeLibrary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -42,7 +42,9 @@ import static com.oracle.graal.python.nodes.StringLiterals.J_NFI_LANGUAGE; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; +import static com.oracle.graal.python.util.PythonUtils.callCallTarget; +import java.lang.invoke.VarHandle; import java.util.Objects; import java.util.logging.Level; @@ -145,7 +147,6 @@ public Throwable fillInStackTrace() { private volatile FunctionWithSignature[] cachedFunctions; private volatile Object cachedLibrary; private volatile InteropLibrary cachedLibraryInterop; - private volatile FunctionWithSignature dummy; public NativeLibrary(String name, int functionsCount, NFIBackend nfiBackend, String noNativeAccessHelp, boolean optional) { this.functionsCount = functionsCount; @@ -155,13 +156,13 @@ public NativeLibrary(String name, int functionsCount, NFIBackend nfiBackend, Str this.optional = optional; } - private Object getCachedLibrary(PythonContext context) { + private Object getCachedLibrary(Node location, PythonContext context) { if (cachedLibrary == null) { // This should be a one-off thing for each context CompilerDirectives.transferToInterpreter(); synchronized (this) { if (cachedLibrary == null) { - Object lib = loadLibrary(context); + Object lib = loadLibrary(location, context); if (lib != null) { // order matters due to multi-threading cases. cachedLibraryInterop = InteropLibrary.getUncached(lib); @@ -173,8 +174,8 @@ private Object getCachedLibrary(PythonContext context) { return cachedLibrary; } - private FunctionWithSignature getCachedFunction(PythonContext context, NativeFunction function) { - Object lib = getCachedLibrary(context); + private FunctionWithSignature getCachedFunction(Node location, PythonContext context, NativeFunction function) { + Object lib = getCachedLibrary(location, context); if (cachedFunctions == null) { // This should be a one-off thing for each context CompilerDirectives.transferToInterpreter(); @@ -189,31 +190,32 @@ private FunctionWithSignature getCachedFunction(PythonContext context, NativeFun // This should be a one-off thing for each context CompilerDirectives.transferToInterpreter(); synchronized (this) { - dummy = getFunction(context, lib, function); + FunctionWithSignature signature = getFunction(location, context, lib, function); + VarHandle.storeStoreFence(); // it is OK to overwrite cachedFunctions[functionIndex] that may have been - // written from another thread: no need to double check that it's still null. + // written from another thread: no need to double-check that it's still null. // dummy is volatile, the object must be fully initialized at this point - cachedFunctions[functionIndex] = dummy; + cachedFunctions[functionIndex] = signature; } } return cachedFunctions[functionIndex]; } - private FunctionWithSignature getFunction(PythonContext context, NativeFunction function) { + private FunctionWithSignature getFunction(Node location, PythonContext context, NativeFunction function) { CompilerAsserts.neverPartOfCompilation(); - Object lib = getCachedLibrary(context); - return getFunction(context, lib, function); + Object lib = getCachedLibrary(location, context); + return getFunction(location, context, lib, function); } - private Object parseSignature(PythonContext context, String signature) { + private Object parseSignature(Node location, PythonContext context, String signature) { Source sigSource = Source.newBuilder(J_NFI_LANGUAGE, nfiBackend.withClause + signature, "python-nfi-signature").build(); - return context.getEnv().parseInternal(sigSource).call(); + return callCallTarget(context.getEnv().parseInternal(sigSource), location); } - private FunctionWithSignature getFunction(PythonContext context, Object lib, NativeFunction function) { + private FunctionWithSignature getFunction(Node location, PythonContext context, Object lib, NativeFunction function) { CompilerAsserts.neverPartOfCompilation(); try { - Object signature = parseSignature(context, function.signature()); + Object signature = parseSignature(location, context, function.signature()); Object symbol = cachedLibraryInterop.readMember(lib, function.name()); return new FunctionWithSignature(signature, symbol); } catch (UnsupportedMessageException | UnknownIdentifierException e) { @@ -221,7 +223,7 @@ private FunctionWithSignature getFunction(PythonContext context, Object lib, Nat } } - private Object loadLibrary(PythonContext context) { + private Object loadLibrary(Node location, PythonContext context) { CompilerAsserts.neverPartOfCompilation(); if (context.isNativeAccessAllowed()) { String path = getLibPath(context, name); @@ -231,7 +233,7 @@ private Object loadLibrary(PythonContext context) { } Source loadSrc = Source.newBuilder(J_NFI_LANGUAGE, src, "load:" + name).internal(true).build(); try { - return context.getEnv().parseInternal(loadSrc).call(); + return context.getEnv().parseInternal(loadSrc).call(location); } catch (RuntimeException ex) { Level level = optional ? Level.FINE : Level.SEVERE; if (LOGGER.isLoggable(level)) { @@ -267,10 +269,10 @@ private static String getLibPath(PythonContext context, String name) { protected Object callUncached(PythonContext context, NativeFunction f, Object... args) { CompilerAsserts.neverPartOfCompilation(); - final Object lib = getCachedLibrary(context); + final Object lib = getCachedLibrary(null, context); if (lib != null) { try { - Object signature = parseSignature(context, f.signature()); + Object signature = parseSignature(null, context, f.signature()); Object symbol = cachedLibraryInterop.readMember(lib, f.name()); return SignatureLibrary.getUncached().call(signature, symbol, args); } catch (Exception e) { @@ -346,7 +348,7 @@ public & NativeFunction> TruffleString callString(TypedNative static Object doSingleContext(@SuppressWarnings("unused") NativeLibrary lib, @SuppressWarnings("unused") NativeFunction function, Object[] args, @SuppressWarnings("unused") @Cached(value = "lib", weak = true) NativeLibrary cachedLib, @Cached("function") NativeFunction cachedFunction, - @Cached(value = "getFunction(lib, function)", weak = true) FunctionWithSignature funObj, + @Cached(value = "getFunction($node, lib, function)", weak = true) FunctionWithSignature funObj, @CachedLibrary("funObj.signature()") SignatureLibrary funInterop) { return invoke(cachedFunction, args, funObj, funInterop); } @@ -357,7 +359,7 @@ static Object doMultiContext(NativeLibrary lib, NativeFunction functionIn, Objec @Cached InlinedExactClassProfile functionClassProfile, @CachedLibrary(limit = "1") SignatureLibrary funInterop) { NativeFunction function = functionClassProfile.profile(inliningTarget, functionIn); - FunctionWithSignature funObj = lib.getCachedFunction(PythonContext.get(funInterop), function); + FunctionWithSignature funObj = lib.getCachedFunction(inliningTarget, PythonContext.get(funInterop), function); return invoke(function, args, funObj, funInterop); } @@ -376,8 +378,8 @@ private static Object invoke(NativeFunction function, Object[] args, FunctionWit } } - protected FunctionWithSignature getFunction(NativeLibrary lib, NativeFunction fun) { - return lib.getFunction(PythonContext.get(this), fun); + protected FunctionWithSignature getFunction(Node location, NativeLibrary lib, NativeFunction fun) { + return lib.getFunction(location, PythonContext.get(this), fun); } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowSupport.java index 0ee633b6c9..6f71638ef8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -49,6 +49,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.nfi.api.SignatureLibrary; public class ArrowSupport { @@ -67,35 +68,35 @@ public ArrowSupport(PythonContext ctx) { private Object arrowSchemaDestructorNFIClosure; @CompilationFinal private long arrowSchemaDestructor; - public long getArrowSchemaDestructor() { + public long getArrowSchemaDestructor(Node location) { if (arrowSchemaDestructor == 0) { CompilerDirectives.transferToInterpreterAndInvalidate(); - initArrowSchemaDestructor(); + initArrowSchemaDestructor(location); } return arrowSchemaDestructor; } - public long getArrowArrayDestructor() { + public long getArrowArrayDestructor(Node location) { if (arrowArrayDestructor == 0L) { CompilerDirectives.transferToInterpreterAndInvalidate(); - initArrowArrayDestructor(); + initArrowArrayDestructor(location); } return arrowArrayDestructor; } @TruffleBoundary - private void initArrowArrayDestructor() { + private void initArrowArrayDestructor(Node location) { CompilerAsserts.neverPartOfCompilation(); - var signature = ArrowUtil.createNfiSignature("(POINTER):VOID", ctx); + var signature = ArrowUtil.createNfiSignature(location, "(POINTER):VOID", ctx); var executable = new ArrowArrayCapsuleDestructor(); this.arrowArrayDestructorNFIClosure = SignatureLibrary.getUncached().createClosure(signature, executable); this.arrowArrayDestructor = PythonUtils.coerceToLong(arrowArrayDestructorNFIClosure, InteropLibrary.getUncached()); } @TruffleBoundary - private void initArrowSchemaDestructor() { + private void initArrowSchemaDestructor(Node location) { CompilerAsserts.neverPartOfCompilation(); - var signature = ArrowUtil.createNfiSignature("(POINTER):VOID", ctx); + var signature = ArrowUtil.createNfiSignature(location, "(POINTER):VOID", ctx); var executable = new ArrowSchemaCapsuleDestructor(); this.arrowSchemaDestructorNFIClosure = SignatureLibrary.getUncached().createClosure(signature, executable); this.arrowSchemaDestructor = PythonUtils.coerceToLong(arrowSchemaDestructorNFIClosure, InteropLibrary.getUncached()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowUtil.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowUtil.java index cb0d0068c9..cab540e404 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowUtil.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/arrow/ArrowUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,15 +40,17 @@ */ package com.oracle.graal.python.runtime.arrow; +import static com.oracle.graal.python.nodes.StringLiterals.J_NFI_LANGUAGE; +import static com.oracle.graal.python.util.PythonUtils.callCallTarget; + import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; -import static com.oracle.graal.python.nodes.StringLiterals.J_NFI_LANGUAGE; - public class ArrowUtil { - public static Object createNfiSignature(String methodSignature, PythonContext ctx) { + public static Object createNfiSignature(Node location, String methodSignature, PythonContext ctx) { Source sigSource = Source.newBuilder(J_NFI_LANGUAGE, methodSignature, "python-nfi-signature").build(); - return ctx.getEnv().parseInternal(sigSource).call(); + return callCallTarget(ctx.getEnv().parseInternal(sigSource), location); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java index ecf1d7ab58..42a6d7c208 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java @@ -100,7 +100,6 @@ import com.oracle.truffle.api.nodes.NodeVisitor; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.ConditionProfile; -import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleString.Encoding; @@ -719,21 +718,11 @@ public static void flipBuffer(ByteBuffer buffer) { buffer.flip(); } - @TruffleBoundary - public static boolean bufferHasRemaining(ByteBuffer buffer) { - return buffer.hasRemaining(); - } - @TruffleBoundary public static boolean equals(Object a, Object b) { return a.equals(b); } - @TruffleBoundary - public static ArrayDeque newDeque() { - return new ArrayDeque<>(); - } - @TruffleBoundary public static void push(ArrayDeque q, E e) { q.push(e); @@ -764,22 +753,6 @@ public static Object[] toArray(List list) { return list.toArray(); } - /** - * Same as {@link Character#isBmpCodePoint(int)}. - */ - public static boolean isBmpCodePoint(int codePoint) { - return codePoint >>> 16 == 0; - // Optimized form of: - // codePoint >= MIN_VALUE && codePoint <= MAX_VALUE - // We consistently use logical shift (>>>) to facilitate - // additional runtime optimizations. - } - - public static ValueProfile createValueIdentityProfile() { - CompilerAsserts.neverPartOfCompilation(); - return PythonLanguage.get(null).isSingleContext() ? ValueProfile.createIdentityProfile() : ValueProfile.createClassProfile(); - } - @TruffleBoundary public static PBuiltinFunction createMethod(PythonLanguage language, Object klass, NodeFactory nodeFactory, Object type, int numDefaults) { Class nodeClass = nodeFactory.getNodeClass(); @@ -858,14 +831,6 @@ public static byte[] getAsciiBytes(TruffleString string, TruffleString.CopyToByt return data; } - public static ConditionProfile[] createConditionProfiles(int n) { - ConditionProfile[] profiles = new ConditionProfile[n]; - for (int i = 0; i < profiles.length; i++) { - profiles[i] = ConditionProfile.create(); - } - return profiles; - } - public static Object builtinClassToType(Object cls) { if (cls instanceof PythonBuiltinClass builtinClass) { return builtinClass.getType(); @@ -1024,30 +989,6 @@ public static long crcHqx(int initialValue, byte[] bytes, int offset, int length 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, }; - /** - * Use as a documentation and safety guard in specializations that are meant to be activated - * only in the uncached case. Those Specializations exist only to allow to generate an uncached - * variant of the node, but should never be activated in a regular cached case. - * - * Note that such specializations can take VirtualFrame and should forward it to other uncached - * (and cached) nodes. The uncached nodes may be executed during the uncached execution of the - * bytecode root node where it is allowed to pass the VirtualFrame around without materializing - * it. - */ - public static void assertUncached() { - if (!TruffleOptions.AOT) { - // We cannot assert that it's never part of compilation, because then it would fail - // during native-image build since it cannot prove that this Specialization is never - // activated at runtime and includes this in runtime compiled methods. - CompilerAsserts.neverPartOfCompilation(); - } - CompilerDirectives.transferToInterpreter(); - } - - public static boolean isBitSet(int state, int position) { - return ((state >>> position) & 0x1) != 0; - } - public static String formatPointer(Object pointer) { CompilerAsserts.neverPartOfCompilation(); InteropLibrary lib = InteropLibrary.getUncached(pointer); @@ -1076,6 +1017,22 @@ public static long coerceToLong(Object allocated, InteropLibrary lib) { } } + /** + * Use this helper in PE code or behind Truffle boundary if the PE caller does not push + * encapsulating node (either directly or, e.g., via + * {@link com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext}). + *

+ * For boundary calls: if we know the encapsulating node was set, we can safely call directly + * the overload without the location parameter ({@link CallTarget#call(Object...)}). + *

+ * For PE calls: we may be in uncached interpreter (the {@code location} Node is not adoptable + * or {@code null}), in which case we must call the overload without the location parameter + * ({@link CallTarget#call(Object...)}), so that it uses the encapsulating node. + */ + public static Object callCallTarget(CallTarget target, Node location, Object... args) { + return location != null && location.isAdoptable() ? target.call(location, args) : target.call(args); + } + public static InteropLibrary getUncachedInterop(InteropLibrary existing, Object obj) { // TODO: have a simple LRU cache of "uncached" pointer InteropLibrary in context? // "accepts" should be fast and saves us the concurrent hash map lookup in getUncached