diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java index 41140d446a..e7d23a3f21 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/debug/PythonDebugTest.java @@ -82,6 +82,7 @@ public void before() { Builder newBuilder = Context.newBuilder(); newBuilder.allowExperimentalOptions(true); newBuilder.allowAllAccess(true); + newBuilder.option("engine.WarnInterpreterOnly", "false"); PythonTests.closeContext(); tester = new DebuggerTester(newBuilder); } diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_code.py b/graalpython/com.oracle.graal.python.test/src/tests/test_code.py index b34bc155a5..8c944d6377 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_code.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_code.py @@ -1,4 +1,4 @@ -# 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 @@ -284,4 +284,32 @@ def bug93662(): raise ValueError() check_lines(misshappen) - check_lines(bug93662) \ No newline at end of file + check_lines(bug93662) + + +def test_code_identity(): + import sys + import marshal + import types + import _imp + def foo(): + def bar(): + return sys._getframe() + + return bar + + bar = foo() + assert bar.__code__ is foo().__code__ + i = foo.__code__.co_consts.index(bar.__code__) + # TODO this is currently broken on the DSL interpreter because the code unit in constants is a separate copy + # assert bar.__code__ is foo.__code__.co_consts[i] + assert bar.__code__ is bar().f_code + + foo_copy = types.FunctionType(marshal.loads(marshal.dumps(foo.__code__)), globals=foo.__globals__, closure=foo.__closure__) + bar_copy = foo_copy() + assert foo_copy.__code__ is not foo.__code__ + _imp._fix_co_filename(foo_copy.__code__, 'asdf') + assert foo_copy.__code__.co_filename == 'asdf' + assert bar_copy.__code__.co_filename == 'asdf' + assert foo.__code__.co_filename != 'asdf' + assert bar.__code__.co_filename != 'asdf' 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 54a7030aad..fe350688b0 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 @@ -808,6 +808,7 @@ public Object execute(VirtualFrame frame) { PFrame pFrame = materializeFrameNode.execute(this, false, true, frame); Object pLocals = getFrameLocalsNode.executeCached(frame, pFrame, true); PArguments.setSpecialArgument(arguments, pLocals); + PArguments.setCodeObject(arguments, PFactory.createCode(getLanguage(PythonLanguage.class), callTarget)); PArguments.setGlobals(arguments, PArguments.getGlobals(frame)); boolean wasAcquired = gilNode.acquire(); try { @@ -1186,6 +1187,10 @@ public RootCallTarget createCachedCallTarget(Function return createCachedCallTargetUnsafe(rootNodeFunction, true, nodeClass1, nodeClass2, type, name); } + public RootCallTarget createCachedCallTarget(Function rootNodeFunction, CodeUnit key) { + return createCachedCallTargetUnsafe(rootNodeFunction, true, key); + } + /** * Caches call targets for external C functions created by extensions at runtime. *

diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java index 1e537ec582..f3de65b755 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java @@ -224,6 +224,7 @@ import com.oracle.graal.python.builtins.objects.bytes.BytesCommonBuiltins; import com.oracle.graal.python.builtins.objects.cell.CellBuiltins; import com.oracle.graal.python.builtins.objects.code.CodeBuiltins; +import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.complex.ComplexBuiltins; import com.oracle.graal.python.builtins.objects.contextvars.ContextBuiltins; @@ -1328,7 +1329,8 @@ private void loadFile(TruffleString s, TruffleString prefix, PythonModule mod) { return getLanguage().parse(getContext(), source, InputType.FILE, false, 0, false, null, EnumSet.noneOf(FutureFeature.class)); }; RootCallTarget callTarget = (RootCallTarget) getLanguage().cacheCode(s, getCode); - CallDispatchers.SimpleIndirectInvokeNode.executeUncached(callTarget, PArguments.withGlobals(mod)); + PCode code = PFactory.createCode(language, callTarget); + CallDispatchers.SimpleIndirectInvokeNode.executeUncached(callTarget, PArguments.withGlobals(code, mod)); } public final PInt getTrue() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java index c3e8fda3ed..8b8eb7d983 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java @@ -895,6 +895,7 @@ static Object eval(VirtualFrame frame, Node inliningTarget, Object source, Objec throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.CODE_OBJ_NO_FREE_VARIABLES, mode); } Object[] args = createArguments.execute(frame, inliningTarget, globals, locals, mode); + PArguments.setCodeObject(args, code); RootCallTarget callTarget = getCallTarget.execute(inliningTarget, code); return invoke.execute(frame, inliningTarget, callTarget, args); } @@ -985,10 +986,9 @@ protected abstract Object executeInternal(VirtualFrame frame, Object source, Tru int featureVersion); private int inheritFlags(VirtualFrame frame, int flags, ReadFrameNode readCallerFrame) { - PFrame fr = readCallerFrame.getCurrentPythonFrame(frame); - if (fr != null) { - PCode code = PFactory.createCode(PythonLanguage.get(this), fr.getTarget()); - flags |= code.getFlags() & PyCF_MASK; + PFrame pyFrame = readCallerFrame.getCurrentPythonFrame(frame); + if (pyFrame != null) { + flags |= pyFrame.getCode().getFlags() & PyCF_MASK; } return flags; } @@ -1071,7 +1071,7 @@ Object compile(TruffleString expression, TruffleString filename, TruffleString m } else { ct = getContext().getLanguage().cacheCode(filename, createCode); } - return wrapRootCallTarget((RootCallTarget) ct); + return wrapRootCallTarget((RootCallTarget) ct, filename); } @Specialization(limit = "3") @@ -1102,7 +1102,7 @@ Object generic(VirtualFrame frame, Object wSource, Object wFilename, TruffleStri ModTy mod = AstModuleBuiltins.obj2sst(inliningTarget, context, wSource, getParserInputType(mode, flags)); Source source = PythonUtils.createFakeSource(filename); RootCallTarget rootCallTarget = context.getLanguage(inliningTarget).compileModule(context, mod, source, false, optimize, null, null, flags); - return wrapRootCallTarget(rootCallTarget); + return wrapRootCallTarget(rootCallTarget, filename); } TruffleString source = sourceAsString(frame, inliningTarget, wSource, filename, interopLib, acquireLib, bufferLib, switchEncodingNode, raiseNode); checkSource(source); @@ -1112,7 +1112,7 @@ Object generic(VirtualFrame frame, Object wSource, Object wFilename, TruffleStri } } - private static PCode wrapRootCallTarget(RootCallTarget rootCallTarget) { + private static PCode wrapRootCallTarget(RootCallTarget rootCallTarget, TruffleString filename) { RootNode rootNode = rootCallTarget.getRootNode(); if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { if (rootNode instanceof PBytecodeDSLRootNode bytecodeDSLRootNode) { @@ -1121,7 +1121,7 @@ private static PCode wrapRootCallTarget(RootCallTarget rootCallTarget) { } else if (rootNode instanceof PBytecodeRootNode bytecodeRootNode) { bytecodeRootNode.triggerDeferredDeprecationWarnings(); } - return PFactory.createCode(PythonLanguage.get(null), rootCallTarget); + return PFactory.createCode(PythonLanguage.get(null), rootCallTarget, filename); } @TruffleBoundary 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 042ab27c0c..c5df567077 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 @@ -410,7 +410,9 @@ private void runFile(PythonContext context, TruffleString inputFilePath) { } PythonLanguage language = context.getLanguage(); RootCallTarget callTarget = (RootCallTarget) context.getEnv().parsePublic(source); + PCode code = PFactory.createCode(language, callTarget); Object[] arguments = PArguments.create(); + PArguments.setCodeObject(arguments, code); PythonModule mainModule = context.getMainModule(); PDict mainDict = GetOrCreateDictNode.executeUncached(mainModule); PArguments.setGlobals(arguments, mainDict); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java index b9b5feb9c7..1d4752f59b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java @@ -89,7 +89,6 @@ import com.oracle.graal.python.builtins.objects.module.PythonFrozenModule; import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.object.PythonObject; -import com.oracle.graal.python.builtins.objects.str.PString; import com.oracle.graal.python.builtins.objects.str.StringNodes; import com.oracle.graal.python.compiler.CodeUnit; import com.oracle.graal.python.lib.PyMemoryViewFromObject; @@ -625,13 +624,14 @@ public static PythonModule importFrozenModuleObject(Node inliningTarget, PConstr RootCallTarget callTarget = createCallTarget(core.getContext(), info); PythonModule module = globals == null ? PFactory.createPythonModule(name) : globals; + PCode code = PFactory.createCode(core.getLanguage(), callTarget); if (info.isPackage) { /* Set __path__ to the empty list */ WriteAttributeToPythonObjectNode.getUncached().execute(module, T___PATH__, PFactory.createList(core.getLanguage())); } - CallDispatchers.SimpleIndirectInvokeNode.executeUncached(callTarget, PArguments.withGlobals(module)); + CallDispatchers.SimpleIndirectInvokeNode.executeUncached(callTarget, PArguments.withGlobals(code, module)); Object origName = info.origName == null ? PNone.NONE : info.origName; WriteAttributeToPythonObjectNode.getUncached().execute(module, T___ORIGNAME__, origName); @@ -728,23 +728,20 @@ protected ArgumentClinicProvider getArgumentClinic() { } } - @Builtin(name = "_fix_co_filename", minNumOfPositionalArgs = 2) + @Builtin(name = "_fix_co_filename", minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 2, parameterNames = {"code", "path"}) @GenerateNodeFactory - public abstract static class FixCoFilename extends PythonBinaryBuiltinNode { + @ArgumentClinic(name = "path", conversion = ClinicConversion.TString) + public abstract static class FixCoFilename extends PythonBinaryClinicBuiltinNode { @Specialization @TruffleBoundary - public Object run(PCode code, PString path, - @Bind Node inliningTarget, - @Cached CastToTruffleStringNode castToStringNode) { - code.setFilename(castToStringNode.execute(inliningTarget, path)); + public Object run(PCode code, TruffleString path) { + code.fixCoFilename(path); return PNone.NONE; } - @Specialization - @TruffleBoundary - public Object run(PCode code, TruffleString path) { - code.setFilename(path); - return PNone.NONE; + @Override + protected ArgumentClinicProvider getArgumentClinic() { + return ImpModuleBuiltinsClinicProviders.FixCoFilenameClinicProviderGen.INSTANCE; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java index 76cb8a1a3a..8ec4564be5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java @@ -118,7 +118,6 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnit; -import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnitAndRoot; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNodeGen; import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode; @@ -347,7 +346,6 @@ public static final class Marshal { private static final char TYPE_ARRAY = ']'; // These are constants that show up in the Bytecode DSL interpreter. private static final char TYPE_GRAALPYTHON_DSL_CODE_UNIT = 'D'; - private static final char TYPE_GRAALPYTHON_DSL_CODE_UNIT_AND_ROOT = 'K'; private static final char TYPE_DSL_SOURCE = '$'; private static final char TYPE_DSL_EMPTY_KEYWORDS = 'k'; @@ -804,16 +802,6 @@ private void writeObject(Object v) throws IOException { } else if (v instanceof BigInteger) { writeByte(TYPE_BIG_INTEGER); writeBigInteger((BigInteger) v); - } else if (v instanceof BytecodeDSLCodeUnitAndRoot unitAndRoot) { - // BytecodeDSLCodeUnit data should be deserialized to BytecodeDSLCodeUnit if we are - // deserializing a constant in the constants array of BytecodeDSLCodeUnit, otherwise - // if we are deserializing a constant operand of MakeFunction operation, we should - // deserialize it to BytecodeDSLCodeUnitAndRoot. - // In the deserializer we would have to pass down some context to know whether to - // deserialize to one or the other. Instead, we write this extra byte that allows us - // to distinguish this locally during deserialization. - writeByte(TYPE_GRAALPYTHON_DSL_CODE_UNIT_AND_ROOT); - writeReferenceOrComplexObject(unitAndRoot.getCodeUnit()); } else { writeReferenceOrComplexObject(v); } @@ -1187,13 +1175,6 @@ private Object readObject(int type, AddRefAndReturn addRef) throws NumberFormatE return addRef.run(readBytecodeCodeUnit()); case TYPE_GRAALPYTHON_DSL_CODE_UNIT: return addRef.run(readBytecodeDSLCodeUnit()); - case TYPE_GRAALPYTHON_DSL_CODE_UNIT_AND_ROOT: - Object co = readObject(); - if (co instanceof BytecodeDSLCodeUnit dslUnit) { - return new BytecodeDSLCodeUnitAndRoot(dslUnit); - } else { - throw new MarshalError(ValueError, ErrorMessages.BAD_MARSHAL_DATA); - } case TYPE_DSL_SOURCE: return getSource(); case TYPE_DSL_EMPTY_KEYWORDS: @@ -1571,14 +1552,12 @@ private PCode readCode() { return PythonLanguage.callTargetFromBytecode(context, subSource, code); }; CallTarget callTarget; - if (context.getLanguage().isSingleContext() || cacheKey == 0) { + if (getLanguage().isSingleContext() || cacheKey == 0) { callTarget = supplier.get(); } else { - // get a new ID every time we deserialize the same filename in the same context - long fullCacheKey = cacheKey + context.getDeserializationId(fileName); - callTarget = context.getLanguage().cacheCode(new PythonLanguage.CodeCacheKey(fileName, fullCacheKey), supplier); + callTarget = getLanguage().cacheCode(new PythonLanguage.CodeCacheKey(fileName, cacheKey), supplier); } - return PFactory.createCode(context.getLanguage(), (RootCallTarget) callTarget, flags, firstLineNo, lnoTab, fileName); + return PFactory.createCode(getLanguage(), (RootCallTarget) callTarget, flags, firstLineNo, lnoTab, fileName); } } 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 aff1a9f536..cea24442b7 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 @@ -45,7 +45,6 @@ import static com.oracle.graal.python.nodes.ErrorMessages.INTEROP_TYPE_ALREADY_REGISTERED; import static com.oracle.graal.python.nodes.ErrorMessages.INTEROP_TYPE_NOT_MERGABLE; import static com.oracle.graal.python.nodes.ErrorMessages.S_ARG_MUST_BE_S_NOT_P; -import static com.oracle.graal.python.nodes.ErrorMessages.S_CANNOT_HAVE_S; import static com.oracle.graal.python.nodes.ErrorMessages.S_DOES_NOT_TAKE_VARARGS; import static com.oracle.graal.python.nodes.ErrorMessages.S_TAKES_EXACTLY_D_ARGS; import static com.oracle.graal.python.nodes.ErrorMessages.S_TAKES_NO_KEYWORD_ARGS; @@ -706,10 +705,6 @@ void handleArg(Object value, InteropBehaviorMethod method, InteropBehavior inter // validate the function if (function.getKwDefaults().length != 0) { throw raiseNode.raise(this, ValueError, S_TAKES_NO_KEYWORD_ARGS, method.name); - } else if (function.getCode().getCellVars().length != 0) { - throw raiseNode.raise(this, ValueError, S_CANNOT_HAVE_S, method.name, "cell vars"); - } else if (function.getCode().getFreeVars().length != 0) { - throw raiseNode.raise(this, ValueError, S_CANNOT_HAVE_S, method.name, "free vars"); } else { // check signature if (method.takesVarArgs != signature.takesVarArgs()) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java index e81bb0bbe2..68bf00ea9a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java @@ -80,7 +80,6 @@ import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltinsClinicProviders.WarnBuiltinNodeClinicProviderGen; import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltinsFactory.WarnBuiltinNodeFactory; import com.oracle.graal.python.builtins.objects.PNone; -import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.frame.PFrame; @@ -140,7 +139,6 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -403,22 +401,21 @@ private PFrame getCallerFrame(VirtualFrame frame, int stackLevel, TruffleString[ readFrameNode = insert(ReadFrameNode.create()); } ReadFrameNode.FrameSelector selector = ReadFrameNode.VisiblePythonFramesSelector.INSTANCE; - if (skipFilePrefixes != null) { - /* - * CPython would always count the first frame into the stacklevel even if it is - * supposed to be skipped. We do that too, but our code is one off because of the - * builtin frame. Let's just assume the common case where the first python frame is - * always skipped by the filter. - */ - stackLevel--; - selector = rootNode -> ReadFrameNode.VisiblePythonFramesSelector.INSTANCE.skip(rootNode) || isFilenameToSkip(skipFilePrefixes, rootNode); - } - return readFrameNode.getFrameForReference(frame, PArguments.getCurrentFrameInfo(frame), selector, stackLevel, CallerFlags.NEEDS_LASTI); + if (skipFilePrefixes != null && stackLevel > 0) { + PFrame currentFrame = readFrameNode.getCurrentPythonFrame(frame, CallerFlags.NEEDS_LASTI); + while (--stackLevel > 0 && currentFrame != null) { + do { + currentFrame = readFrameNode.getFrameForReference(frame, currentFrame.getRef(), selector, 1, CallerFlags.NEEDS_LASTI); + } while (currentFrame != null && isFilenameToSkip(currentFrame.getCode().getFilename(), skipFilePrefixes)); + } + return currentFrame; + } else { + return readFrameNode.getFrameForReference(frame, PArguments.getCurrentFrameInfo(frame), selector, stackLevel - 1, CallerFlags.NEEDS_LASTI); + } } @TruffleBoundary - private static boolean isFilenameToSkip(TruffleString[] skipFilePrefixes, RootNode rootNode) { - TruffleString fileName = PCode.extractFileName(rootNode); + private static boolean isFilenameToSkip(TruffleString fileName, TruffleString[] skipFilePrefixes) { for (TruffleString prefix : skipFilePrefixes) { if (fileName.byteLength(TS_ENCODING) >= prefix.byteLength(TS_ENCODING) && prefix.regionEqualByteIndexUncached(0, fileName, 0, prefix.byteLength(TS_ENCODING), TS_ENCODING)) { @@ -871,9 +868,7 @@ private void warnExplicitPart2(PythonContext context, PythonModule warnings, Tru * Used from doWarn. On the fast path. */ private void setupContext(VirtualFrame frame, int stackLevel, TruffleString[] skipFilePrefixes, TruffleString[] filename, int[] lineno, TruffleString[] module, Object[] registry) { - // the stack level for the intrinsified version is off-by-one compared to the Python - // version - PFrame f = frame == null ? null : getCallerFrame(frame, stackLevel - 1, skipFilePrefixes); + PFrame f = frame == null ? null : getCallerFrame(frame, stackLevel, skipFilePrefixes); PDict globals; if (f == null || f.getGlobals() == null) { globals = getSysDict(); @@ -884,7 +879,7 @@ private void setupContext(VirtualFrame frame, int stackLevel, TruffleString[] sk lineno[0] = f.getLine(); RootCallTarget ct = f.getTarget(); if (ct != null) { - filename[0] = PCode.extractFileName(ct.getRootNode()); + filename[0] = f.getCode().getFilename(); } else { filename[0] = T_UNKNOWN_SOURCE; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGeneratorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGeneratorBuiltins.java index 716f7b5c8a..28c83c8b8f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGeneratorBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGeneratorBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -68,7 +68,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; @CoreFunctions(extendClasses = PythonBuiltinClassType.PAsyncGenerator) public final class AsyncGeneratorBuiltins extends PythonBuiltins { @@ -96,10 +95,8 @@ protected List> getNodeFa @GenerateNodeFactory public abstract static class GetCode extends PythonUnaryBuiltinNode { @Specialization - static Object getCode(PAsyncGen self, - @Bind Node inliningTarget, - @Cached InlinedConditionProfile hasCodeProfile) { - return self.getOrCreateCode(inliningTarget, hasCodeProfile); + static Object getCode(PAsyncGen self) { + return self.getGeneratorFunction().getCode(); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java index b61beaa410..b6fed6522e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -144,9 +144,6 @@ private static PCode createCode(PythonLanguage language, PythonContext context, ct = deserializeForBytecodeInterpreter(context, codedata, cellvars, freevars, flags); signature = ((PRootNode) ct.getRootNode()).getSignature(); } - if (filename != null) { - context.setCodeFilename(ct, filename); - } return PFactory.createCode(language, ct, signature, nlocals, stacksize, flags, constants, names, varnames, freevars, cellvars, filename, name, qualname, firstlineno, linetable); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java index 7e4b524a9c..397659c088 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java @@ -48,8 +48,10 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import com.oracle.graal.python.PythonLanguage; @@ -78,7 +80,6 @@ import com.oracle.graal.python.runtime.sequence.storage.DoubleSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.LongSequenceStorage; import com.oracle.graal.python.util.PythonUtils; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.bytecode.BytecodeNode; @@ -135,6 +136,8 @@ public final class PCode extends PythonBuiltinObject { // qualified name with which this code object was defined private TruffleString qualname; + private Map childCode; + // number of first line in Python source code private int firstlineno = -1; // is a string encoding the mapping from bytecode offsets to line numbers @@ -145,9 +148,14 @@ public final class PCode extends PythonBuiltinObject { private TruffleString[] cellvars; public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget) { + this(cls, instanceShape, callTarget, null); + } + + public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget, TruffleString filename) { super(cls, instanceShape); this.callTarget = callTarget; this.signature = Signature.fromCallTarget(callTarget); + this.filename = filename; } public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget, int flags, int firstlineno, byte[] linetable, TruffleString filename) { @@ -158,15 +166,15 @@ public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget, int fla this.filename = filename; } - public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget, Signature signature, BytecodeCodeUnit codeUnit) { + public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget, Signature signature, BytecodeCodeUnit codeUnit, TruffleString filename) { this(cls, instanceShape, callTarget, signature, codeUnit.varnames.length, -1, -1, null, null, - null, null, null, null, + null, null, null, filename, codeUnit.name, codeUnit.qualname, -1, codeUnit.srcOffsetTable); } - public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget, Signature signature, BytecodeDSLCodeUnit codeUnit) { + public PCode(Object cls, Shape instanceShape, RootCallTarget callTarget, Signature signature, BytecodeDSLCodeUnit codeUnit, TruffleString filename) { this(cls, instanceShape, callTarget, signature, codeUnit.varnames.length, -1, -1, null, null, - null, null, null, null, + null, null, null, filename, codeUnit.name, codeUnit.qualname, -1, null); } @@ -212,39 +220,14 @@ private static TruffleString[] extractCellVars(RootNode rootNode) { } } - @TruffleBoundary - private static void setRootNodeFileName(RootNode rootNode, TruffleString filename) { - RootNode funcRootNode = rootNodeForExtraction(rootNode); - PythonContext.get(rootNode).setCodeFilename(funcRootNode.getCallTarget(), filename); - } - @TruffleBoundary public static TruffleString extractFileName(RootNode rootNode) { RootNode funcRootNode = rootNodeForExtraction(rootNode); - - PythonContext context = PythonContext.get(rootNode); - TruffleString filename; - if (context != null) { - if (rootNode instanceof PBytecodeRootNode) { - filename = context.getCodeUnitFilename(((PBytecodeRootNode) rootNode).getCodeUnit()); - } else { - filename = context.getCodeFilename(funcRootNode.getCallTarget()); - } - } else { - return toInternedTruffleStringUncached(funcRootNode.getName()); - } - if (filename != null) { - // for compiled modules, _imp._fix_co_filename will set the filename - return filename; - } - SourceSection src = funcRootNode.getSourceSection(); - String jFilename; - if (src != null) { - jFilename = getSourceSectionFileName(src); - } else { - jFilename = funcRootNode.getName(); + String fileName = getSourceSectionFileName(funcRootNode.getSourceSection()); + if (fileName != null) { + return toInternedTruffleStringUncached(fileName); } - return toInternedTruffleStringUncached(jFilename); + return toInternedTruffleStringUncached(funcRootNode.getName()); } @TruffleBoundary @@ -293,7 +276,7 @@ private static int extractStackSize(RootNode rootNode) { BytecodeCodeUnit code = bytecodeRootNode.getCodeUnit(); return code.stacksize + code.varnames.length + code.cellvars.length + code.freevars.length; } - /** + /* * NB: This fallback case includes PBytecodeDSLRootNode. The Bytecode DSL stack does not * mirror a CPython stack (it's an operand stack for its own instruction set), so the frame * size is our best estimate. @@ -311,14 +294,14 @@ private static TruffleString[] extractVarnames(RootNode node) { } @TruffleBoundary - private static Object[] extractConstants(RootNode node) { + private Object[] extractConstants(RootNode node) { RootNode rootNode = rootNodeForExtraction(node); if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { if (rootNode instanceof PBytecodeDSLRootNode bytecodeDSLRootNode) { BytecodeDSLCodeUnit co = bytecodeDSLRootNode.getCodeUnit(); List constants = new ArrayList<>(); for (int i = 0; i < co.constants.length; i++) { - Object constant = convertConstantToPythonSpace(rootNode, co.constants[i]); + Object constant = convertConstantToPythonSpace(co.constants[i]); constants.add(constant); } return constants.toArray(new Object[0]); @@ -350,7 +333,7 @@ private static Object[] extractConstants(RootNode node) { } List constants = new ArrayList<>(); for (int i = 0; i < co.constants.length; i++) { - Object constant = convertConstantToPythonSpace(rootNode, co.constants[i]); + Object constant = convertConstantToPythonSpace(co.constants[i]); if (constant != PNone.NONE || !bytecodeConstants.contains(PNone.NONE)) { constants.add(constant); } @@ -428,21 +411,17 @@ public TruffleString[] getCellVars() { return cellvars; } - public void setFilename(TruffleString filename) { - CompilerAsserts.neverPartOfCompilation(); + @TruffleBoundary + public void fixCoFilename(TruffleString filename) { filename = PythonUtils.internString(filename); - this.filename = filename; - RootNode rootNode = rootNodeForExtraction(getRootNode()); - setRootNodeFileName(rootNode, filename); - if (rootNode instanceof PBytecodeRootNode) { - PythonContext context = PythonContext.get(rootNode); - CodeUnit co = ((PBytecodeRootNode) rootNode).getCodeUnit(); - context.setCodeUnitFilename(co, filename); - for (int i = 0; i < co.constants.length; i++) { - if (co.constants[i] instanceof CodeUnit) { - context.setCodeUnitFilename((CodeUnit) co.constants[i], filename); - } + /* + * New code objects inherit the filename from parent, so no need to eagerly construct them + * here + */ + if (childCode != null) { + for (PCode code : childCode.values()) { + code.filename = filename; } } } @@ -553,17 +532,58 @@ public Object[] getConstants() { } @TruffleBoundary - private static Object convertConstantToPythonSpace(RootNode rootNode, Object o) { + public PCode getOrCreateChildCode(BytecodeDSLCodeUnit codeUnit) { + PCode code = null; + if (childCode == null) { + childCode = new HashMap<>(); + } else { + code = childCode.get(codeUnit); + } + if (code == null) { + PBytecodeDSLRootNode outerRootNode = (PBytecodeDSLRootNode) getRootNode(); + PythonLanguage language = outerRootNode.getLanguage(); + RootCallTarget callTarget = language.createCachedCallTarget(l -> codeUnit.createRootNode(PythonContext.get(null), outerRootNode.getSource()), codeUnit); + PBytecodeDSLRootNode rootNode = (PBytecodeDSLRootNode) callTarget.getRootNode(); + code = PFactory.createCode(language, callTarget, rootNode.getSignature(), codeUnit, getFilename()); + childCode.put(codeUnit, code); + } + return code; + } + + @TruffleBoundary + public PCode getOrCreateChildCode(BytecodeCodeUnit codeUnit) { + PCode code = null; + if (childCode == null) { + childCode = new HashMap<>(); + } else { + code = childCode.get(codeUnit); + } + if (code == null) { + PBytecodeRootNode outerRootNode = (PBytecodeRootNode) getRootNodeForExtraction(); + PythonLanguage language = outerRootNode.getLanguage(); + RootCallTarget callTarget = language.createCachedCallTarget( + l -> PBytecodeRootNode.createMaybeGenerator(language, codeUnit, outerRootNode.getLazySource(), outerRootNode.isInternal()), + codeUnit); + RootNode rootNode = callTarget.getRootNode(); + if (rootNode instanceof PBytecodeGeneratorFunctionRootNode generatorRoot) { + rootNode = generatorRoot.getBytecodeRootNode(); + } + code = PFactory.createCode(language, callTarget, ((PBytecodeRootNode) rootNode).getSignature(), codeUnit, getFilename()); + childCode.put(codeUnit, code); + } + return code; + } + + @TruffleBoundary + private Object convertConstantToPythonSpace(Object o) { PythonLanguage language = PythonLanguage.get(null); if (o instanceof CodeUnit) { if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { BytecodeDSLCodeUnit code = (BytecodeDSLCodeUnit) o; - PBytecodeDSLRootNode root = code.createRootNode(PythonContext.get(rootNode), getSourceSection(rootNode).getSource()); - return PFactory.createCode(language, root.getCallTarget(), root.getSignature(), code); + return getOrCreateChildCode(code); } else { BytecodeCodeUnit code = (BytecodeCodeUnit) o; - PBytecodeRootNode bytecodeRootNode = PBytecodeRootNode.create(language, code, ((PBytecodeRootNode) rootNode).getLazySource(), rootNode.isInternal()); - return PFactory.createCode(language, bytecodeRootNode.getCallTarget(), bytecodeRootNode.getSignature(), code); + return getOrCreateChildCode(code); } } else if (o instanceof BigInteger) { return PFactory.createInt(language, (BigInteger) o); @@ -591,11 +611,6 @@ private static Object convertConstantToPythonSpace(RootNode rootNode, Object o) return o; } - @TruffleBoundary - private static SourceSection getSourceSection(RootNode rootNode) { - return rootNode.getSourceSection(); - } - public TruffleString[] getNames() { if (names == null) { names = extractNames(getRootNode()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameBuiltins.java index 69d8e9b095..b254e51251 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameBuiltins.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) 2014, Regents of the University of California * * All rights reserved. @@ -62,7 +62,6 @@ import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.OverflowException; import com.oracle.truffle.api.CompilerDirectives; -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.GenerateNodeFactory; @@ -253,11 +252,9 @@ public abstract static class GetCodeNode extends PythonBuiltinNode { public abstract PCode executeObject(VirtualFrame frame, PFrame self); @Specialization - static PCode get(PFrame self, - @Bind PythonLanguage language) { - RootCallTarget ct = self.getTarget(); - assert ct != null; - return PFactory.createCode(language, ct); + static Object get(PFrame self) { + PCode code = self.getCode(); + return code != null ? code : PNone.NONE; } @NeverDefault diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java index dc9d895240..530ca4895a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java @@ -45,6 +45,7 @@ import com.oracle.graal.python.builtins.objects.code.CodeNodes.GetCodeRootNode; import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.function.PArguments; +import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.nodes.bytecode.PBytecodeGeneratorRootNode; @@ -55,7 +56,6 @@ import com.oracle.graal.python.nodes.frame.ReadFrameNode; import com.oracle.graal.python.runtime.CallerFlags; import com.oracle.graal.python.runtime.PythonOptions; -import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.bytecode.BytecodeFrame; @@ -91,7 +91,8 @@ public final class PFrame extends PythonBuiltinObject { * {@link BytecodeNode} that was executed at the time when the BCI was captured. */ private Node location; - private RootCallTarget callTarget; + private PFunction function; + private PCode code; private int line = UNINITIALIZED_LINE; private int bci = -1; @@ -111,8 +112,6 @@ public final class PFrame extends PythonBuiltinObject { private boolean traceLine = true; - private PFrame.Reference backref = null; - /** * The last {@link CallerFlags} that were used the last time the frame was synced or passed down * to a callee. See {@link #needsRefresh(VirtualFrame, int)} for more details. @@ -207,10 +206,15 @@ public Reference getCallerInfo() { } } - public PFrame(PythonLanguage lang, Reference virtualFrameInfo, Node location, boolean hasCustomLocals) { + public PFrame(PythonLanguage lang, Reference virtualFrameInfo, Node location, Object functionOrCode, boolean hasCustomLocals) { super(PythonBuiltinClassType.PFrame, PythonBuiltinClassType.PFrame.getInstanceShape(lang)); this.virtualFrameInfo = virtualFrameInfo; this.location = location; + if (functionOrCode instanceof PFunction function) { + this.function = function; + } else if (functionOrCode instanceof PCode code) { + this.code = code; + } this.hasCustomLocals = hasCustomLocals; // Mark everything as current for now. MaterializeFrameNode will set lastCallerFlags to a // narrower value if needed @@ -222,6 +226,7 @@ public PFrame(PythonLanguage lang, @SuppressWarnings("unused") Object threadStat super(PythonBuiltinClassType.PFrame, PythonBuiltinClassType.PFrame.getInstanceShape(lang)); // TODO: frames: extract the information from the threadState object this.globals = globals; + this.code = code; this.location = GetCodeRootNode.executeUncached(code); Reference curFrameInfo = new Reference(location != null ? location.getRootNode() : null, null); this.virtualFrameInfo = curFrameInfo; @@ -383,14 +388,14 @@ public PythonObject getGlobals() { } public RootCallTarget getTarget() { - if (callTarget == null) { - if (location != null) { - callTarget = PythonUtils.getOrCreateCallTarget(location.getRootNode()); - } else if (getRef() != null && getRef().getRootNode() != null) { - callTarget = PythonUtils.getOrCreateCallTarget(getRef().getRootNode()); - } + return getCode().getRootCallTarget(); + } + + public PCode getCode() { + if (code == null && function != null) { + code = function.getCode(); } - return callTarget; + return code; } public void setGlobals(PythonObject globals) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.java index 2790c91638..9f8a92c895 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.java @@ -25,6 +25,7 @@ */ package com.oracle.graal.python.builtins.objects.function; +import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.frame.PFrame; import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.object.PythonObject; @@ -39,7 +40,7 @@ *
    *
  • {@code SPECIAL_ARGUMENT (Object)}
  • *
  • {@code INDEX_GLOBALS_ARGUMENT (PythonObject)}
  • - *
  • {@code INDEX_FUNCTION_OBJECT (PFunction)}
  • + *
  • {@code INDEX_FUNCTION_OR_CODE_OBJECT (PFunction)}
  • *
  • {@code INDEX_CALLER_FRAME_INFO (PFrame.Reference)}
  • *
  • {@code INDEX_CURRENT_FRAME_INFO (PFrame.Reference)}
  • *
  • {@code INDEX_CURRENT_EXCEPTION (PException)}
  • @@ -58,7 +59,7 @@ public final class PArguments { private static final int INDEX_SPECIAL_ARGUMENT = 0; private static final int INDEX_GLOBALS_ARGUMENT = 1; - private static final int INDEX_FUNCTION_OBJECT = 2; + private static final int INDEX_FUNCTION_OR_CODE_OBJECT = 2; private static final int INDEX_CALLER_FRAME_INFO = 3; private static final int INDEX_CURRENT_FRAME_INFO = 4; private static final int INDEX_CURRENT_EXCEPTION = 5; @@ -72,10 +73,11 @@ public static boolean isPythonFrame(Object[] frameArgs) { return frameArgs.length >= USER_ARGUMENTS_OFFSET && frameArgs[INDEX_CURRENT_FRAME_INFO] instanceof PFrame.Reference; } - public static Object[] withGlobals(PythonModule globals) { + public static Object[] withGlobals(PCode code, PythonModule globals) { CompilerAsserts.neverPartOfCompilation(); Object[] arguments = create(); setGlobals(arguments, globals.getDict()); + setCodeObject(arguments, code); return arguments; } @@ -192,12 +194,42 @@ public static void setExceptionUnchecked(Object[] arguments, Object exc) { arguments[INDEX_CURRENT_EXCEPTION] = exc; } + public static Object getFunctionOrCodeObject(Object[] arguments) { + return arguments[INDEX_FUNCTION_OR_CODE_OBJECT]; + } + + public static Object getFunctionOrCodeObject(Frame frame) { + return getFunctionOrCodeObject(frame.getArguments()); + } + public static PFunction getFunctionObject(Object[] arguments) { - return (PFunction) arguments[INDEX_FUNCTION_OBJECT]; + return (PFunction) arguments[INDEX_FUNCTION_OR_CODE_OBJECT]; + } + + public static PFunction getFunctionObject(Frame frame) { + return getFunctionObject(frame.getArguments()); + } + + public static PCode getCodeObject(Object[] arguments) { + Object functionOrCodeObject = getFunctionOrCodeObject(arguments); + if (functionOrCodeObject instanceof PFunction function) { + return function.getCode(); + } else if (functionOrCodeObject instanceof PCode code) { + return code; + } + return null; + } + + public static PCode getCodeObject(Frame frame) { + return getCodeObject(frame.getArguments()); } public static void setFunctionObject(Object[] arguments, PFunction function) { - arguments[INDEX_FUNCTION_OBJECT] = function; + arguments[INDEX_FUNCTION_OR_CODE_OBJECT] = function; + } + + public static void setCodeObject(Object[] arguments, PCode code) { + arguments[INDEX_FUNCTION_OR_CODE_OBJECT] = code; } public static void setArgument(Object[] arguments, int index, Object value) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java index 2dc74c6634..59400c4693 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java @@ -405,7 +405,7 @@ static Object sendThrow(VirtualFrame frame, PGenerator self, Object typ, Object } MaterializedFrame generatorFrame = self.getGeneratorFrame(); PFrame.Reference ref = new PFrame.Reference(rootNode, PFrame.Reference.EMPTY); - PFrame pFrame = MaterializeFrameNode.materializeGeneratorFrame(PythonLanguage.get(inliningTarget), location, generatorFrame, self.getGlobals(), ref); + PFrame pFrame = MaterializeFrameNode.materializeGeneratorFrame(PythonLanguage.get(inliningTarget), location, generatorFrame, self.getGeneratorFunction(), self.getGlobals(), ref); FrameInfo info = (FrameInfo) generatorFrame.getFrameDescriptor().getInfo(); pFrame.setLine(info.getFirstLineNumber()); Object existingTracebackObj = getTracebackNode.execute(inliningTarget, instance); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CoroutineBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CoroutineBuiltins.java index 98a8cd8bc5..e6ba012b69 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CoroutineBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CoroutineBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -62,8 +62,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @CoreFunctions(extendClasses = PythonBuiltinClassType.PCoroutine) @@ -80,10 +78,8 @@ protected List> getNodeFa @GenerateNodeFactory public abstract static class GetCode extends PythonUnaryBuiltinNode { @Specialization - static Object getCode(PGenerator self, - @Bind Node inliningTarget, - @Cached InlinedConditionProfile hasCodeProfile) { - return self.getOrCreateCode(inliningTarget, hasCodeProfile); + static Object getCode(PGenerator self) { + return self.getGeneratorFunction().getCode(); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java index b48d1fee65..807750f148 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java @@ -71,7 +71,6 @@ import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @CoreFunctions(extendClasses = PythonBuiltinClassType.PGenerator) @@ -160,10 +159,8 @@ static Object next(VirtualFrame frame, PGenerator self, @GenerateNodeFactory public abstract static class GetCodeNode extends PythonUnaryBuiltinNode { @Specialization - static Object getCode(PGenerator self, - @Bind Node inliningTarget, - @Cached InlinedConditionProfile hasCodeProfile) { - return self.getOrCreateCode(inliningTarget, hasCodeProfile); + static Object getCode(PGenerator self) { + return self.getGeneratorFunction().getCode(); } } @@ -207,7 +204,8 @@ static Object getFrame(VirtualFrame frame, PGenerator self, if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { BytecodeDSLFrameInfo info = (BytecodeDSLFrameInfo) generatorFrame.getFrameDescriptor().getInfo(); if (pyFrame == null) { - pyFrame = MaterializeFrameNode.materializeGeneratorFrame(PythonLanguage.get(readFrameNode), self.getBytecodeNode(), generatorFrame, self.getGlobals(), currentRef); + pyFrame = MaterializeFrameNode.materializeGeneratorFrame(PythonLanguage.get(readFrameNode), self.getBytecodeNode(), generatorFrame, self.getGeneratorFunction(), + self.getGlobals(), currentRef); } BytecodeLocation location = self.getCurrentLocation(); if (location != null) { @@ -221,7 +219,8 @@ static Object getFrame(VirtualFrame frame, PGenerator self, } else { BytecodeFrameInfo info = (BytecodeFrameInfo) generatorFrame.getFrameDescriptor().getInfo(); if (pyFrame == null) { - pyFrame = MaterializeFrameNode.materializeGeneratorFrame(PythonLanguage.get(readFrameNode), info.getRootNode(), generatorFrame, self.getGlobals(), currentRef); + pyFrame = MaterializeFrameNode.materializeGeneratorFrame(PythonLanguage.get(readFrameNode), info.getRootNode(), generatorFrame, self.getGeneratorFunction(), self.getGlobals(), + currentRef); } int bci = self.getBci(); if (bci >= 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java index 34ac4c604d..c1366dd488 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java @@ -42,7 +42,6 @@ import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLFrameInfo; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.runtime.PythonOptions; -import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.RootCallTarget; @@ -53,9 +52,7 @@ import com.oracle.truffle.api.bytecode.ContinuationRootNode; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.MaterializedFrame; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; public class PGenerator extends PythonBuiltinObject { @@ -280,6 +277,10 @@ public PythonObject getGlobals() { return globals; } + public PFunction getGeneratorFunction() { + return generatorFunction; + } + public static Object getSendValue(Object[] arguments) { return PArguments.getArgument(arguments, 1); } @@ -387,14 +388,6 @@ public final String toString() { return ""; } - public final PCode getOrCreateCode(Node inliningTarget, InlinedConditionProfile hasCodeProfile) { - if (hasCodeProfile.profile(inliningTarget, code == null)) { - RootCallTarget callTarget = getRootNode().getCallTarget(); - code = PFactory.createCode(PythonLanguage.get(inliningTarget), callTarget); - } - return code; - } - public final boolean isRunning() { return running; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java index c1d8b43ffc..f6a72b8127 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java @@ -102,7 +102,6 @@ import com.oracle.graal.python.lib.PyObjectRichCompareBool; import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnit; -import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnitAndRoot; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNodeGen; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNodeGen.Builder; @@ -4352,7 +4351,7 @@ private void emitMakeFunction(BytecodeDSLCodeUnit codeUnit, Object scopeKey, Str // Register these in the Python constants list. addConstant(codeUnit); - b.beginMakeFunction(functionName, qualifiedName, new BytecodeDSLCodeUnitAndRoot(codeUnit)); + b.beginMakeFunction(functionName, qualifiedName, codeUnit); if (defaultArgsLocal != null) { assert argsForDefaults == null; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java index d813f4c9f8..aeb8c1d999 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java @@ -56,12 +56,10 @@ import java.nio.charset.StandardCharsets; import com.oracle.graal.python.PythonFileDetector; -import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.exception.ExceptionNodes; -import com.oracle.graal.python.builtins.objects.frame.PFrame; import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.traceback.PTraceback; @@ -78,7 +76,6 @@ import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; -import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.OverflowException; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -220,11 +217,6 @@ public static TruffleString classNameNoDot(TruffleString name) { return (i > 0) ? name.substringUncached(i + 1, len - i - 1, TS_ENCODING, true) : name; } - private static PCode getCode(PythonLanguage language, TracebackBuiltins.GetTracebackFrameNode getTbFrameNode, PTraceback tb) { - final PFrame pFrame = getTbFrameNode.execute(null, tb); - return PFactory.createCode(language, pFrame.getTarget()); - } - protected static PTraceback getNextTb(Node inliningTarget, TracebackBuiltins.MaterializeTruffleStacktraceNode materializeStNode, PTraceback traceback) { materializeStNode.execute(inliningTarget, traceback); return traceback.getNext(); @@ -355,9 +347,8 @@ private static void printInternal(Node inliningTarget, TracebackBuiltins.GetTrac tb = getNextTb(inliningTarget, materializeStNode, tb); } EqualNode tstrEqNode = EqualNode.getUncached(); - PythonLanguage language = PythonLanguage.get(inliningTarget); while (tb != null) { - final PCode code = getCode(language, getTbFrameNode, tb); + final PCode code = getTbFrameNode.execute(null, tb).getCode(); if (lastFile == null || code.getFilename() == null || !tstrEqNode.execute(code.getFilename(), lastFile, TS_ENCODING) || lastLine == -1 || tb.getLineno() != lastLine || diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java index ceab1fb2f2..3228287c34 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java @@ -166,7 +166,6 @@ public abstract class ErrorMessages { public static final TruffleString CAN_ONLY_CONCAT_S_NOT_P_TO_S = tsLiteral("can only concatenate %s (not \"%p\") to %s"); public static final TruffleString CAN_ONLY_JOIN_ITERABLE = tsLiteral("can only join an iterable"); public static final TruffleString S_CANNOT_BE_NEGATIVE_INTEGER_D = tsLiteral("%s cannot be negative integer (%d)"); - public static final TruffleString S_CANNOT_HAVE_S = tsLiteral("%s cannot have %s"); public static final TruffleString S_EXPECTED_D_ARGUMENTS_GOT_D = tsLiteral("%s expected %d arguments, got %d"); public static final TruffleString CANNOT_CONVERT_DICT_UPDATE_SEQ = tsLiteral("cannot convert dictionary update sequence element #%d to a sequence"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/MakeFunctionNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/MakeFunctionNode.java index 47ebd89cad..0dee0e1405 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/MakeFunctionNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/MakeFunctionNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -45,40 +45,35 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.objects.cell.PCell; import com.oracle.graal.python.builtins.objects.code.PCode; +import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; -import com.oracle.graal.python.builtins.objects.function.Signature; import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.compiler.BytecodeCodeUnit; import com.oracle.graal.python.compiler.OpCodes; import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.attributes.WriteAttributeToPythonObjectNode; import com.oracle.graal.python.runtime.object.PFactory; -import com.oracle.graal.python.util.LazySource; import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; public abstract class MakeFunctionNode extends PNodeWithContext { - private final RootCallTarget callTarget; - private final BytecodeCodeUnit code; - private final Signature signature; + private final BytecodeCodeUnit codeUnit; @CompilationFinal private PCode cachedCode; private final Assumption codeStableAssumption = Truffle.getRuntime().createAssumption("code stable assumption"); public abstract int execute(VirtualFrame frame, Object globals, int initialStackTop, int flags); - public MakeFunctionNode(RootCallTarget callTarget, BytecodeCodeUnit code, Signature signature) { - this.callTarget = callTarget; - this.code = code; - this.signature = signature; + public MakeFunctionNode(BytecodeCodeUnit codeUnit) { + this.codeUnit = codeUnit; } @Specialization @@ -87,18 +82,18 @@ int makeFunction(VirtualFrame frame, Object globals, int initialStackTop, int fl @Cached WriteAttributeToPythonObjectNode writeAttrNode) { int stackTop = initialStackTop; - PCode codeObj = cachedCode; - if (codeObj == null) { + PCode code = cachedCode; + if (code == null) { + code = PArguments.getCodeObject(frame).getOrCreateChildCode(codeUnit); if (PythonLanguage.get(this).isSingleContext()) { CompilerDirectives.transferToInterpreterAndInvalidate(); /* * We cannot initialize the cached code in create, because that may be called * without langauge context when materializing nodes for instrumentation */ - cachedCode = codeObj = PFactory.createCode(language, callTarget, signature, code); + cachedCode = code; } else { // In multi-context mode we have to create the code for every execution - codeObj = PFactory.createCode(language, callTarget, signature, code); } } @@ -124,7 +119,7 @@ int makeFunction(VirtualFrame frame, Object globals, int initialStackTop, int fl frame.setObject(stackTop--, null); } - PFunction function = PFactory.createFunction(language, code.name, code.qualname, codeObj, (PythonObject) globals, defaults, kwdefaults, closure, codeStableAssumption); + PFunction function = PFactory.createFunction(language, codeUnit.name, codeUnit.qualname, code, (PythonObject) globals, defaults, kwdefaults, closure, codeStableAssumption); if (annotations != null) { writeAttrNode.execute(function, T___ANNOTATIONS__, annotations); @@ -134,19 +129,8 @@ int makeFunction(VirtualFrame frame, Object globals, int initialStackTop, int fl return stackTop; } - public static MakeFunctionNode create(PythonLanguage language, BytecodeCodeUnit code, LazySource lazySource, boolean internal) { - RootCallTarget callTarget; - PBytecodeRootNode bytecodeRootNode = PBytecodeRootNode.create(language, code, lazySource, internal); - if (code.isGeneratorOrCoroutine()) { - // TODO what should the frameDescriptor be? does it matter? - callTarget = new PBytecodeGeneratorFunctionRootNode(language, bytecodeRootNode.getFrameDescriptor(), bytecodeRootNode, code.name).getCallTarget(); - } else { - callTarget = bytecodeRootNode.getCallTarget(); - } - return MakeFunctionNodeGen.create(callTarget, code, bytecodeRootNode.getSignature()); - } - - public RootCallTarget getCallTarget() { - return callTarget; + @NeverDefault + public static MakeFunctionNode create(BytecodeCodeUnit codeUnit) { + return MakeFunctionNodeGen.create(codeUnit); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java index e86ab84f0c..9e0d32342d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java @@ -247,6 +247,7 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.HostCompilerDirectives.BytecodeInterpreterSwitch; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; +import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -667,6 +668,16 @@ public static PBytecodeRootNode create(PythonLanguage language, BytecodeCodeUnit return create(language, co, lazySource, internal, null); } + @TruffleBoundary + public static RootNode createMaybeGenerator(PythonLanguage language, BytecodeCodeUnit co, LazySource source, boolean internal) { + PBytecodeRootNode bytecodeRootNode = PBytecodeRootNode.create(language, co, source, internal); + if (co.isGeneratorOrCoroutine()) { + return new PBytecodeGeneratorFunctionRootNode(language, bytecodeRootNode.getFrameDescriptor(), bytecodeRootNode, co.name); + } else { + return bytecodeRootNode; + } + } + @TruffleBoundary public static PBytecodeRootNode create(PythonLanguage language, BytecodeCodeUnit co, LazySource lazySource, boolean internal, ParserCallbacksImpl parserCallbacks) { BytecodeFrameInfo frameInfo = new BytecodeFrameInfo(); @@ -895,7 +906,7 @@ private void doInsertChildNode(Node[] nodes, int nodeIndex, Node newNode) { } } - private PythonLanguage getLanguage() { + public PythonLanguage getLanguage() { return getLanguage(PythonLanguage.class); } @@ -2900,22 +2911,24 @@ private Object notifyEnter(VirtualFrame virtualFrame, InstrumentationSupport ins } private MakeFunctionNode insertMakeFunctionNode(Node[] localNodes, int beginBci, BytecodeCodeUnit codeUnit) { - return insertChildNode(localNodes, beginBci, MakeFunctionNodeGen.class, () -> MakeFunctionNode.create(getLanguage(PythonLanguage.class), codeUnit, lazySource, internal)); + return insertChildNode(localNodes, beginBci, MakeFunctionNodeGen.class, () -> MakeFunctionNode.create(codeUnit)); } public void materializeContainedFunctionsForInstrumentation(Set> materializedTags) { usingCachedNodes = true; - BytecodeCodeUnit.iterateBytecode(bytecode, (bci, op, oparg, followingArgs) -> { - if (op == OpCodes.MAKE_FUNCTION) { - BytecodeCodeUnit codeUnit = (BytecodeCodeUnit) consts[oparg]; - MakeFunctionNode makeFunctionNode = insertMakeFunctionNode(getChildNodes(), bci, codeUnit); - RootNode rootNode = makeFunctionNode.getCallTarget().getRootNode(); + PythonLanguage language = getLanguage(); + for (int i = 0; i < co.constants.length; i++) { + if (co.constants[i] instanceof BytecodeCodeUnit codeUnit) { + RootCallTarget callTarget = language.createCachedCallTarget( + l -> PBytecodeRootNode.createMaybeGenerator(language, codeUnit, lazySource, isInternal()), + codeUnit); + RootNode rootNode = callTarget.getRootNode(); if (rootNode instanceof PBytecodeGeneratorFunctionRootNode) { rootNode = ((PBytecodeGeneratorFunctionRootNode) rootNode).getBytecodeRootNode(); } ((PBytecodeRootNode) rootNode).instrumentationRoot.materializeInstrumentableNodes(materializedTags); } - }); + } } public Node createInstrumentationMaterializationForwarder() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/BytecodeDSLCodeUnitAndRoot.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/BytecodeDSLCodeUnitAndRoot.java deleted file mode 100644 index 04e8e0d0c6..0000000000 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/BytecodeDSLCodeUnitAndRoot.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2025, 2025, 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 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.graal.python.nodes.bytecode_dsl; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; - -import com.oracle.graal.python.runtime.PythonContext; -import com.oracle.truffle.api.CompilerDirectives; - -/** - * Wrapper around {@link BytecodeDSLCodeUnit} that can lazily initialize the corresponding root - * node. - *

    - * We cannot just use {@code @Cached} argument to cache the {@link PBytecodeDSLRootNode} created - * from the {@link BytecodeDSLCodeUnit}, because Truffle DSL permits races, and it could be - * initialized multiple times, which we must avoid to 1) not fill inline caches unnecessarily, 2) - * make use of the fact that comprehensions cannot change, so that we can invoke them using - * {@code DirectCallNode} without inline cache. - */ -public final class BytecodeDSLCodeUnitAndRoot { - private final BytecodeDSLCodeUnit codeUnit; - // updated via VarHandle - private PBytecodeDSLRootNode rootNode; - - public BytecodeDSLCodeUnitAndRoot(BytecodeDSLCodeUnit codeUnit) { - this.codeUnit = codeUnit; - } - - public BytecodeDSLCodeUnit getCodeUnit() { - return codeUnit; - } - - public PBytecodeDSLRootNode getRootNode(PBytecodeDSLRootNode outerRootNode) { - PBytecodeDSLRootNode existing = rootNode; - if (existing != null) { - return existing; - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - PBytecodeDSLRootNode created = codeUnit.createRootNode(PythonContext.get(outerRootNode), outerRootNode.getSource()); - PBytecodeDSLRootNode prev = (PBytecodeDSLRootNode) ROOT_HANDLE.compareAndExchangeRelease(this, null, created); - return prev != null ? prev : created; - } - - private static final VarHandle ROOT_HANDLE; - static { - try { - ROOT_HANDLE = MethodHandles.lookup().findVarHandle(BytecodeDSLCodeUnitAndRoot.class, "rootNode", PBytecodeDSLRootNode.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } -} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java index 610555aed2..a29efbebfb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java @@ -476,6 +476,7 @@ public static final class EnterCalleeContext { @Specialization public static void doEnter(VirtualFrame frame, @Bind PBytecodeDSLRootNode root) { + assert PArguments.getFunctionOrCodeObject(frame) != null; root.calleeContext.enter(frame, root); } } @@ -944,7 +945,7 @@ public int getFirstLineno() { return co.startLine; } - protected Source getSource() { + public Source getSource() { SourceSection section = getSourceSection(); if (section == null) { return PythonUtils.createFakeSource(); @@ -1461,41 +1462,43 @@ public static Object perform(VirtualFrame frame, LocalAccessor attributes, Objec } } - @Operation(storeBytecodeIndex = true) + @Operation(storeBytecodeIndex = true, forceCached = true) @ConstantOperand(type = TruffleString.class, name = "name") @ConstantOperand(type = TruffleString.class, name = "qualifiedName") - @ConstantOperand(type = BytecodeDSLCodeUnitAndRoot.class) + @ConstantOperand(type = BytecodeDSLCodeUnit.class) public static final class MakeFunction { - @Specialization(guards = "isSingleContext(rootNode)", excludeForUncached = true) + @Specialization(guards = "isSingleContext(rootNode)") public static Object functionSingleContext(VirtualFrame frame, TruffleString name, TruffleString qualifiedName, - BytecodeDSLCodeUnitAndRoot codeUnit, + BytecodeDSLCodeUnit codeUnit, Object[] defaults, Object[] kwDefaultsObject, Object closure, Object annotations, @Bind PBytecodeDSLRootNode rootNode, - @Cached("createCode(rootNode, codeUnit)") PCode cachedCode, + @Cached("getCode(frame, codeUnit)") PCode cachedCode, + @Shared @Cached("createCodeStableAssumption()") Assumption codeStableAssumption, @Shared @Cached DynamicObject.PutNode putNode) { - return createFunction(frame, name, qualifiedName, codeUnit.getCodeUnit().getDocstring(), - cachedCode, defaults, kwDefaultsObject, closure, annotations, rootNode, putNode); + return createFunction(frame, name, qualifiedName, codeUnit.getDocstring(), + cachedCode, defaults, kwDefaultsObject, closure, annotations, codeStableAssumption, rootNode, putNode); } @Specialization(replaces = "functionSingleContext") public static Object functionMultiContext(VirtualFrame frame, TruffleString name, TruffleString qualifiedName, - BytecodeDSLCodeUnitAndRoot codeUnit, + BytecodeDSLCodeUnit codeUnit, Object[] defaults, Object[] kwDefaultsObject, Object closure, Object annotations, @Bind PBytecodeDSLRootNode rootNode, + @Shared @Cached("createCodeStableAssumption()") Assumption codeStableAssumption, @Shared @Cached DynamicObject.PutNode putNode) { - PCode code = createCode(rootNode, codeUnit); - return createFunction(frame, name, qualifiedName, codeUnit.getCodeUnit().getDocstring(), - code, defaults, kwDefaultsObject, closure, annotations, rootNode, putNode); + PCode code = getCode(frame, codeUnit); + return createFunction(frame, name, qualifiedName, codeUnit.getDocstring(), + code, defaults, kwDefaultsObject, closure, annotations, codeStableAssumption, rootNode, putNode); } @Idempotent @@ -1504,26 +1507,28 @@ protected static boolean isSingleContext(Node node) { } @NeverDefault - protected static PCode createCode(PBytecodeDSLRootNode outerRootNode, BytecodeDSLCodeUnitAndRoot codeUnit) { - PBytecodeDSLRootNode rootNode = codeUnit.getRootNode(outerRootNode); - return PFactory.createCode( - PythonLanguage.get(outerRootNode), - rootNode.getCallTarget(), - rootNode.getSignature(), - codeUnit.getCodeUnit()); + static Assumption createCodeStableAssumption() { + return Truffle.getRuntime().createAssumption("code stable assumption"); + } + + @NeverDefault + protected static PCode getCode(VirtualFrame frame, BytecodeDSLCodeUnit codeUnit) { + PCode thisCode = PArguments.getCodeObject(frame); + return thisCode.getOrCreateChildCode(codeUnit); } protected static PFunction createFunction(VirtualFrame frame, TruffleString name, TruffleString qualifiedName, TruffleString doc, PCode code, Object[] defaults, Object[] kwDefaultsObject, Object closure, Object annotations, - PBytecodeDSLRootNode node, + Assumption codeStableAssumption, PBytecodeDSLRootNode node, DynamicObject.PutNode putNode) { PKeyword[] kwDefaults = new PKeyword[kwDefaultsObject.length]; // Note: kwDefaultsObject should be a result of operation MakeKeywords, which produces // PKeyword[] PythonUtils.arraycopy(kwDefaultsObject, 0, kwDefaults, 0, kwDefaults.length); - PFunction function = PFactory.createFunction(PythonLanguage.get(node), name, qualifiedName, code, PArguments.getGlobals(frame), defaults, kwDefaults, (PCell[]) closure); + PFunction function = PFactory.createFunction(PythonLanguage.get(node), name, qualifiedName, code, PArguments.getGlobals(frame), defaults, kwDefaults, (PCell[]) closure, + codeStableAssumption); if (annotations != null) { putNode.execute(function, T___ANNOTATIONS__, annotations); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java index 216a0c2602..8a86eae397 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java @@ -43,11 +43,13 @@ import static com.oracle.graal.python.builtins.modules.io.IONodes.T_WRITE; import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemExit; +import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.exception.ExceptionNodes; import com.oracle.graal.python.builtins.objects.exception.PBaseException; @@ -86,6 +88,7 @@ import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.api.strings.TruffleString; public final class TopLevelExceptionHandler extends RootNode { private final RootCallTarget innerCallTarget; @@ -317,6 +320,8 @@ private Object run(VirtualFrame frame) { PythonContext pythonContext = getContext(); PythonModule mainModule = null; PythonLanguage language = getPythonLanguage(); + PCode code = PFactory.createCode(language, innerCallTarget, PythonUtils.internString(TruffleString.fromJavaStringUncached(source.getName(), TS_ENCODING))); + PArguments.setCodeObject(arguments, code); if (source.isInternal()) { // internal sources are not run in the main module PArguments.setGlobals(arguments, PFactory.createDict(language)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/MaterializeFrameNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/MaterializeFrameNode.java index e57bb64b11..a48124ca1d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/MaterializeFrameNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/MaterializeFrameNode.java @@ -45,6 +45,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.objects.frame.PFrame; import com.oracle.graal.python.builtins.objects.function.PArguments; +import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.generator.PGenerator; import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.nodes.PRootNode; @@ -173,7 +174,7 @@ public final PFrame execute(Node location, boolean markAsEscaped, boolean forceS static PFrame freshPFrameCachedFD(Node location, boolean markAsEscaped, boolean forceSync, Frame frameToMaterialize, @Bind PythonLanguage language, @Shared("syncValuesNode") @Cached SyncFrameValuesNode syncValuesNode) { - PFrame escapedFrame = PFactory.createPFrame(language, PArguments.getCurrentFrameInfo(frameToMaterialize), location, false); + PFrame escapedFrame = PFactory.createPFrame(language, PArguments.getCurrentFrameInfo(frameToMaterialize), location, PArguments.getFunctionOrCodeObject(frameToMaterialize), false); return doEscapeFrame(frameToMaterialize, escapedFrame, markAsEscaped, forceSync, location, syncValuesNode); } @@ -181,7 +182,7 @@ static PFrame freshPFrameCachedFD(Node location, boolean markAsEscaped, boolean static PFrame freshPFrameCustomLocals(Node location, boolean markAsEscaped, @SuppressWarnings("unused") boolean forceSync, Frame frameToMaterialize, @Bind PythonLanguage language) { - PFrame escapedFrame = PFactory.createPFrame(language, PArguments.getCurrentFrameInfo(frameToMaterialize), location, true); + PFrame escapedFrame = PFactory.createPFrame(language, PArguments.getCurrentFrameInfo(frameToMaterialize), location, PArguments.getFunctionOrCodeObject(frameToMaterialize), true); escapedFrame.setLocalsDict(PArguments.getSpecialArgument(frameToMaterialize)); return doEscapeFrame(frameToMaterialize, escapedFrame, markAsEscaped, false, location, null); } @@ -190,7 +191,7 @@ static PFrame freshPFrameCustomLocals(Node location, boolean markAsEscaped, @Sup static PFrame freshPFrameForGenerator(Node location, @SuppressWarnings("unused") boolean markAsEscaped, @SuppressWarnings("unused") boolean forceSync, Frame frameToMaterialize) { MaterializedFrame generatorFrame = PGenerator.getGeneratorFrame(frameToMaterialize); PFrame.Reference frameRef = PArguments.getCurrentFrameInfo(frameToMaterialize); - PFrame escapedFrame = materializeGeneratorFrame(location, generatorFrame, PArguments.getGlobals(frameToMaterialize), frameRef); + PFrame escapedFrame = materializeGeneratorFrame(location, generatorFrame, PArguments.getFunctionObject(frameToMaterialize), PArguments.getGlobals(frameToMaterialize), frameRef); return doEscapeFrame(frameToMaterialize, escapedFrame, markAsEscaped, false, location, null); } @@ -209,12 +210,13 @@ static PFrame alreadyEscapedFrame(@SuppressWarnings("unused") Node location, boo return pyFrame; } - public static PFrame materializeGeneratorFrame(Node location, MaterializedFrame generatorFrame, PythonObject globals, PFrame.Reference frameRef) { - return materializeGeneratorFrame(PythonLanguage.get(location), location, generatorFrame, globals, frameRef); + public static PFrame materializeGeneratorFrame(Node location, MaterializedFrame generatorFrame, PFunction generatorFunction, PythonObject globals, PFrame.Reference frameRef) { + return materializeGeneratorFrame(PythonLanguage.get(location), location, generatorFrame, generatorFunction, globals, frameRef); } - public static PFrame materializeGeneratorFrame(PythonLanguage language, Node location, MaterializedFrame generatorFrame, PythonObject globals, PFrame.Reference frameRef) { - PFrame escapedFrame = PFactory.createPFrame(language, frameRef, location, false); + public static PFrame materializeGeneratorFrame(PythonLanguage language, Node location, MaterializedFrame generatorFrame, PFunction generatorFunction, PythonObject globals, + PFrame.Reference frameRef) { + PFrame escapedFrame = PFactory.createPFrame(language, frameRef, location, generatorFunction, false); if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { BytecodeNode bytecodeNode = BytecodeNode.get(location); assert bytecodeNode != null : location; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/GetInteropBehaviorValueNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/GetInteropBehaviorValueNode.java index efa8715cf0..38247c171f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/GetInteropBehaviorValueNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/GetInteropBehaviorValueNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -46,8 +46,10 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PythonAbstractObject; +import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.call.CallDispatchers; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaBooleanNode; @@ -60,7 +62,6 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.util.PythonUtils; -import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateInline; @@ -68,8 +69,6 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; @GenerateUncached @@ -186,16 +185,16 @@ static Object getValueConstantBoolean(@SuppressWarnings("unused") Node inliningT @Specialization(guards = {"!behavior.isConstant(method)", "method.checkArity(extraArguments)"}) static Object getValue(Node inliningTarget, InteropBehavior behavior, InteropBehaviorMethod method, PythonAbstractObject receiver, Object[] extraArguments, - @Cached SimpleInvokeNodeDispatch invokeNode, + @Cached CallDispatchers.FunctionCachedInvokeNode invokeNode, @Cached ConvertJavaStringArguments convertArgs, @Cached IsBuiltinObjectProfile unsupportedMessageProfile, @Cached GilNode gil) throws UnsupportedMessageException { assert behavior.isDefined(method) : "interop behavior method is not defined!"; - CallTarget callTarget = behavior.getCallTarget(method); + PFunction function = behavior.getFunction(method); Object[] pArguments = behavior.createArguments(method, receiver, convertArgs.execute(inliningTarget, extraArguments)); boolean mustRelease = gil.acquire(); try { - return invokeNode.execute(inliningTarget, callTarget, pArguments); + return invokeNode.execute(null, inliningTarget, function, pArguments); } catch (PException pe) { pe.expect(inliningTarget, PythonBuiltinClassType.UnsupportedMessage, unsupportedMessageProfile); throw UnsupportedMessageException.create(); @@ -221,25 +220,6 @@ public static GetInteropBehaviorValueNode getUncached() { return GetInteropBehaviorValueNodeGen.getUncached(); } - @GenerateUncached - @GenerateInline - abstract static class SimpleInvokeNodeDispatch extends Node { - public abstract Object execute(Node inliningTarget, CallTarget callTarget, Object[] arguments); - - @Specialization(guards = {"cachedCallTarget == callTarget"}, limit = "3") - static Object doDirectCall(CallTarget callTarget, Object[] arguments, - @Cached("callTarget") CallTarget cachedCallTarget, - @Cached("create(callTarget)") DirectCallNode directCallNode) { - return directCallNode.call(arguments); - } - - @Specialization(replaces = "doDirectCall") - static Object doIndirectCall(CallTarget callTarget, Object[] arguments, - @Cached IndirectCallNode indirectCallNode) { - return indirectCallNode.call(callTarget, arguments); - } - } - @GenerateUncached @GenerateInline abstract static class ConvertJavaStringArguments extends Node { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/InteropBehavior.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/InteropBehavior.java index 6bf73f17b5..a23513646a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/InteropBehavior.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/interop/InteropBehavior.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -47,9 +47,7 @@ import com.oracle.graal.python.builtins.objects.PythonAbstractObject; import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PFunction; -import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.util.PythonUtils; -import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.TruffleLogger; @@ -60,7 +58,7 @@ public class InteropBehavior { private static final TruffleLogger LOGGER = PythonLanguage.getLogger(LOGGER_INTEROP_BEHAVIOR_NAME); @ValueType - private record InteropBehaviorMethodRecord(CallTarget callTarget, PythonObject globals, boolean constant) { + private record InteropBehaviorMethodRecord(PFunction function, boolean constant) { } private final PythonAbstractObject receiver; @@ -72,14 +70,14 @@ public InteropBehavior(PythonAbstractObject receiver) { } public void defineBehavior(InteropBehaviorMethod method, PFunction function) { - records[method.ordinal()] = new InteropBehaviorMethodRecord(function.getCode().getRootCallTarget(), function.getGlobals(), false); + records[method.ordinal()] = new InteropBehaviorMethodRecord(function, false); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(PythonUtils.formatJString("register %s.%s interop extension as function", receiver, method.name)); } } public void defineBehavior(InteropBehaviorMethod method, boolean constant) { - records[method.ordinal()] = new InteropBehaviorMethodRecord(null, null, constant); + records[method.ordinal()] = new InteropBehaviorMethodRecord(null, constant); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(PythonUtils.formatJString("register %s.%s interop extension as constant (%s)", receiver, method.name, constant)); } @@ -89,19 +87,14 @@ public boolean isDefined(InteropBehaviorMethod method) { return records[method.ordinal()] != null; } - public CallTarget getCallTarget(InteropBehaviorMethod method) { + public PFunction getFunction(InteropBehaviorMethod method) { assert isDefined(method) : "interop behavior method not defined"; - return records[method.ordinal()].callTarget; - } - - public PythonObject getGlobals(InteropBehaviorMethod method) { - assert isDefined(method) : "interop behavior method not defined"; - return records[method.ordinal()].globals; + return records[method.ordinal()].function; } public boolean isConstant(InteropBehaviorMethod method) { assert isDefined(method) : "interop behavior method not defined"; - return records[method.ordinal()].callTarget == null; + return records[method.ordinal()].function == null; } public boolean getConstantValue(InteropBehaviorMethod method) { @@ -112,7 +105,6 @@ public boolean getConstantValue(InteropBehaviorMethod method) { public Object[] createArguments(InteropBehaviorMethod method, PythonAbstractObject receiver, Object[] extraArguments) { assert method.checkArity(extraArguments); Object[] pArguments = PArguments.create(1 + (method.takesVarArgs ? 1 : method.extraArguments)); - PArguments.setGlobals(pArguments, getGlobals(method)); PArguments.setArgument(pArguments, 0, receiver); if (method.takesVarArgs) { PArguments.setArgument(pArguments, 1, extraArguments); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/IsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/IsNode.java index 792315d853..9bb8643a2f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/IsNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/IsNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -43,22 +43,16 @@ import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; -import com.oracle.graal.python.builtins.objects.code.CodeNodes; -import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.builtins.objects.str.PString; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.nodes.PGuards; -import com.oracle.graal.python.nodes.bytecode.PBytecodeGeneratorFunctionRootNode; -import com.oracle.graal.python.nodes.bytecode.PBytecodeRootNode; -import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.expression.BinaryOp; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsAnyBuiltinObjectProfile; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.util.OverflowException; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; -import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.bytecode.OperationProxy; import com.oracle.truffle.api.bytecode.StoreBytecodeIndex; import com.oracle.truffle.api.dsl.Bind; @@ -75,7 +69,6 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; @ImportStatic(PythonOptions.class) @GenerateUncached @@ -222,44 +215,6 @@ public static boolean doNative(PythonAbstractNativeObject left, PythonAbstractNa return interop.isIdentical(left, right, interop); } - // code - @Specialization - @InliningCutoff - public static boolean doCode(PCode left, PCode right, - @Bind Node inliningTarget, - @Cached CodeNodes.GetCodeCallTargetNode getCt) { - // Special case for code objects: Frames create them on-demand even if they refer to the - // same function. So we need to compare the root nodes. - if (left != right) { - RootCallTarget leftCt = getCt.execute(inliningTarget, left); - RootCallTarget rightCt = getCt.execute(inliningTarget, right); - if (leftCt != null && rightCt != null) { - RootNode leftRootNode = leftCt.getRootNode(); - RootNode rightRootNode = rightCt.getRootNode(); - if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { - if (leftRootNode instanceof PBytecodeDSLRootNode l && rightRootNode instanceof PBytecodeDSLRootNode r) { - return l.getCodeUnit() == r.getCodeUnit(); - } - } else { - if (leftRootNode instanceof PBytecodeGeneratorFunctionRootNode l) { - leftRootNode = l.getBytecodeRootNode(); - } - if (rightRootNode instanceof PBytecodeGeneratorFunctionRootNode r) { - rightRootNode = r.getBytecodeRootNode(); - } - - if (leftRootNode instanceof PBytecodeRootNode l && rightRootNode instanceof PBytecodeRootNode r) { - return l.getCodeUnit() == r.getCodeUnit(); - } - } - return leftRootNode == rightRootNode; - } else { - return false; - } - } - return true; - } - public static boolean someIsNone(Object left, Object right) { return PGuards.isPNone(left) || PGuards.isPNone(right); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index 1b91e7d4d7..36a1f94d10 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -137,7 +137,6 @@ import com.oracle.graal.python.builtins.objects.thread.PLock; import com.oracle.graal.python.builtins.objects.thread.PThread; import com.oracle.graal.python.builtins.objects.tuple.PTuple; -import com.oracle.graal.python.compiler.CodeUnit; import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectGetAttr; import com.oracle.graal.python.lib.PyObjectIsTrueNode; @@ -764,32 +763,6 @@ public Thread getOwner() { @CompilationFinal(dimensions = 1) private Object[] optionValues; - /* - * These maps are used to ensure that each "deserialization" of code in the parser gets a - * different instance (inside one context - ASTs can still be shared between contexts). - * Deserializing the same code multiple times is an infrequent case, but Python assumes that - * these code instances don't share attributes like the associated filename. - * - * Each time a specific filename is passed to deserialization in the same context, it gets a new - * id. The filename is stored in a weak hash map, because the code itself is a - * context-independent object. - */ - private final WeakHashMap codeFilename = new WeakHashMap<>(); - - /* - * These maps are used to ensure that each "deserialization" of code in the parser gets a - * different instance (inside one context - ASTs can still be shared between contexts). - * Deserializing the same code multiple times is an infrequent case, but Python assumes that - * these code instances don't share attributes like the associated filename. - * - * Each time a specific filename is passed to deserialization in the same context, it gets a new - * id. The filename is stored in a weak hash map, because the code itself is a - * context-independent object. - */ - private final WeakHashMap codeUnitFilename = new WeakHashMap<>(); - - private final ConcurrentHashMap deserializationId = new ConcurrentHashMap<>(); - @CompilationFinal private long perfCounterStart = System.nanoTime(); public static final String CHILD_CONTEXT_DATA = "childContextData"; @@ -2646,28 +2619,6 @@ public boolean isFinalizing() { return finalizing; } - public void setCodeFilename(CallTarget callTarget, TruffleString filename) { - assert PythonUtils.isInterned(filename); - codeFilename.put(callTarget, filename); - } - - public TruffleString getCodeFilename(CallTarget callTarget) { - return codeFilename.get(callTarget); - } - - public void setCodeUnitFilename(CodeUnit co, TruffleString filename) { - assert PythonUtils.isInterned(filename); - codeUnitFilename.put(co, filename); - } - - public TruffleString getCodeUnitFilename(CodeUnit co) { - return codeUnitFilename.get(co); - } - - public long getDeserializationId(TruffleString fileName) { - return deserializationId.computeIfAbsent(fileName, f -> new AtomicLong()).incrementAndGet(); - } - public void ensureNFILanguage(Node nodeForRaise, String optionName, String optionValue) { if (!env.getInternalLanguages().containsKey(J_NFI_LANGUAGE)) { throw PRaiseNode.raiseStatic(nodeForRaise, PythonBuiltinClassType.SystemError, ErrorMessages.NFI_NOT_AVAILABLE, optionName, optionValue); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java index 107e1596f4..b3ca58c273 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.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. @@ -508,11 +508,6 @@ public static PFunction createFunction(PythonLanguage language, TruffleString na return new PFunction(language, name, name, code, globals, closure); } - public static PFunction createFunction(PythonLanguage language, TruffleString name, TruffleString qualname, PCode code, PythonObject globals, Object[] defaultValues, PKeyword[] kwDefaultValues, - PCell[] closure) { - return new PFunction(language, name, qualname, code, globals, defaultValues, kwDefaultValues, closure); - } - public static PFunction createFunction(PythonLanguage language, TruffleString name, PCode code, PythonObject globals, Object[] defaultValues, PKeyword[] kwDefaultValues, PCell[] closure) { return new PFunction(language, name, name, code, globals, defaultValues, kwDefaultValues, closure); } @@ -857,8 +852,8 @@ public static PCell createCell(Assumption effectivelyFinal) { * Frames, traces and exceptions */ - public static PFrame createPFrame(PythonLanguage language, PFrame.Reference frameInfo, Node location, boolean hasCustomLocals) { - return new PFrame(language, frameInfo, location, hasCustomLocals); + public static PFrame createPFrame(PythonLanguage language, PFrame.Reference frameInfo, Node location, Object functionOrCode, boolean hasCustomLocals) { + return new PFrame(language, frameInfo, location, functionOrCode, hasCustomLocals); } public static PFrame createPFrame(PythonLanguage language, Object threadState, PCode code, PythonObject globals, Object localsDict) { @@ -1084,16 +1079,20 @@ public static PCode createCode(PythonLanguage language, RootCallTarget ct) { return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), ct); } + public static PCode createCode(PythonLanguage language, RootCallTarget ct, TruffleString filename) { + return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), ct, filename); + } + public static PCode createCode(PythonLanguage language, RootCallTarget ct, int flags, int firstlineno, byte[] linetable, TruffleString filename) { return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), ct, flags, firstlineno, linetable, filename); } - public static PCode createCode(PythonLanguage language, RootCallTarget callTarget, Signature signature, BytecodeCodeUnit codeUnit) { - return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), callTarget, signature, codeUnit); + public static PCode createCode(PythonLanguage language, RootCallTarget callTarget, Signature signature, BytecodeCodeUnit codeUnit, TruffleString filename) { + return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), callTarget, signature, codeUnit, filename); } - public static PCode createCode(PythonLanguage language, RootCallTarget callTarget, Signature signature, BytecodeDSLCodeUnit codeUnit) { - return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), callTarget, signature, codeUnit); + public static PCode createCode(PythonLanguage language, RootCallTarget callTarget, Signature signature, BytecodeDSLCodeUnit codeUnit, TruffleString filename) { + return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), callTarget, signature, codeUnit, filename); } public static PCode createCode(PythonLanguage language, RootCallTarget callTarget, Signature signature, int nlocals,