From 5554362afd5911731e09e0d33665ee825941c163 Mon Sep 17 00:00:00 2001 From: stepan Date: Tue, 29 Sep 2026 22:46:33 +0200 Subject: [PATCH 001/129] Report loop count wherever the count can be derived in O(1) and without any virtual or boundary call and without additional code in the loop body (cherry picked from commit dae499f897426a7d866dd04475612a41d7a3adae) --- .../modules/BinasciiModuleBuiltins.java | 8 +- .../builtins/modules/BuiltinFunctions.java | 1 + .../modules/CodecsModuleBuiltins.java | 7 +- .../modules/ItertoolsModuleBuiltins.java | 4 +- .../modules/JArrayModuleBuiltins.java | 4 +- .../builtins/modules/MathModuleBuiltins.java | 7 + .../builtins/modules/PosixModuleBuiltins.java | 3 + .../PosixSubprocessModuleBuiltins.java | 5 + .../builtins/modules/PwdModuleBuiltins.java | 2 + .../modules/SelectModuleBuiltins.java | 11 +- .../modules/SocketModuleBuiltins.java | 3 + .../modules/StringModuleBuiltins.java | 9 +- .../builtins/modules/SysModuleBuiltins.java | 2 + .../modules/TypingModuleBuiltins.java | 8 +- .../modules/WarningsModuleBuiltins.java | 2 + .../builtins/modules/ast/AstBuiltins.java | 5 + .../modules/cext/PythonCextDictBuiltins.java | 4 + .../cext/PythonCextObjectBuiltins.java | 4 + .../modules/cext/PythonCextTypeBuiltins.java | 4 + .../cext/PythonCextUnicodeBuiltins.java | 4 + .../MultibyteStreamWriterBuiltins.java | 2 + .../modules/codecs/ErrorHandlers.java | 9 ++ .../functools/LruCacheWrapperBuiltins.java | 4 +- .../modules/functools/PartialBuiltins.java | 8 +- .../builtins/modules/io/BytesIOBuiltins.java | 3 + .../builtins/modules/io/IOBaseBuiltins.java | 4 +- .../builtins/modules/pickle/PUnpickler.java | 2 + .../builtins/modules/pickle/PicklerNodes.java | 12 +- .../builtins/modules/re/MatchBuiltins.java | 6 + .../builtins/modules/re/PatternBuiltins.java | 3 + .../modules/re/SREModuleBuiltins.java | 2 + .../modules/zlib/ZLibModuleBuiltins.java | 5 +- .../objects/PythonAbstractObject.java | 11 +- .../builtins/objects/array/ArrayBuiltins.java | 76 +++++++--- .../buffer/ForeignBufferAcquireExports.java | 2 + .../buffer/PythonBufferAccessLibrary.java | 4 + .../objects/bytes/ByteArrayBuiltins.java | 4 +- .../builtins/objects/bytes/BytesBuiltins.java | 4 +- .../objects/bytes/BytesCommonBuiltins.java | 49 ++++++- .../builtins/objects/bytes/BytesNodes.java | 28 ++-- .../cext/capi/ExternalFunctionNodes.java | 13 +- .../capi/transitions/CApiTransitions.java | 7 +- .../objects/common/DynamicObjectStorage.java | 3 + .../objects/common/HashingStorageNodes.java | 5 +- .../objects/common/KeywordsStorage.java | 6 +- .../objects/common/SequenceStorageNodes.java | 136 ++++++++++++------ .../builtins/objects/common/SortNodes.java | 4 + .../builtins/objects/deque/DequeBuiltins.java | 4 + .../objects/deque/DequeIterBuiltins.java | 12 +- .../objects/deque/DequeRevIterBuiltins.java | 12 +- .../exception/BaseExceptionGroupBuiltins.java | 2 + .../exception/PBaseExceptionGroup.java | 2 +- .../objects/floats/FloatBuiltins.java | 3 + .../foreign/ForeignObjectBuiltins.java | 2 + .../frame/FrameLocalsProxyBuiltins.java | 8 +- .../objects/iterator/IteratorNodes.java | 2 + .../objects/iterator/ZipBuiltins.java | 23 +-- .../objects/itertools/BatchedBuiltins.java | 41 +++--- .../itertools/CombinationsBuiltins.java | 6 + .../itertools/PermutationsBuiltins.java | 47 +++--- .../objects/itertools/ProductBuiltins.java | 49 ++++--- .../objects/itertools/ZipLongestBuiltins.java | 45 +++--- .../builtins/objects/list/ListBuiltins.java | 2 + .../builtins/objects/map/MapBuiltins.java | 17 ++- .../memoryview/MemoryViewBuiltins.java | 3 + .../objects/memoryview/MemoryViewNodes.java | 5 +- .../builtins/objects/mmap/MMapBuiltins.java | 2 + .../namespace/SimpleNamespaceBuiltins.java | 9 +- .../builtins/objects/object/ObjectNodes.java | 3 + .../ordereddict/OrderedDictBuiltins.java | 3 + .../builtins/objects/range/RangeBuiltins.java | 5 +- .../builtins/objects/select/PollBuiltins.java | 3 + .../builtins/objects/set/BaseSetBuiltins.java | 2 + .../objects/set/FrozenSetBuiltins.java | 5 + .../builtins/objects/set/SetBuiltins.java | 9 ++ .../builtins/objects/socket/SocketNodes.java | 11 +- .../objects/ssl/SSLContextBuiltins.java | 13 +- .../builtins/objects/str/StringBuiltins.java | 17 ++- .../builtins/objects/str/StringNodes.java | 28 ++-- .../builtins/objects/str/StringUtils.java | 2 + .../objects/struct/StructBuiltins.java | 3 + .../InstantiableStructSequenceBuiltins.java | 2 + .../objects/tuple/StructSequenceBuiltins.java | 5 + .../builtins/objects/tuple/TupleBuiltins.java | 4 + .../builtins/objects/type/TypeBuiltins.java | 6 +- .../builtins/objects/type/TypeNodes.java | 21 ++- .../objects/types/UnionTypeBuiltins.java | 4 + .../oracle/graal/python/lib/PyDictMerge.java | 3 + .../lib/PyObjectRecursiveBinaryCheckNode.java | 8 +- .../nodes/argument/CreateArgumentsNode.java | 5 + .../ExecutePositionalStarargsNode.java | 3 + .../attributes/LookupAttributeInMRONode.java | 2 + .../python/nodes/bytecode/ImportStarNode.java | 14 +- .../bytecode_dsl/PBytecodeDSLRootNode.java | 2 + .../bytecode_dsl/SequenceFromArrayNode.java | 6 +- .../classes/AbstractObjectIsSubclassNode.java | 16 ++- .../python/nodes/classes/IsSubtypeNode.java | 8 +- .../EncapsulateExceptionGroupNode.java | 2 + .../nodes/exception/ExceptMatchNode.java | 3 + .../HandleExceptionsInHandlerNode.java | 5 +- .../nodes/frame/GetFrameLocalsNode.java | 2 + .../nodes/statement/AbstractImportNode.java | 2 + .../python/runtime/NativePosixSupport.java | 52 ++++--- .../sequence/storage/BoolSequenceStorage.java | 7 +- .../sequence/storage/ByteSequenceStorage.java | 5 +- .../storage/DoubleSequenceStorage.java | 7 +- .../storage/ForeignSequenceStorage.java | 4 +- .../sequence/storage/IntSequenceStorage.java | 7 +- .../sequence/storage/LongSequenceStorage.java | 7 +- .../storage/SequenceStorageFactory.java | 68 +++++---- .../oracle/graal/python/util/PythonUtils.java | 8 +- 111 files changed, 875 insertions(+), 322 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java index aa7a0cec47..561fa5222b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -409,10 +409,11 @@ abstract static class Crc32Node extends PythonBinaryClinicBuiltinNode { @Specialization(limit = "3") static long b2a(VirtualFrame frame, Object buffer, long crc, + @Bind Node inliningTarget, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib) { try { - return crc32((int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); + return crc32(inliningTarget, (int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); } finally { bufferLib.release(buffer, frame, callData); } @@ -432,10 +433,11 @@ abstract static class CrcHqxNode extends PythonBinaryClinicBuiltinNode { @Specialization(limit = "3") static long b2a(VirtualFrame frame, Object buffer, long crc, + @Bind Node inliningTarget, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib) { try { - return crcHqx((int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); + return crcHqx(inliningTarget, (int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); } finally { bufferLib.release(buffer, frame, callData); } 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 51ac7a8a55..ae404df180 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 @@ -1609,6 +1609,7 @@ static PNone printAllGiven(VirtualFrame frame, Object[] values, TruffleString se callWrite.execute(frame, writeMethod, strNode.execute(frame, inliningTarget, values[i])); callWrite.execute(frame, writeMethod, sep); } + LoopNode.reportLoopCount(inliningTarget, values.length == 0 ? 0 : values.length - 1); if (lastValue >= 0) { callWrite.execute(frame, writeMethod, strNode.execute(frame, inliningTarget, values[lastValue])); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java index 2dabf1adad..188e65f357 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java @@ -150,6 +150,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -779,8 +780,9 @@ static PTuple lookup(VirtualFrame frame, Node inliningTarget, TruffleString enco } } else { Object[] searchPaths = getSearchPaths(context); - for (Object func : searchPaths) { - Object obj = callNode.executeObject(frame, func, normalizedEncoding); + int i = 0; + for (; i < searchPaths.length; i++) { + Object obj = callNode.executeObject(frame, searchPaths[i], normalizedEncoding); if (obj != PNone.NONE) { if (isTupleProfile.profile(inliningTarget, !isTupleInstanceCheck(frame, inliningTarget, obj, 4, typeCheck, sizeNode))) { throw raiseNode.raise(inliningTarget, TypeError, CODEC_SEARCH_MUST_RETURN_4); @@ -789,6 +791,7 @@ static PTuple lookup(VirtualFrame frame, Node inliningTarget, TruffleString enco break; } } + LoopNode.reportLoopCount(inliningTarget, i); } if (result != null) { putSearchPath(context, normalizedEncoding, result); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.java index 8650f46bf0..3ab1107790 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.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. @@ -57,6 +57,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -159,6 +160,7 @@ static Object tee(VirtualFrame frame, Object iterable, int n, for (int i = 1; i < n; i++) { tupleObjs[i] = TeeBuiltins.CopyNode.copy(to, language); } + LoopNode.reportLoopCount(inliningTarget, n - 1); return PFactory.createTuple(language, tupleObjs); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java index 07dad36ccb..8d9a97fb34 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -84,6 +84,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(defineModule = "jarray") @@ -227,6 +228,7 @@ static Object fromSequence(PSequence sequence, Object type, throw CompilerDirectives.shouldNotReachHere("failed to set array item"); } } + LoopNode.reportLoopCount(inliningTarget, length); return array; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java index a5ee509dec..029f6ac3cf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java @@ -954,6 +954,7 @@ public abstract static class GcdNode extends PythonVarargsBuiltinNode { @Specialization(guards = {"args.length > 1", "keywords.length == 0"}) public static Object gcd(VirtualFrame frame, @SuppressWarnings("unused") Object self, Object[] args, @SuppressWarnings("unused") PKeyword[] keywords, + @Bind Node inliningTarget, @Cached Gcd2Node gdcNode, @Cached LoopConditionProfile profile) { Object res = args[0]; @@ -961,6 +962,7 @@ public static Object gcd(VirtualFrame frame, @SuppressWarnings("unused") Object for (int i = 1; profile.inject(i < args.length); i++) { res = gdcNode.execute(frame, res, args[i]); } + LoopNode.reportLoopCount(inliningTarget, args.length - 1); return res; } @@ -1116,6 +1118,7 @@ static Object gcd(VirtualFrame frame, @SuppressWarnings("unused") Object self, O Object m = mulNode.execute(frame, f, b); a = absNode.execute(frame, m); } + LoopNode.reportLoopCount(inliningTarget, args.length - 1); return a; } @@ -2342,6 +2345,7 @@ public double hypot2(VirtualFrame frame, @SuppressWarnings("unused") Object self } coordinates[i] = x; } + LoopNode.reportLoopCount(inliningTarget, arguments.length); if (Double.isInfinite(max)) { return max; } @@ -2364,6 +2368,7 @@ public double hypot2(VirtualFrame frame, @SuppressWarnings("unused") Object self csum += x; frac += (oldcsum - csum) + x; } + LoopNode.reportLoopCount(inliningTarget, arguments.length); return max * Math.sqrt(csum - 1.0 + frac); } } @@ -2824,6 +2829,7 @@ static double doGeneric(VirtualFrame frame, Object p, Object q, max = x; } } + LoopNode.reportLoopCount(inliningTarget, len); if (infProfile.profile(inliningTarget, Double.isInfinite(max))) { return max; } @@ -2845,6 +2851,7 @@ static double doGeneric(VirtualFrame frame, Object p, Object q, csum += x; frac += (oldcsum - csum) + x; } + LoopNode.reportLoopCount(inliningTarget, len); return max * Math.sqrt(csum - 1.0 + frac); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index a0ba1abd22..10557b83a5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -154,6 +154,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -490,6 +491,7 @@ private static void checkEqualSign(Node inliningTarget, byte[] bytes, PRaiseNode throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ILLEGAL_ENVIRONMENT_VARIABLE_NAME); } } + LoopNode.reportLoopCount(inliningTarget, bytes.length); } private static void checkWindowsEnvName(Node inliningTarget, TruffleString name, TruffleString.CodePointLengthNode codePointLengthNode, @@ -595,6 +597,7 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, Buffer bytes = posixLib.getPathAsBytes(context.getPosixSupport(), opaquePath); opaqueArgs[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); } + LoopNode.reportLoopCount(inliningTarget, args.length); // TODO ValueError "execv() arg 2 first element cannot be empty" auditNode.audit(frame, inliningTarget, T_OS_EXEC, path.originalObject, argv, PNone.NONE); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java index 22b17b9833..b5bdd3491d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java @@ -98,6 +98,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -153,6 +154,7 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, Buffer bytes = posixLib.getPathAsBytes(context.getPosixSupport(), path); argsArray[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); } + LoopNode.reportLoopCount(inliningTarget, len); return argsArray; } @@ -190,6 +192,7 @@ static Object doSequence(VirtualFrame frame, Object env, } result[i] = o1; } + LoopNode.reportLoopCount(inliningTarget, length); return result; } @@ -307,6 +310,7 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo executables[i] = createCStringFromBytes(inliningTarget, bytes, posixLib, raiseNode); } } + LoopNode.reportLoopCount(inliningTarget, length); gil.release(true); try { @@ -343,6 +347,7 @@ private static int[] convertFdSequence(Node inliningTarget, SequenceStorage stor } throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BAD_VALUES_IN_FDS_TO_KEEP); } + LoopNode.reportLoopCount(inliningTarget, len); return fds; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java index b05f6a58d5..b503d3aaee 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java @@ -85,6 +85,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -246,6 +247,7 @@ static Object doGetpall(VirtualFrame frame, for (int i = 0; i < result.length; i++) { result[i] = PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, createPwuidObject(inliningTarget, entries[i], language, unsignedConversionProfile)); } + LoopNode.reportLoopCount(inliningTarget, result.length); return PFactory.createList(language, result); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java index 6f9963e03d..d66b51b34a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java @@ -92,6 +92,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -194,15 +195,15 @@ static PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object x } } return PFactory.createTuple(language, new PList[]{ - toList(result.getReadFds(), readFDs, language), - toList(result.getWriteFds(), writeFDs, language), - toList(result.getErrorFds(), xFDs, language)}); + toList(inliningTarget, result.getReadFds(), readFDs, language), + toList(inliningTarget, result.getWriteFds(), writeFDs, language), + toList(inliningTarget, result.getErrorFds(), xFDs, language)}); } /** * Also maps the returned FDs back to their original Python level objects. */ - private static PList toList(boolean[] result, ObjAndFDList fds, PythonLanguage language) { + private static PList toList(Node inliningTarget, boolean[] result, ObjAndFDList fds, PythonLanguage language) { Object[] resultObjs = new Object[result.length]; int resultObjsIdx = 0; for (int i = 0; i < fds.fds.length; i++) { @@ -210,6 +211,7 @@ private static PList toList(boolean[] result, ObjAndFDList fds, PythonLanguage l resultObjs[resultObjsIdx++] = fds.objects[i]; } } + LoopNode.reportLoopCount(inliningTarget, fds.fds.length); return PFactory.createList(language, PythonUtils.arrayCopyOf(resultObjs, resultObjsIdx)); } @@ -231,6 +233,7 @@ private static ObjAndFDList seq2set(VirtualFrame frame, Node inliningTarget, Obj } fds.add(fd); } + LoopNode.reportLoopCount(inliningTarget, objects.size()); return new ObjAndFDList(objects.toArray(new Object[0]), fds.toArray()); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index e838baaaf2..2d5d882fdd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -135,6 +135,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.memory.ByteArraySupport; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedExactClassProfile; @@ -309,6 +310,7 @@ static Object doGeneric(VirtualFrame frame, Object ip, UniversalSockAddr forwardAddr = addrInfoCursorLib.getSockAddr(cursor); storage = appendNode.execute(inliningTarget, storage, makeIpAddrNode.execute(frame, inliningTarget, forwardAddr), SequenceStorageNodes.ListGeneralizationNode.SUPPLIER); } while (addrInfoCursorLib.next(cursor)); + LoopNode.reportLoopCount(inliningTarget, storage.length()); } finally { addrInfoCursorLib.release(cursor); } @@ -726,6 +728,7 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje new Object[]{cursorLib.getFamily(cursor), cursorLib.getSockType(cursor), cursorLib.getProtocol(cursor), canonName, addr}); storage = appendNode.execute(inliningTarget, storage, tuple, SequenceStorageNodes.ListGeneralizationNode.SUPPLIER); } while (cursorLib.next(cursor)); + LoopNode.reportLoopCount(inliningTarget, storage.length()); return PFactory.createList(context.getLanguage(inliningTarget), storage); } finally { cursorLib.release(cursor); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java index cb1cd7b2ef..50f5f40636 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java @@ -66,6 +66,8 @@ 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.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @CoreFunctions(defineModule = J__STRING) @@ -97,15 +99,16 @@ PSequenceIterator formatterParser(VirtualFrame frame, TruffleString self, } finally { ExecutionContext.BoundaryCallContext.exit(frame, language, context, state); } - return parserListToIterator(parserList, language); + return parserListToIterator(this, parserList, language); } } - private static PSequenceIterator parserListToIterator(ArrayList parserList, PythonLanguage language) { + private static PSequenceIterator parserListToIterator(Node inliningTarget, ArrayList parserList, PythonLanguage language) { Object[] tuples = new Object[parserList.size()]; for (int i = 0; i < tuples.length; i++) { tuples[i] = PFactory.createTuple(language, parserList.get(i)); } + LoopNode.reportLoopCount(inliningTarget, tuples.length); return PFactory.createSequenceIterator(language, PFactory.createList(language, tuples)); } @@ -131,7 +134,7 @@ Object formatterParser(VirtualFrame frame, TruffleString self, } finally { ExecutionContext.BoundaryCallContext.exit(frame, language, context, state); } - return PFactory.createTuple(language, new Object[]{result.first, parserListToIterator(result.parserList, language)}); + return PFactory.createTuple(language, new Object[]{result.first, parserListToIterator(this, result.parserList, language)}); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index c757647e9e..d7b29a3966 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -286,6 +286,7 @@ import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -1260,6 +1261,7 @@ static void doAudit(VirtualFrame frame, Node inliningTarget, TruffleString event for (Object hook : hooks) { callNode.get(inliningTarget).execute(frame, hook, event, argsTuple); } + LoopNode.reportLoopCount(inliningTarget, hooks.length); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java index 3a6a3ad5b0..25f58f9575 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java @@ -83,6 +83,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -254,12 +255,14 @@ static PTuple doUnpack(VirtualFrame frame, Node inliningTarget, PTuple params, @Cached UnpackNode unpackNode) { Object[] elements = toArrayNode.execute(inliningTarget, params.getSequenceStorage()); boolean found = false; - for (Object element : elements) { - if (element instanceof PTypeVarTuple) { + int index = 0; + for (; index < elements.length; index++) { + if (elements[index] instanceof PTypeVarTuple) { found = true; break; } } + LoopNode.reportLoopCount(inliningTarget, index); if (!found) { return params; } @@ -271,6 +274,7 @@ static PTuple doUnpack(VirtualFrame frame, Node inliningTarget, PTuple params, unpacked[i] = elements[i]; } } + LoopNode.reportLoopCount(inliningTarget, unpacked.length); return PFactory.createTuple(language, unpacked); } } 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 37e60023cd..a186658601 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 @@ -141,6 +141,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -1016,6 +1017,7 @@ Object doWarn(VirtualFrame frame, PythonModule mod, Object message, Object categ Object item = getItemScalarNode.execute(inliningTarget, storage, i); skipFilePrefixes[i] = castToStringChecked.cast(inliningTarget, item, ErrorMessages.FOUND_NON_STR_S_IN_SKIP_FILE_PREFIXES, item); } + LoopNode.reportLoopCount(inliningTarget, skipFilePrefixes.length); if (stacklevel < 2) { stacklevel = 2; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java index 3212366bb2..cc95ae9f93 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java @@ -101,6 +101,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.AST) @@ -159,6 +160,7 @@ protected Object doIt(VirtualFrame frame, Object self, Object[] args, PKeyword[] setAttrNode.execute(frame, inliningTarget, self, field, args[i]); discardNode.execute(frame, remainingFields, field); } + LoopNode.reportLoopCount(inliningTarget, args.length); Object selfType = getClassNode.execute(inliningTarget, self); for (PKeyword kwArg : kwArgs) { if (containsNode.execute(frame, inliningTarget, fieldsObj, kwArg.getName())) { @@ -173,6 +175,7 @@ protected Object doIt(VirtualFrame frame, Object self, Object[] args, PKeyword[] } setAttrNode.execute(frame, inliningTarget, self, kwArg.getName(), kwArg.getValue()); } + LoopNode.reportLoopCount(inliningTarget, kwArgs.length); if (storageLenNode.execute(inliningTarget, remainingFields.getDictStorage()) > 0) { Object fieldTypesObj = lookupAttrNode.execute(frame, inliningTarget, selfType, T__FIELD_TYPES); if (!(fieldTypesObj instanceof PDict fieldTypes)) { @@ -195,6 +198,7 @@ protected Object doIt(VirtualFrame frame, Object self, Object[] args, PKeyword[] } } } + LoopNode.reportLoopCount(inliningTarget, numFields); } return PNone.NONE; } @@ -253,6 +257,7 @@ static Object doit(VirtualFrame frame, PythonObject self, Object ignored, } numPositionalArgs++; } + LoopNode.reportLoopCount(inliningTarget, numFields); PNone[] positionalArgs = new PNone[numPositionalArgs]; Arrays.fill(positionalArgs, PNone.NONE); return PFactory.createTuple(language, new Object[]{clazz, PFactory.createTuple(language, positionalArgs), dict}); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java index 7694a37392..bcaf6b1404 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java @@ -143,6 +143,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -243,6 +244,7 @@ static int next(PDict dict, long posPtr, long keyPtr, long valuePtr, long hashPt break; } } + LoopNode.reportLoopCount(inliningTarget, len); } else { /* * Other storages always have string keys or have complex iterators, just @@ -268,6 +270,7 @@ static int next(PDict dict, long posPtr, long keyPtr, long valuePtr, long hashPt // promoted key will never have side-effecting __hash__/__eq__ setItem.execute(null, inliningTarget, newStorage, key, value); } + LoopNode.reportLoopCount(inliningTarget, len); dict.setDictStorage(newStorage); if (storage instanceof DynamicObjectStorage dynamicStorage && dynamicStorage.getStore() instanceof PythonObject owner) { @@ -888,6 +891,7 @@ static int merge(PDict a, Object b, @SuppressWarnings("unused") int override, aStorage = setItemA.execute(null, inliningTarget, aStorage, key, value); } } + LoopNode.reportLoopCount(inliningTarget, size); a.setDictStorage(aStorage); return 0; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 5f115f4d17..398655635e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -162,6 +162,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -225,6 +226,7 @@ static Object doLong(long arrayPointer, int len, pointers[i] = elem; resolved[i] = nativeToPythonNode.execute(inliningTarget, elem); } + LoopNode.reportLoopCount(inliningTarget, resolved.length); HandleContext handleContext = PythonContext.get(inliningTarget).handleContext; for (int i = 0; i < resolved.length; i++) { long refCount = CApiTransitions.readNativeRefCount(pointers[i]); @@ -242,6 +244,7 @@ static Object doLong(long arrayPointer, int len, updateRefNode.execute(inliningTarget, handleContext, pointers[i], hti, refCount); } } + LoopNode.reportLoopCount(inliningTarget, resolved.length); Reference.reachabilityFence(resolved); return PNone.NO_VALUE; } @@ -335,6 +338,7 @@ static Object doGeneric(@SuppressWarnings("unused") long threadState, Object cal TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); keywords[i] = new PKeyword(name, kwValues[i]); } + LoopNode.reportLoopCount(inliningTarget, kwcount); } else { throw CompilerDirectives.shouldNotReachHere("_PyObject_MakeTpCall: keywords must be NULL, a tuple or a dict"); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java index c5b2d46b31..691e893535 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java @@ -133,6 +133,7 @@ import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.EncapsulatingNodeReference; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.Shape; @@ -188,11 +189,14 @@ Object doGeneric(Object type, Object name, } else { setItem.execute(null, inliningTarget, dict, key, promoted); } + LoopNode.reportLoopCount(inliningTarget, i); return promoted; } + LoopNode.reportLoopCount(inliningTarget, i); return value; } } + LoopNode.reportLoopCount(inliningTarget, mro.length()); return NATIVE_NULL; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java index 5cd0f27dc1..7e67ff7c82 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java @@ -189,6 +189,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.nodes.ControlFlowException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedExactClassProfile; @@ -489,6 +490,7 @@ static Object formatLong(Object val, int alt, int prec, int type, for (int i = 0; i < prec - numdigits; i++) { b1[b1i++] = '0'; } + LoopNode.reportLoopCount(inliningTarget, prec - numdigits); for (int i = 0; i < numdigits; i++) { b1[b1i++] = buf[bufi++]; b1[b1i] = '\0'; @@ -508,6 +510,7 @@ static Object formatLong(Object val, int alt, int prec, int type, buf[i] -= 'a' - 'A'; } } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, len - bufi)); } return fromCharArrayNode.execute(buf); } @@ -848,6 +851,7 @@ static Object join(Object separatorObj, long itemsObj, long seqlenlong, } appendStringNode.execute(sb, item); } + LoopNode.reportLoopCount(inliningTarget, items.length); return toStringNode.execute(sb); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java index 40317f7de0..208c54b469 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java @@ -82,6 +82,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -186,6 +187,7 @@ static Object doGeneric(VirtualFrame frame, MultibyteStreamWriterObject self, Ob Object str = encodeStatefulNode.execute(frame, self, strobj, 0); callMethod.execute(frame, inliningTarget, self.stream, WRITE, str); } + LoopNode.reportLoopCount(inliningTarget, n); return PNone.NONE; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java index 5c14430531..f8c85b8a89 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java @@ -112,6 +112,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -376,11 +377,13 @@ static Object doEncode(PBaseException exception, for (int i = start; i < end; ++i) { replacementLength += getXmlCharRefReplacementLength(codePointAtIndexNode.execute(src, i)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); byte[] replacement = new byte[replacementLength]; int pos = 0; for (int i = start; i < end; ++i) { pos = appendXmlCharRefReplacement(replacement, pos, codePointAtIndexNode.execute(src, i)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); TruffleString resultAscii = fromByteArrayNode.execute(replacement, 0, replacement.length, TruffleString.CompactionLevel.S1, false); return PFactory.createTuple(language, new Object[]{resultAscii, end}); } @@ -423,6 +426,7 @@ static Object doDecodeException(VirtualFrame frame, PBaseException exception, for (int i = start; i < end; i++) { pos = BytesUtils.byteEscape(src[i] & 0xFF, pos, replacement); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); } finally { accessLib.release(srcBuf, frame, callData); } @@ -457,12 +461,14 @@ static Object doEncodeOrTranslateException(PBaseException exception, len += 1 + 1 + 2; // \\xNN } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); byte[] replacement = new byte[len]; int pos = 0; for (int i = start; i < end; i++) { int cp = codePointAtIndexNode.execute(src, i); pos = BytesUtils.unicodeNonAsciiEscape(cp, pos, replacement, true); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); TruffleString resultAscii = fromByteArrayNode.execute(replacement, 0, replacement.length, TruffleString.CompactionLevel.S1, false); return PFactory.createTuple(language, new Object[]{resultAscii, end}); } @@ -515,6 +521,7 @@ static Object doEncode(PBaseException exception, appendStringNode.execute(tsb, fromByteArrayNode.execute(buf, 0, len, TruffleString.CompactionLevel.S1, true)); } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); return PFactory.createTuple(language, new Object[]{toStringNode.execute(tsb), end}); } @@ -563,6 +570,7 @@ static Object doEncode(PBaseException exception, encodeCodepoint(encoding, result, pos, cp); pos += encoding.byteLength; } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); return PFactory.createTuple(language, new Object[]{PFactory.createBytes(language, result), end}); } @@ -691,6 +699,7 @@ static Object doEncode(PBaseException exception, } result[pos++] = (byte) (cp - 0xdc00); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); return PFactory.createTuple(language, new Object[]{PFactory.createBytes(language, result), end}); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.java index 371f6861db..484ec5e9da 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.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 @@ -104,6 +104,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -320,6 +321,7 @@ static Object lruCacheMakeKey(Object kwdMark, Object[] args, PKeyword[] kwds, in } } } + LoopNode.reportLoopCount(inliningTarget, keyPos - kwdsSize - (kwdsSize != 0 ? 1 : 0)); assert (keyPos == keySize); return PFactory.createTuple(PythonLanguage.get(inliningTarget), keyArray); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java index 6cd8fedd46..a79f81ab0a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java @@ -127,6 +127,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -500,6 +501,7 @@ static Object callWDictWKw(VirtualFrame frame, PPartial self, Object[] args, PKe callKeywords[idx] = kw; } } + LoopNode.reportLoopCount(inliningTarget, keywords.length); callKeywords = PythonUtils.arrayCopyOfRange(callKeywords, 0, kwIndex); return callNode.execute(frame, self.getFn(), callArgs, callKeywords); @@ -511,10 +513,12 @@ static Object callWDictWKw(VirtualFrame frame, PPartial self, Object[] args, PKe abstract static class PartialReprNode extends PythonUnaryBuiltinNode { private static void reprArgs(VirtualFrame frame, Node inliningTarget, PPartial partial, TruffleStringBuilderUTF32 sb, PyObjectReprAsTruffleStringNode reprNode, TruffleStringBuilder.AppendStringNode appendStringNode) { - for (Object arg : partial.getArgs()) { + Object[] args = partial.getArgs(); + for (int i = 0; i < args.length; i++) { appendStringNode.execute(sb, T_COMMA_SPACE); - appendStringNode.execute(sb, reprNode.execute(frame, inliningTarget, arg)); + appendStringNode.execute(sb, reprNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); } private static void reprKwArgs(VirtualFrame frame, Node inliningTarget, PPartial partial, TruffleStringBuilderUTF32 sb, PyObjectReprAsTruffleStringNode reprNode, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java index 5bc9da8838..c8e2b30493 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java @@ -133,6 +133,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.PBytesIO) @@ -353,6 +354,7 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization(guards = "self.hasBuf()") static Object readlines(PBytesIO self, int maxsize, + @Bind Node inliningTarget, @Bind PythonLanguage language, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib) { ArrayBuilder result = new ArrayBuilder<>(); @@ -372,6 +374,7 @@ static Object readlines(PBytesIO self, int maxsize, } cur += n; } + LoopNode.reportLoopCount(inliningTarget, result.size()); return PFactory.createList(language, result.toArray(new Object[0])); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.java index e248e10e62..ab1ae6299a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.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 @@ -136,6 +136,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -572,6 +573,7 @@ static Object withHint(VirtualFrame frame, Object self, int hintIn, } length += lineLength; } + LoopNode.reportLoopCount(inliningTarget, list.size()); return PFactory.createList(language, list.toArray(new Object[0])); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index 305f47cede..85ab4c5bba 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -187,6 +187,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; @@ -385,6 +386,7 @@ public HashingStorage copyMemoToHashingStorage(Node inliningTarget, HashingStora // frame not needed for integer key hashingStorage = setItem.execute(null, inliningTarget, hashingStorage, i, memo[i]); } + LoopNode.reportLoopCount(inliningTarget, memo.length); return hashingStorage; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 6e38abab05..8ac0b1339e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -110,6 +110,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -601,21 +602,23 @@ public TruffleString asStringStrict(Object value) { public static Pair getDeepAttribute(VirtualFrame frame, PyObjectLookupAttr lookup, Object obj, TruffleString[] names) { Object parent = null; Object object = obj; - for (TruffleString name : names) { + for (int i = 0; i < names.length; i++) { parent = object; - object = lookup.executeCached(frame, parent, name); + object = lookup.executeCached(frame, parent, names[i]); if (object == NO_VALUE) { + LoopNode.reportLoopCount(lookup, i); return null; } } + LoopNode.reportLoopCount(lookup, names.length); return Pair.create(object, parent); } public TruffleString[] getDottedPath(Object obj, TruffleString name) { TruffleString[] dottedPath = StringUtils.split(name, T_DOT, ensureTsCodePointLengthNode(), ensureTsIndexOfStringNode(), ensureTsSubstringNode(), ensureTsEqualNode()); assert dottedPath.length > 0; - for (TruffleString subPath : dottedPath) { - if (ensureTsEqualNode().execute(subPath, T_LOCALS, TS_ENCODING)) { + for (int i = 0; i < dottedPath.length; i++) { + if (ensureTsEqualNode().execute(dottedPath[i], T_LOCALS, TS_ENCODING)) { if (obj == null) { throw raise(AttributeError, ErrorMessages.CANT_PICKLE_LOCAL_OBJ_S, name); } else { @@ -623,6 +626,7 @@ public TruffleString[] getDottedPath(Object obj, TruffleString name) { } } } + LoopNode.reportLoopCount(this, dottedPath.length); return dottedPath; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java index d166e20c21..e18592d60d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java @@ -84,6 +84,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleStringBuilder; @@ -266,6 +267,7 @@ static Object expand(VirtualFrame frame, PMatch self, Object templateString, appendStringNode.execute(builder, substring); } } + LoopNode.reportLoopCount(inliningTarget, template.indices.length); // add the extra literal Object literal = template.literals[template.literals.length - 1]; @@ -309,6 +311,7 @@ static Object group(VirtualFrame frame, PMatch self, Object[] args, PKeyword[] k Object group = getSliceNode.execute(frame, inliningTarget, self, args[i]); groups[i] = group; } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createTuple(language, groups); } @@ -342,6 +345,7 @@ static Object groups(VirtualFrame frame, PMatch self, Object defaultValueArg, groups[i] = group; } } + LoopNode.reportLoopCount(inliningTarget, groups.length); return PFactory.createTuple(language, groups); } @@ -375,6 +379,7 @@ static Object groupDict(VirtualFrame frame, PMatch self, Object defaultValueArg, keysAndValues[i + 1] = group; } } + LoopNode.reportLoopCount(inliningTarget, keysAndValues.length / 2); LinkedHashMap groupNameToGroupMap = arrayToMap(keysAndValues); return PFactory.createDictFromMap(language, groupNameToGroupMap); @@ -553,6 +558,7 @@ static PTuple spans(PMatch self, spans[groupIndex] = PFactory.createTuple(language, new int[]{start, end}); } + LoopNode.reportLoopCount(inliningTarget, spans.length); return PFactory.createTuple(language, spans); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java index 7d0f041dc5..415432bd14 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java @@ -135,6 +135,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -808,6 +809,7 @@ static Object doString(Node inliningTarget, Object compiledRegex, Object compile pos = end; mustAdvance = start == end; } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) n * groupCount)); result.add(createSubstring(inliningTarget, input, binary, pos, stringLength, substringByteIndexNode, copyToByteArrayNode)); return PFactory.createList(PythonLanguage.get(inliningTarget), result.toObjectArray()); } @@ -952,6 +954,7 @@ static Object doString(Node inliningTarget, Object compiledRegex, Object compile pos = end; mustAdvance = start == end; } + LoopNode.reportLoopCount(inliningTarget, createTuples ? (int) Math.min(Integer.MAX_VALUE, (long) result.size() * groupCount) : result.size()); return PFactory.createList(PythonLanguage.get(inliningTarget), result.toObjectArray()); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java index c6a4a0f5d5..9c364dd814 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java @@ -74,6 +74,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; @@ -220,6 +221,7 @@ PTemplate template(VirtualFrame frame, PPattern pattern, PList template, literals[i / 2] = item; } } + LoopNode.reportLoopCount(inliningTarget, length); PythonBuiltinClassType cls = PythonBuiltinClassType.SRETemplate; Shape shape = cls.getInstanceShape(language); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java index 55dc6d940a..8fd8860451 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java @@ -353,14 +353,15 @@ static long doJavaBytes(PBytesLike data, int value, @Shared("b") @Cached SequenceStorageNodes.GetInternalBytesNode toBytes) { byte[] bytes = toBytes.execute(inliningTarget, data); int len = data.getSequenceStorage().length(); - return crc32(value, bytes, 0, len); + return crc32(inliningTarget, value, bytes, 0, len); } @Specialization(guards = {"!useNative()", "!isBytes(data)"}) static long doJavaObject(VirtualFrame frame, Object data, int value, + @Bind Node inliningTarget, @Shared("bb") @Cached ToBytesNode toBytesNode) { byte[] bytes = toBytesNode.execute(frame, data); - return crc32(value, bytes, 0, bytes.length); + return crc32(inliningTarget, value, bytes, 0, bytes.length); } @Fallback diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java index 0c35fc57a1..ecafd8f465 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java @@ -175,6 +175,7 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.Shape; @@ -1162,7 +1163,10 @@ static boolean access(Object object, TruffleString attrKeyName, int type, Object attr = PNone.NO_VALUE; Object klass = getClassNode.execute(inliningTarget, object); - for (PythonAbstractClass c : getMroNode.execute(inliningTarget, klass)) { + PythonAbstractClass[] mro = getMroNode.execute(inliningTarget, klass); + int i = 0; + for (; i < mro.length; i++) { + PythonAbstractClass c = mro[i]; // n.b. we need to use a different node because it makes a difference if the // type is native attr = readTypeAttrNode.execute(c, attrKeyName); @@ -1171,6 +1175,7 @@ static boolean access(Object object, TruffleString attrKeyName, int type, break; } } + LoopNode.reportLoopCount(inliningTarget, i); if (attr == PNone.NO_VALUE) { attr = readObjectAttrNode.execute(owner, attrKeyName); } @@ -1337,6 +1342,7 @@ static Object doExecute(Object receiver, Object[] arguments, for (int i = 0; loopProfile.inject(inliningTarget, i < length); i++) { starArgs[i] = iLibIterator.getIteratorNextElement(iterator); } + LoopNode.reportLoopCount(inliningTarget, starArgs.length); if (isIndexNotZeroProfile.profile(inliningTarget, index > 0)) { newArgs = new Object[index + starArgs.length]; PythonUtils.arraycopy(arguments, 0, newArgs, 0, index); @@ -1388,12 +1394,13 @@ static Object[] cached(Object[] arguments, } @Specialization(replaces = "cached") - static Object[] generic(Object[] arguments, + static Object[] generic(Node inliningTarget, Object[] arguments, @Shared @Cached(inline = false) PForeignToPTypeNode fromForeign) { Object[] convertedArgs = new Object[arguments.length]; for (int i = 0; i < arguments.length; i++) { convertedArgs[i] = fromForeign.executeConvert(arguments[i]); } + LoopNode.reportLoopCount(inliningTarget, arguments.length); return convertedArgs; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java index 049cebe02b..977d5b6d08 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java @@ -138,6 +138,7 @@ import com.oracle.graal.python.util.BufferFormat; import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.dsl.Bind; @@ -155,6 +156,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedByteValueProfile; @@ -255,6 +257,7 @@ static PArray arrayWithRangeInitializer(Node inliningTarget, Object cls, Truffle for (int index = 0, value = start; index < len; index++, value += step) { putValueNode.execute(null, inliningTarget, array, index, value); } + LoopNode.reportLoopCount(inliningTarget, len); return array; } @@ -298,6 +301,7 @@ static PArray arrayArrayInitializer(VirtualFrame frame, Node inliningTarget, Obj for (int i = 0; i < length; i++) { putValueNode.execute(frame, inliningTarget, array, i, getValueNode.execute(inliningTarget, initializer, i)); } + LoopNode.reportLoopCount(inliningTarget, length); return array; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -319,6 +323,7 @@ static PArray arraySequenceInitializer(VirtualFrame frame, Node inliningTarget, for (int i = 0; i < length; i++) { putValueNode.execute(frame, inliningTarget, array, i, getItemNode.execute(inliningTarget, storage, i)); } + LoopNode.reportLoopCount(inliningTarget, length); return array; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -355,6 +360,7 @@ static PArray arrayIteratorInitializer(VirtualFrame frame, Node inliningTarget, break; } } + LoopNode.reportLoopCount(inliningTarget, length); setLengthNode.execute(inliningTarget, array, length); return array; @@ -436,6 +442,7 @@ static PArray concat(PArray self, int valueIn, for (int i = 0; loopProfile.inject(inliningTarget, i < value); i++) { bufferLib.readIntoBuffer(self.getBuffer(), 0, newArray.getBuffer(), segmentLength * i, segmentLength, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, value); return newArray; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -470,6 +477,7 @@ static Object concat(PArray self, int value, for (int i = 0; i < value; i++) { bufferLib.readIntoBuffer(self.getBuffer(), 0, self.getBuffer(), segmentLength * i, segmentLength, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, value > 0 ? value : 0); return self; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -499,17 +507,22 @@ static Object cmpItems(VirtualFrame frame, PArray left, PArray right, RichCmpOp fullCmpProfile.enter(inliningTarget); int commonLength = Math.min(left.getLength(), right.getLength()); loopProfile.profileCounted(inliningTarget, commonLength); // ignoring the early exit - for (int i = 0; loopProfile.inject(inliningTarget, i < commonLength); i++) { - Object leftValue = getLeft.execute(inliningTarget, left, i); - Object rightValue = getRight.execute(inliningTarget, right, i); - if (!richCmpEqNode.execute(frame, inliningTarget, leftValue, rightValue, RichCmpOp.Py_EQ)) { - if (op == RichCmpOp.Py_EQ) { - return false; - } else if (op == RichCmpOp.Py_NE) { - return true; + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < commonLength); i++) { + Object leftValue = getLeft.execute(inliningTarget, left, i); + Object rightValue = getRight.execute(inliningTarget, right, i); + if (!richCmpEqNode.execute(frame, inliningTarget, leftValue, rightValue, RichCmpOp.Py_EQ)) { + if (op == RichCmpOp.Py_EQ) { + return false; + } else if (op == RichCmpOp.Py_NE) { + return true; + } + return richCmpOpNode.execute(frame, inliningTarget, leftValue, rightValue, op); } - return richCmpOpNode.execute(frame, inliningTarget, leftValue, rightValue, op); } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } if (op.isEqOrNe()) { return op.isEq(); @@ -539,12 +552,17 @@ static boolean cmpDoubles(VirtualFrame frame, PArray left, PArray right, RichCmp fullCmpProfile.enter(inliningTarget); int commonLength = Math.min(left.getLength(), right.getLength()); loopProfile.profileCounted(inliningTarget, commonLength); // ignoring the early exit - for (int i = 0; loopProfile.inject(inliningTarget, i < commonLength); i++) { - double leftValue = (Double) getLeft.execute(inliningTarget, left, i); - double rightValue = (Double) getRight.execute(inliningTarget, right, i); - if (leftValue != rightValue) { - return op.compare(leftValue, rightValue); + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < commonLength); i++) { + double leftValue = (Double) getLeft.execute(inliningTarget, left, i); + double rightValue = (Double) getRight.execute(inliningTarget, right, i); + if (leftValue != rightValue) { + return op.compare(leftValue, rightValue); + } } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } if (op.isEqOrNe()) { return op.isEq(); @@ -618,6 +636,7 @@ static TruffleString repr(VirtualFrame frame, PArray self, Object value = getValueNode.execute(inliningTarget, self, i); appendStringNode.execute(sb, cast.execute(inliningTarget, repr.execute(frame, inliningTarget, value))); } + LoopNode.reportLoopCount(inliningTarget, length); appendStringNode.execute(sb, T_RBRACKET); } } @@ -690,6 +709,7 @@ static Object doSlice(PArray self, PSlice slice, for (int i = sliceInfo.start, j = 0; j < sliceInfo.sliceLength; i += sliceInfo.step, j++) { bufferLib.readIntoBuffer(self.getBuffer(), i << itemShift, newArray.getBuffer(), j << itemShift, itemsize, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, sliceInfo.sliceLength); } return newArray; } @@ -835,6 +855,7 @@ static void setitem(PArray self, PSlice slice, Object other, for (cur = start, offset = 0; offset < sliceLength - 1; cur += step, offset++) { bufferLib.readIntoBuffer(self.getBuffer(), (cur + 1) << itemShift, self.getBuffer(), (cur - offset) << itemShift, (step - 1) << itemShift, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, offset); bufferLib.readIntoBuffer(self.getBuffer(), (cur + 1) << itemShift, self.getBuffer(), (cur - offset) << itemShift, (length - cur - 1) << itemShift, bufferLib); setLengthNode.execute(inliningTarget, self, length - sliceLength); } @@ -843,6 +864,7 @@ static void setitem(PArray self, PSlice slice, Object other, for (int cur = start, i = 0; i < sliceLength; cur += step, i++) { bufferLib.readIntoBuffer(sourceBuffer, i << itemShift, self.getBuffer(), cur << itemShift, itemsize, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, sliceLength); } else { wrongLengthProfile.enter(inliningTarget); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ATTEMPT_ASSIGN_ARRAY_OF_SIZE, needed, sliceLength); @@ -1078,6 +1100,7 @@ static Object extend(VirtualFrame frame, PArray self, PSequence value, putValueNode.execute(frame, inliningTarget, self, length, getItemNode.execute(inliningTarget, storage, i)); setLengthNode.execute(inliningTarget, self, ++length); } + LoopNode.reportLoopCount(inliningTarget, storageLength); return PNone.NONE; } @@ -1113,7 +1136,6 @@ static Object extend(VirtualFrame frame, PArray self, Object value, putValueNode.execute(frame, inliningTarget, self, length - 1, nextValue); setLengthNode.execute(inliningTarget, self, length); } - return PNone.NONE; } @@ -1175,6 +1197,7 @@ static Object remove(VirtualFrame frame, PArray self, Object value, if (eqNode.execute(frame, inliningTarget, item, value, RichCmpOp.Py_EQ)) { self.checkCanResize(inliningTarget, raiseNode); deleteSliceNode.execute(inliningTarget, self, i, 1); + LoopNode.reportLoopCount(inliningTarget, i + 1); return PNone.NONE; } } @@ -1313,6 +1336,7 @@ static Object fromlist(VirtualFrame frame, PArray self, PList list, for (int i = 0; i < length; i++) { putValueNode.execute(frame, inliningTarget, self, self.getLength() + i, getItemScalarNode.execute(inliningTarget, storage, i)); } + LoopNode.reportLoopCount(inliningTarget, length); setLengthNode.execute(inliningTarget, self, newLength); return PNone.NONE; } catch (OverflowException e) { @@ -1358,6 +1382,7 @@ static Object fromunicode(VirtualFrame frame, PArray self, TruffleString str, TruffleString value = fromCodePointNode.execute(nextNode.execute(it, TS_ENCODING), TS_ENCODING, true); putValueNode.execute(frame, inliningTarget, self, self.getLength() + codePointIndex++, value); } + LoopNode.reportLoopCount(inliningTarget, length); setLengthNode.execute(inliningTarget, self, newLength); return PNone.NONE; } catch (OverflowException e) { @@ -1421,6 +1446,7 @@ static TruffleString tounicode(PArray self, for (int i = 0; i < length; i++) { appendStringNode.execute(sb, (TruffleString) getValueNode.execute(inliningTarget, self, i)); } + LoopNode.reportLoopCount(inliningTarget, length); return toStringNode.execute(sb); } } @@ -1463,6 +1489,8 @@ static Object tofile(VirtualFrame frame, PArray self, Object file, callMethod.execute(frame, inliningTarget, file, T_WRITE, PFactory.createBytes(language, buffer)); remaining -= blocksize; } + // Rounding up remaining to whole blocks above can overflow to a negative nblocks. + LoopNode.reportLoopCount(inliningTarget, Math.max(0, nblocks)); } return PNone.NONE; } @@ -1479,29 +1507,35 @@ static Object byteswap1(@SuppressWarnings("unused") PArray self) { @Specialization(guards = "self.getFormat().bytesize == 2") static Object byteswap2(PArray self, + @Bind Node inliningTarget, @Shared @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib) { - doByteSwapExploded(self, 2, self.getBuffer(), bufferLib); + doByteSwapExploded(inliningTarget, self, 2, self.getBuffer(), bufferLib); return PNone.NONE; } @Specialization(guards = "self.getFormat().bytesize == 4") static Object byteswap4(PArray self, + @Bind Node inliningTarget, @Shared @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib) { - doByteSwapExploded(self, 4, self.getBuffer(), bufferLib); + doByteSwapExploded(inliningTarget, self, 4, self.getBuffer(), bufferLib); return PNone.NONE; } @Specialization(guards = "self.getFormat().bytesize == 8") static Object byteswap8(PArray self, + @Bind Node inliningTarget, @Shared @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib) { - doByteSwapExploded(self, 8, self.getBuffer(), bufferLib); + doByteSwapExploded(inliningTarget, self, 8, self.getBuffer(), bufferLib); return PNone.NONE; } - private static void doByteSwapExploded(PArray self, int itemsize, Object buffer, PythonBufferAccessLibrary bufferLib) { + private static void doByteSwapExploded(Node inliningTarget, PArray self, int itemsize, Object buffer, PythonBufferAccessLibrary bufferLib) { + CompilerAsserts.compilationConstant(itemsize); for (int i = 0; i < self.getBytesLength(); i += itemsize) { doByteSwapExplodedInnerLoop(buffer, itemsize, i, bufferLib); } + // over-reporting, but also inner loop is not counted... + LoopNode.reportLoopCount(inliningTarget, self.getBytesLength()); } @ExplodeLoop @@ -1537,9 +1571,11 @@ static int index(VirtualFrame frame, PArray self, Object value, int start, int s } for (int i = start; i < stop && i < length; i++) { if (eqNode.execute(frame, inliningTarget, getValueNode.execute(inliningTarget, self, i), value, RichCmpOp.Py_EQ)) { + LoopNode.reportLoopCount(inliningTarget, i - start + 1); return i; } } + LoopNode.reportLoopCount(inliningTarget, Math.min(stop, length) > start ? Math.min(stop, length) - start : 0); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ARRAY_INDEX_X_NOT_IN_ARRAY); } @@ -1573,6 +1609,7 @@ abstract static class ReverseNode extends PythonUnaryBuiltinNode { @Specialization static Object reverse(PArray self, + @Bind Node inliningTarget, @CachedLibrary(limit = "2") PythonBufferAccessLibrary bufferLib) { int itemsize = self.getFormat().bytesize; int itemShift = self.getItemSizeShift(); @@ -1583,6 +1620,7 @@ static Object reverse(PArray self, bufferLib.readIntoBuffer(self.getBuffer(), (length - i - 1) << itemShift, self.getBuffer(), i << itemShift, itemsize, bufferLib); bufferLib.writeFromByteArray(self.getBuffer(), (length - i - 1) << itemShift, tmp, 0, itemsize); } + LoopNode.reportLoopCount(inliningTarget, length / 2); return PNone.NONE; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java index 0c31775649..ba8768cbf5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java @@ -59,6 +59,7 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -176,6 +177,7 @@ void readIntoBuffer(int srcOffset, Object dest, int destOffset, int length, Pyth for (int i = 0; i < length; i++) { otherLib.writeByte(dest, destOffset + i, readByte(srcOffset + i, interop)); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, length)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java index d74ab10fe0..4ecfe395e3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java @@ -51,6 +51,7 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.GenerateLibrary; @@ -198,6 +199,7 @@ public void readIntoByteArray(Object receiver, int srcOffset, byte[] dest, int d for (int i = 0; i < length; i++) { dest[destOffset + i] = readByte(receiver, srcOffset + i); } + LoopNode.reportLoopCount(this, Math.max(0, length)); } } @@ -218,6 +220,7 @@ public void writeFromByteArray(Object receiver, int destOffset, byte[] src, int for (int i = 0; i < length; i++) { writeByte(receiver, destOffset + i, src[srcOffset + i]); } + LoopNode.reportLoopCount(this, Math.max(0, length)); } } @@ -239,6 +242,7 @@ public void readIntoBuffer(Object receiver, int srcOffset, Object dest, int dest for (int i = 0; i < length; i++) { otherLib.writeByte(dest, destOffset + i, readByte(receiver, srcOffset + i)); } + LoopNode.reportLoopCount(this, Math.max(0, length)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java index 44bed66f34..794ef94f73 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java @@ -760,11 +760,11 @@ static PByteArray translate(VirtualFrame frame, PByteArray self, Object table, O Result result; if (bTable != null && bDelete != null) { - result = translateAndDelete(bSelf, bTable, bDelete); + result = translateAndDelete(inliningTarget, bSelf, bTable, bDelete); } else if (bTable != null) { result = translate(bSelf, bTable); } else if (bDelete != null) { - result = delete(bSelf, bDelete); + result = delete(inliningTarget, bSelf, bDelete); } else { return PFactory.createByteArray(language, bSelf); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java index 45e196dc27..60f3a9bf04 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java @@ -330,11 +330,11 @@ static Object translate(VirtualFrame frame, Object self, Object table, Object de Result result; if (bTable != null && bDelete != null) { - result = translateAndDelete(bSelf, bTable, bDelete); + result = translateAndDelete(inliningTarget, bSelf, bTable, bDelete); } else if (bTable != null) { result = translate(bSelf, bTable); } else if (bDelete != null) { - result = delete(bSelf, bDelete); + result = delete(inliningTarget, bSelf, bDelete); } else if (!checkExactNode.execute(inliningTarget, self)) { return PFactory.createBytes(language, bSelf); } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java index 558e063b3d..5920ee72a9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java @@ -424,9 +424,11 @@ private boolean doIt(VirtualFrame frame, byte[] self, int len, SequenceStorage s Object element = getItemNode.execute(inliningTarget, substrsStorage, i); byte[] bytes = tobytes.execute(frame, element); if (doIt(self, len, bytes, start, stop)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, substrsStorage.length()); return false; } } @@ -886,9 +888,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (b[i] < 0) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -919,9 +923,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isAlnum(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -952,9 +958,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isAlpha(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -985,9 +993,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isDigit(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -1023,10 +1033,12 @@ static boolean check(Object buffer, if (!BytesUtils.isUpper(ch)) { uncased++; } else { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } } + LoopNode.reportLoopCount(inliningTarget, len); return uncased == 0 || len > uncased; } finally { bufferLib.release(buffer); @@ -1062,10 +1074,12 @@ static boolean check(Object buffer, if (!BytesUtils.isLower(ch)) { uncased++; } else { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } } + LoopNode.reportLoopCount(inliningTarget, len); return uncased == 0 || len > uncased; } finally { bufferLib.release(buffer); @@ -1096,9 +1110,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isSpace(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -1134,18 +1150,21 @@ static boolean check(Object buffer, if (BytesUtils.isUpper(ch)) { if (previousIsCased) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } previousIsCased = true; cased = true; } else if (BytesUtils.isLower(ch)) { if (!previousIsCased) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } else { previousIsCased = false; } } + LoopNode.reportLoopCount(inliningTarget, len); return cased; } finally { bufferLib.release(buffer); @@ -1273,6 +1292,7 @@ protected byte[] make(byte[] self, int len, int width, byte fill) { for (int i = l, j = 0; i < (len + l); j++, i++) { res[i] = self[j]; } + LoopNode.reportLoopCount(this, len); return res; } @@ -1400,6 +1420,7 @@ static PBytesLike replace(Object self, for (int i = 0; i < bytes.length; ++i) { bytes[i] = toLower(bytes[i]); } + LoopNode.reportLoopCount(node, bytes.length); return create.execute(node, self, bytes); } } @@ -1417,6 +1438,7 @@ static PBytesLike replace(Object self, for (int i = 0; i < bytes.length; ++i) { bytes[i] = toUpper(bytes[i]); } + LoopNode.reportLoopCount(inliningTarget, bytes.length); return create.execute(inliningTarget, self, bytes); } } @@ -1679,6 +1701,8 @@ protected ArrayBuilder splitSingle(byte[] bytes, int len, byte sep, int } } } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); + LoopNode.reportLoopCount(this, j); if (i <= len) { list.add(copyOfRange(bytes, i, len)); } @@ -1701,6 +1725,7 @@ protected ArrayBuilder splitDelimiter(byte[] bytes, int len, byte[] sep, list.add(copyOfRange(bytes, i, j)); i = j + sepLen; } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); list.add(copyOfRange(bytes, i, len)); @@ -1743,6 +1768,7 @@ protected ArrayBuilder splitWhitespace(byte[] bytes, int len, int maxspl } list.add(copyOfRange(bytes, i + 1, j + 1)); } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); if (i >= 0) { /* Only occurs when maxcount was reached */ @@ -1754,6 +1780,7 @@ protected ArrayBuilder splitWhitespace(byte[] bytes, int len, int maxspl list.add(copyOfRange(bytes, 0, i + 1)); } } + LoopNode.reportLoopCount(this, len - 1 - i); list.reverse(); return list; } @@ -1773,6 +1800,8 @@ protected ArrayBuilder splitSingle(byte[] bytes, int len, byte sep, int } } } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); + LoopNode.reportLoopCount(this, len - (i + 1)); if (j >= -1) { list.add(copyOfRange(bytes, 0, j + 1)); } @@ -1798,6 +1827,7 @@ protected ArrayBuilder splitDelimiter(byte[] bytes, int len, byte[] sep, list.add(copyOfRange(bytes, pos + sepLen, j)); j = pos; } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); list.add(copyOfRange(bytes, 0, j)); list.reverse(); return list; @@ -2036,6 +2066,7 @@ static PBytes maketrans(VirtualFrame frame, @SuppressWarnings("unused") Object c byte value = fromB[i]; table[value < 0 ? value + 256 : value] = toB[i]; } + LoopNode.reportLoopCount(inliningTarget, fromB.length); return PFactory.createBytes(language, table); } @@ -2059,6 +2090,7 @@ static PBytesLike capitalize(Object self, for (int i = 1; i < b.length; i++) { b[i] = toLower(b[i]); } + LoopNode.reportLoopCount(inliningTarget, b.length - 1); return create.execute(inliningTarget, self, b); } } @@ -2095,6 +2127,7 @@ static PBytesLike title(Object self, } b[i] = c; } + LoopNode.reportLoopCount(inliningTarget, b.length); return create.execute(inliningTarget, self, b); } @@ -2120,6 +2153,7 @@ static PBytesLike swapcase(Object self, b[i] = toUpper(b[i]); } } + LoopNode.reportLoopCount(inliningTarget, b.length); return create.execute(inliningTarget, self, b); } } @@ -2173,6 +2207,7 @@ static PBytesLike expandtabs(Object self, int tabsize, } } } + LoopNode.reportLoopCount(inliningTarget, len); if (i > max - j) { throw raiseNode.raise(inliningTarget, OverflowError, ErrorMessages.RESULT_TOO_LONG); } @@ -2198,6 +2233,7 @@ static PBytesLike expandtabs(Object self, int tabsize, } } + LoopNode.reportLoopCount(inliningTarget, b.length); return create.execute(inliningTarget, self, q); } @@ -2219,16 +2255,16 @@ static PBytesLike zfill(Object self, int width, @Cached GetInternalByteArrayNode getInternalByteArrayNode, @Cached BytesNodes.CreateBytesNode create) { SequenceStorage storage = getBytesStorage.execute(inliningTarget, self); - return create.execute(inliningTarget, self, zfill(getInternalByteArrayNode.execute(inliningTarget, storage), storage.length(), width)); + return create.execute(inliningTarget, self, zfill(inliningTarget, getInternalByteArrayNode.execute(inliningTarget, storage), storage.length(), width)); } - private static byte[] zfill(byte[] self, int len, int width) { + private static byte[] zfill(Node inliningTarget, byte[] self, int len, int width) { if (len >= width) { return self; } int fill = width - len; - byte[] p = pad(self, len, fill, 0, (byte) '0'); + byte[] p = pad(inliningTarget, self, len, fill, 0, (byte) '0'); if (len == 0) { return p; @@ -2242,7 +2278,7 @@ private static byte[] zfill(byte[] self, int len, int width) { return p; } - private static byte[] pad(byte[] self, int len, int l, int r, byte fillChar) { + private static byte[] pad(Node inliningTarget, byte[] self, int len, int l, int r, byte fillChar) { int left = (l < 0) ? 0 : l; int right = (r < 0) ? 0 : r; if (left == 0 && right == 0) { @@ -2256,6 +2292,7 @@ private static byte[] pad(byte[] self, int len, int l, int r, byte fillChar) { for (int i = left, j = 0; i < (left + len); j++, i++) { u[i] = self[j]; } + LoopNode.reportLoopCount(inliningTarget, len); if (right > 0) { Arrays.fill(u, left + len, u.length, fillChar); } @@ -2311,12 +2348,14 @@ static PBytesLike remove(VirtualFrame frame, Object self, Object prefix, for (int i = 0; i < selfBsLen; i++) { if (i < prefixBsLen) { if (selfBs[i] != prefixBs[i]) { + LoopNode.reportLoopCount(node, i); return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); } } else { result[j++] = selfBs[i]; } } + LoopNode.reportLoopCount(node, selfBsLen); return create.execute(node, self, result); } return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); @@ -2352,12 +2391,14 @@ static PBytesLike remove(VirtualFrame frame, Object self, Object suffix, for (int i = selfBsLen - 1, j = 1; i >= 0; i--, j++) { if (i >= selfBsLen - suffixBsLen) { if (selfBs[i] != suffixBs[suffixBsLen - j]) { + LoopNode.reportLoopCount(node, selfBsLen - i - 1); return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); } } else { result[result.length - k++] = selfBs[i]; } } + LoopNode.reportLoopCount(node, selfBsLen); return create.execute(node, self, result); } return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java index 4b8b7233bf..e9b7eae418 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java @@ -124,6 +124,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.InternalByteArray; @@ -194,6 +195,7 @@ static byte[] join(VirtualFrame frame, Node inliningTarget, byte[] sep, Object i try { next = nextNode.execute(frame, inliningTarget, iterator); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, parts.size()); return joinArrays(sep, parts, partsTotalSize); } partsTotalSize += append(parts, toBytesNode.execute(frame, next)); @@ -706,7 +708,7 @@ public abstract static class ByteToHexNode extends PNodeWithContext { public abstract TruffleString execute(Node inliningTarget, byte[] argbuf, int arglen, byte sep, int bytesPerSepGroup); @Specialization(guards = "bytesPerSepGroup == 0") - static TruffleString zero(byte[] argbuf, int arglen, @SuppressWarnings("unused") byte sep, @SuppressWarnings("unused") int bytesPerSepGroup, + static TruffleString zero(Node inliningTarget, byte[] argbuf, int arglen, @SuppressWarnings("unused") byte sep, @SuppressWarnings("unused") int bytesPerSepGroup, @Shared @Cached TruffleString.FromByteArrayWithCompactionUTF32Node fromByteArrayNode) { int resultlen = arglen * 2; @@ -718,6 +720,7 @@ static TruffleString zero(byte[] argbuf, int arglen, @SuppressWarnings("unused") retbuf[j++] = BytesUtils.HEXDIGITS[c >>> 4]; retbuf[j++] = BytesUtils.HEXDIGITS[c & 0x0f]; } + LoopNode.reportLoopCount(inliningTarget, arglen); return fromByteArrayNode.execute(retbuf, 0, retbuf.length, TruffleString.CompactionLevel.S1, false); } @@ -739,7 +742,7 @@ static TruffleString negative(Node inliningTarget, byte[] argbuf, int arglen, by resultlen += arglen * 2; if (absBytesPerSepGroup >= arglen) { - return zero(argbuf, arglen, sep, 0, fromByteArrayNode); + return zero(inliningTarget, argbuf, arglen, sep, 0, fromByteArrayNode); } byte[] retbuf = new byte[resultlen]; @@ -758,7 +761,7 @@ static TruffleString negative(Node inliningTarget, byte[] argbuf, int arglen, by retbuf[j++] = BytesUtils.HEXDIGITS[c >>> 4]; retbuf[j++] = BytesUtils.HEXDIGITS[c & 0x0f]; } - + LoopNode.reportLoopCount(inliningTarget, arglen); return fromByteArrayNode.execute(retbuf, 0, retbuf.length, TruffleString.CompactionLevel.S1, false); } @@ -780,7 +783,7 @@ static TruffleString positive(Node inliningTarget, byte[] argbuf, int arglen, by resultlen += arglen * 2; if (absBytesPerSepGroup >= arglen) { - return zero(argbuf, arglen, sep, 0, fromByteArrayNode); + return zero(inliningTarget, argbuf, arglen, sep, 0, fromByteArrayNode); } byte[] retbuf = new byte[resultlen]; @@ -800,6 +803,7 @@ static TruffleString positive(Node inliningTarget, byte[] argbuf, int arglen, by retbuf[j--] = BytesUtils.HEXDIGITS[c & 0x0f]; retbuf[j--] = BytesUtils.HEXDIGITS[c >>> 4]; } + LoopNode.reportLoopCount(inliningTarget, arglen); return fromByteArrayNode.execute(retbuf, 0, retbuf.length, TruffleString.CompactionLevel.S1, false); } } @@ -1075,24 +1079,26 @@ protected static boolean[] createDeleteTable(byte[] delete) { for (int i = 0; i < 256; i++) { result[i] = false; } - for (byte b : delete) { - result[b & 0xFF] = true; + for (int i = 0; i < delete.length; i++) { + result[delete[i] & 0xFF] = true; } return result; } - protected static Result delete(byte[] self, byte[] table) { + protected static Result delete(Node inliningTarget, byte[] self, byte[] table) { final int length = self.length; byte[] result = new byte[length]; int resultLen = 0; boolean[] toDelete = createDeleteTable(table); - for (byte b : self) { + for (int i = 0; i < length; i++) { + byte b = self[i]; if (!toDelete[b & 0xFF]) { result[resultLen] = b; resultLen++; } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) length + table.length)); if (resultLen == length) { return new Result(result, false); } @@ -1114,14 +1120,15 @@ protected static Result translate(byte[] self, byte[] table) { return new Result(result, changed); } - protected static Result translateAndDelete(byte[] self, byte[] table, byte[] delete) { + protected static Result translateAndDelete(Node inliningTarget, byte[] self, byte[] table, byte[] delete) { final int length = self.length; byte[] result = new byte[length]; int resultLen = 0; boolean changed = false; boolean[] toDelete = createDeleteTable(delete); - for (byte value : self) { + for (int i = 0; i < length; i++) { + byte value = self[i]; int idx = value & 0xFF; if (!toDelete[idx]) { byte b = table[idx]; @@ -1132,6 +1139,7 @@ protected static Result translateAndDelete(byte[] self, byte[] table, byte[] del resultLen++; } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) length + delete.length)); if (resultLen == length) { return new Result(result, changed); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 94a8219899..4d05162c15 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -189,6 +189,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; @@ -1248,7 +1249,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } kwnamesTuplePtr = createNativeKwNamesTupleNode.execute(context, fastcallKwnames); } - long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(fastcallArgs, argToNativeNode); + LoopNode.reportLoopCount(this, fastcallArgs.length); + long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCFUNCTION_FAST_WITH_KEYWORDS(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), @@ -1330,7 +1332,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } kwnamesTuple = PFactory.createTuple(context.getLanguage(), fastcallKwnames); } - long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(fastcallArgs, argToNativeNode); + LoopNode.reportLoopCount(this, fastcallArgs.length); + long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCMETHOD(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), @@ -1394,7 +1397,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati for (int i = 0; i < args.length; i++) { promotedArgs[i] = ensurePythonObject(args[i]); } - long argsArray = createFastcallArgsArray(promotedArgs, argToNativeNode); + LoopNode.reportLoopCount(this, args.length); + long argsArray = createFastcallArgsArray(this, promotedArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCFUNCTION_FAST(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), @@ -1412,7 +1416,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati * {@code PyObject *arr[]}. This will not create new {@code PyObject *} references (i.e. * refcount is not increased). */ - static long createFastcallArgsArray(Object[] data, PythonToNativeNode argToNativeNode) { + static long createFastcallArgsArray(Node inliningTarget, Object[] data, PythonToNativeNode argToNativeNode) { if (data.length == 0) { return NULLPTR; } @@ -1422,6 +1426,7 @@ static long createFastcallArgsArray(Object[] data, PythonToNativeNode argToNativ assert EnsurePythonObjectNode.doesNotNeedPromotion(data[i]); NativeMemory.writePtrArrayElement(ptr, i, argToNativeNode.execute(data[i])); } + LoopNode.reportLoopCount(inliningTarget, data.length); return ptr; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java index afe09b08f6..00c10dc088 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java @@ -153,6 +153,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -1908,11 +1909,13 @@ static long doNative(Node inliningTarget, PythonAbstractNativeObject obj, boolea if (PythonLanguage.get(inliningTarget).getEngineOption(PythonOptions.PythonGC) && newRefcnt == MANAGED_REFCNT + 1 && obj.getReplicatedNativeReferences() != null) { hasReplicatedNativeReferences.enter(inliningTarget); - for (Object referent : obj.getReplicatedNativeReferences()) { - if (referent instanceof PythonObject pythonObject) { + Object[] referents = obj.getReplicatedNativeReferences(); + for (int i = 0; i < referents.length; i++) { + if (referents[i] instanceof PythonObject pythonObject) { updateRefNode.execute(inliningTarget, pythonObject, pythonObject.getRefCount()); } } + LoopNode.reportLoopCount(inliningTarget, referents.length); } } return obj.getPtr(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java index 608299765d..43ade28b81 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java @@ -71,6 +71,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; import com.oracle.truffle.api.nodes.Node; @@ -174,6 +175,7 @@ static int cachedLen(DynamicObjectStorage self, @Specialization(guards = {"self.cachedLength < 0", "!hasNoDeletedProperties(self)"}, replaces = "cachedLen") static int length(DynamicObjectStorage self, + @Bind Node inliningTarget, @Shared @Cached(inline = false) ReadAttributeFromPythonObjectNode readNode, @Cached DynamicObject.GetKeyArrayNode keyArrayNode) { Object[] keys = keyArrayNode.execute(self.store); @@ -181,6 +183,7 @@ static int length(DynamicObjectStorage self, for (Object key : keys) { len = incrementLen(self, readNode, len, key); } + LoopNode.reportLoopCount(inliningTarget, keys.length); return cacheLength(self, len); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java index 4eaa77eb6c..6a4992c0da 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java @@ -285,7 +285,8 @@ static EconomicMapStorage dynamicObjectStorageToEconomicMap(Node inliningTarget, Object[] keys = getKeyArrayNode.execute(store); EconomicMapStorage result = EconomicMapStorage.create(keys.length); ObjectHashMap resultMap = result; - for (Object k : keys) { + for (int i = 0; i < keys.length; i++) { + Object k = keys[i]; if (k instanceof TruffleString) { Object v = getNode.execute(store, k, PNone.NO_VALUE); if (v != PNone.NO_VALUE) { @@ -293,6 +294,7 @@ static EconomicMapStorage dynamicObjectStorageToEconomicMap(Node inliningTarget, } } } + LoopNode.reportLoopCount(inliningTarget, keys.length); return result; } @@ -1767,6 +1769,7 @@ static HashingStorage doIt(Frame frame, Node inliningTarget, PKeyword[] keywords PKeyword keyword = keywords[i]; result = setItem.execute(frame, inliningTarget, result, keyword.getName(), keyword.getValue()); } + LoopNode.reportLoopCount(inliningTarget, keywords.length); return result; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java index 1d7ea75209..32f98184fa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -59,6 +59,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; import com.oracle.truffle.api.nodes.Node; @@ -147,9 +148,11 @@ static Object notString(Frame frame, Node inliningTarget, KeywordsStorage self, TruffleString currentKey = self.keywords[i].getName(); long keyHash = hashNode.execute(frame, inliningTarget, currentKey); if (keyHash == hash && eqNode.executeEq(frame, inliningTarget, key, currentKey)) { + LoopNode.reportLoopCount(inliningTarget, i); return self.keywords[i].getValue(); } } + LoopNode.reportLoopCount(inliningTarget, self.keywords.length); return null; } } @@ -158,6 +161,7 @@ void addAllTo(Node inliningTarget, HashingStorage storage, SpecializedSetStringK for (PKeyword entry : keywords) { putNode.execute(inliningTarget, storage, entry.getName(), entry.getValue()); } + LoopNode.reportLoopCount(inliningTarget, keywords.length); } public HashingStorage copy() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java index bc65651a20..e5f6c45b92 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java @@ -683,7 +683,8 @@ protected static EmptySequenceStorage doEmpty(EmptySequenceStorage storage, int } @Specialization - protected static SequenceStorage doIntSequenceStorage(IntSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doIntSequenceStorage(IntSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { int[] newArray = new int[length]; int[] values = storage.getInternalIntArray(); @@ -695,12 +696,14 @@ protected static SequenceStorage doIntSequenceStorage(IntSequenceStorage storage for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new IntSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doLongSequenceStorage(LongSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doLongSequenceStorage(LongSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { long[] newArray = new long[length]; long[] values = storage.getInternalLongArray(); @@ -712,12 +715,14 @@ protected static SequenceStorage doLongSequenceStorage(LongSequenceStorage stora for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new LongSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doDoubleSequenceStorage(DoubleSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doDoubleSequenceStorage(DoubleSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { double[] newArray = new double[length]; double[] values = storage.getInternalDoubleArray(); @@ -729,12 +734,14 @@ protected static SequenceStorage doDoubleSequenceStorage(DoubleSequenceStorage s for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new DoubleSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doBoolSequenceStorage(BoolSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doBoolSequenceStorage(BoolSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { boolean[] newArray = new boolean[length]; boolean[] values = storage.getInternalBoolArray(); @@ -746,12 +753,14 @@ protected static SequenceStorage doBoolSequenceStorage(BoolSequenceStorage stora for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new BoolSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doByteSequenceStorage(ByteSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doByteSequenceStorage(ByteSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { byte[] newArray = new byte[length]; byte[] values = storage.getInternalByteArray(); @@ -763,12 +772,14 @@ protected static SequenceStorage doByteSequenceStorage(ByteSequenceStorage stora for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new ByteSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doObjectSequenceStorage(ObjectSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doObjectSequenceStorage(ObjectSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { Object[] newArray = new Object[length]; Object[] values = storage.getInternalObjectArray(); @@ -780,12 +791,14 @@ protected static SequenceStorage doObjectSequenceStorage(ObjectSequenceStorage s for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { PythonAbstractClass[] newArray = new PythonAbstractClass[length]; PythonAbstractClass[] values = storage.getInternalClassArray(); @@ -797,6 +810,7 @@ protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } @@ -804,17 +818,19 @@ protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage @Specialization protected static SequenceStorage doNativeInt(NativeIntSequenceStorage storage, int start, int stop, int step, int length, @Bind Node node) { - NativeBuffer sliceValueBuffer = doNativePrimitiveSliceInBound(PythonContext.get(node), start, step, length, storage); + NativeBuffer sliceValueBuffer = doNativePrimitiveSliceInBound(node, PythonContext.get(node), start, step, length, storage); return PythonContext.get(node).nativeBufferContext.createNativeIntStorage(sliceValueBuffer, length); } @Specialization - protected static SequenceStorage doNativeByte(NativeByteSequenceStorage storage, int start, @SuppressWarnings("unused") int stop, int step, int length) { + protected static SequenceStorage doNativeByte(NativeByteSequenceStorage storage, int start, @SuppressWarnings("unused") int stop, int step, int length, + @Bind Node inliningTarget) { byte[] newArray = new byte[length]; for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = readByteArrayElement(storage.getPtr(), i); } + LoopNode.reportLoopCount(inliningTarget, length); return new ByteSequenceStorage(newArray); } @@ -826,6 +842,7 @@ protected static SequenceStorage doNativeObject(NativeObjectSequenceStorage stor for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = toJavaNode.execute(inliningTarget, readPtrArrayElement(storage.getPtr(), i)); } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } @@ -837,10 +854,11 @@ protected static SequenceStorage doForeign(ForeignSequenceStorage storage, int s for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = readNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } - private static NativeBuffer doNativePrimitiveSliceInBound(PythonContext pythonCtx, int start, int step, int sliceLength, NativePrimitiveSequenceStorage storage) { + private static NativeBuffer doNativePrimitiveSliceInBound(Node inliningTarget, PythonContext pythonCtx, int start, int step, int sliceLength, NativePrimitiveSequenceStorage storage) { var unsafe = pythonCtx.getUnsafe(); long itemSize = storage.getItemSize(); long sizeInBytes = sliceLength * itemSize; @@ -857,6 +875,7 @@ private static NativeBuffer doNativePrimitiveSliceInBound(PythonContext pythonCt j = 0; j < sliceLength; srcAddr += stepInBytes, destAddr += itemSize, j++) { unsafe.copyMemory(srcAddr, destAddr, itemSize); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, sliceLength)); return sliceBuffer; } @@ -1493,6 +1512,7 @@ protected static void doOther(Node inliningTarget, SequenceStorage storage, int // otherwise copying forwards copyForward(inliningTarget, storage, getRightItemNode, setLeftItemNode, distPos, srcPos, length); } + LoopNode.reportLoopCount(inliningTarget, length); } private static void copyForward(Node inliningTarget, SequenceStorage storage, GetItemScalarNode getRightItemNode, SetItemScalarNode setLeftItemNode, int destPos, int srcPos, int length) { @@ -1551,6 +1571,7 @@ protected static void doOther(Node inliningTarget, SequenceStorage dist, int dis for (int cur = distPos, j = srcPos, i = 0; i < length; cur += 1, j++, i++) { setLeftItemNode.execute(inliningTarget, dist, cur, getRightItemNode.execute(inliningTarget, src, j)); } + LoopNode.reportLoopCount(inliningTarget, length); } protected static boolean isArrayBasedSequenceStorage(Object o) { @@ -1571,28 +1592,33 @@ static void doEmpty(@SuppressWarnings("unused") EmptySequenceStorage storage) { } @Specialization - static void doIntStorage(IntSequenceStorage storage) { + static void doIntStorage(Node inliningTarget, IntSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doDoubleStorage(DoubleSequenceStorage storage) { + static void doDoubleStorage(Node inliningTarget, DoubleSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doLongStorage(LongSequenceStorage storage) { + static void doLongStorage(Node inliningTarget, LongSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doByteStorage(ByteSequenceStorage storage) { + static void doByteStorage(Node inliningTarget, ByteSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doObjectStorage(ObjectSequenceStorage storage) { + static void doObjectStorage(Node inliningTarget, ObjectSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization @@ -1610,11 +1636,13 @@ static void doNativePrimitive(Node inliningTarget, NativePrimitiveSequenceStorag startAddress += itemSize; endAddress -= itemSize; } + LoopNode.reportLoopCount(inliningTarget, length / 2); } @Specialization - static void doBoolStorage(BoolSequenceStorage storage) { + static void doBoolStorage(Node inliningTarget, BoolSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization @@ -1645,6 +1673,7 @@ static void doForeign(Node inliningTarget, ForeignSequenceStorage storage, writeNode.execute(inliningTarget, storage, head, readNode.execute(inliningTarget, storage, tail)); writeNode.execute(inliningTarget, storage, tail, temp); } + LoopNode.reportLoopCount(inliningTarget, (length >>> 1) + (length & 1)); } } @@ -1655,7 +1684,8 @@ abstract static class ReverseNativeNode extends Node { abstract void execute(NativeSequenceStorage storage); @Specialization - static void doNativeByte(NativeByteSequenceStorage storage) { + static void doNativeByte(NativeByteSequenceStorage storage, + @Bind Node inliningTarget) { int length = storage.length(); if (length > 0) { int head = 0; @@ -1668,11 +1698,13 @@ static void doNativeByte(NativeByteSequenceStorage storage) { writeByteArrayElement(ptr, head, readByteArrayElement(ptr, tail)); writeByteArrayElement(ptr, tail, temp); } + LoopNode.reportLoopCount(inliningTarget, (length >>> 1) + (length & 1)); } } @Specialization - static void doNativeObject(NativeObjectSequenceStorage storage) { + static void doNativeObject(NativeObjectSequenceStorage storage, + @Bind Node inliningTarget) { int length = storage.length(); if (length > 0) { int head = 0; @@ -1685,6 +1717,7 @@ static void doNativeObject(NativeObjectSequenceStorage storage) { writePtrArrayElement(ptr, head, readPtrArrayElement(ptr, tail)); writePtrArrayElement(ptr, tail, temp); } + LoopNode.reportLoopCount(inliningTarget, (length >>> 1) + (length & 1)); } } } @@ -1763,6 +1796,7 @@ static void multiStep(SequenceStorage self, SliceInfo sinfo, SequenceStorage val for (int cur = start, i = 0; i < slicelen; cur += step, i++) { setLeftItemNode.execute(inliningTarget, self, cur, getRightItemNode.execute(inliningTarget, data, i)); } + LoopNode.reportLoopCount(inliningTarget, slicelen); } } @@ -2142,6 +2176,7 @@ static byte[] doNativeByte(Node inliningTarget, NativeByteSequenceStorage s, assert elem >= 0 && elem < 256; barr[i] = (byte) elem; } + LoopNode.reportLoopCount(inliningTarget, barr.length); return barr; } @@ -2167,6 +2202,7 @@ static byte[] doGeneric(Node inliningTarget, SequenceStorage s, for (int i = 0; i < barr.length; i++) { barr[i] = castToByteNode.execute(inliningTarget, getItemNode.execute(inliningTarget, s, i)); } + LoopNode.reportLoopCount(inliningTarget, barr.length); return barr; } } @@ -2311,6 +2347,7 @@ static SequenceStorage doGenericInplace(@SuppressWarnings("unused") SequenceStor for (int i = 0; i < len2; i++) { initializeItemNode.execute(inliningTarget, left, i + len1, getItemRightNode.execute(inliningTarget, right, i)); } + LoopNode.reportLoopCount(inliningTarget, len2); setLenNode.execute(inliningTarget, left, len1 + len2); return left; } @@ -2330,6 +2367,7 @@ static SequenceStorage doGeneric(SequenceStorage dest, SequenceStorage left, Seq for (int i = 0; i < len2; i++) { initializeItemNode.execute(inliningTarget, dest, i + len1, getItemRightNode.execute(inliningTarget, right, i)); } + LoopNode.reportLoopCount(inliningTarget, len1 + len2); setLenNode.execute(inliningTarget, dest, len1 + len2); return dest; } @@ -2608,7 +2646,7 @@ SequenceStorage doArrayBasedManaged(ArrayBasedSequenceStorage s, int times, int newLength = PythonUtils.multiplyExact(len, times); ArrayBasedSequenceStorage repeated = profiled.createEmpty(newLength); Object destArr = repeated.getInternalArrayObject(); - repeat(destArr, arr1, len, times); + repeat(inliningTarget, destArr, arr1, len, times); repeated.setNewLength(newLength); return repeated; } catch (OutOfMemoryError e) { @@ -2635,6 +2673,7 @@ SequenceStorage doGeneric(SequenceStorage s, int times, for (int i = 0; i < len; i++) { setItemNode.execute(inliningTarget, repeated, i, getItemNode.execute(inliningTarget, s, i)); } + LoopNode.reportLoopCount(inliningTarget, len); // read from destination since that is potentially faster for (int j = 1; j < times; j++) { @@ -2642,6 +2681,8 @@ SequenceStorage doGeneric(SequenceStorage s, int times, setItemNode.execute(inliningTarget, repeated, j * len + i, getDestItemNode.execute(inliningTarget, repeated, i)); } } + LoopNode.reportLoopCount(inliningTarget, times - 1); + LoopNode.reportLoopCount(inliningTarget, newLen - len); repeated.setNewLength(newLen); return repeated; @@ -2652,10 +2693,11 @@ SequenceStorage doGeneric(SequenceStorage s, int times, } } - private static void repeat(Object dest, Object src, int len, int times) { + private static void repeat(Node inliningTarget, Object dest, Object src, int len, int times) { for (int i = 0; i < times; i++) { PythonUtils.arraycopy(src, 0, dest, i * len, len); } + LoopNode.reportLoopCount(inliningTarget, times); } protected static boolean isInt(Object times) { @@ -2708,18 +2750,24 @@ public static int doByteStorage(ByteSequenceStorage s, byte item) { } @Specialization - public static int doIntStorage(IntSequenceStorage s, int item) { - return s.indexOfInt(item); + public static int doIntStorage(Node inliningTarget, IntSequenceStorage s, int item) { + int index = s.indexOfInt(item); + LoopNode.reportLoopCount(inliningTarget, index < 0 ? s.length() : index + 1); + return index; } @Specialization - public static int doLongStorage(LongSequenceStorage s, long item) { - return s.indexOfLong(item); + public static int doLongStorage(Node inliningTarget, LongSequenceStorage s, long item) { + int index = s.indexOfLong(item); + LoopNode.reportLoopCount(inliningTarget, index < 0 ? s.length() : index + 1); + return index; } @Specialization - public static int doDoubleStorage(DoubleSequenceStorage s, double item) { - return s.indexOfDouble(item); + public static int doDoubleStorage(Node inliningTarget, DoubleSequenceStorage s, double item) { + int index = s.indexOfDouble(item); + LoopNode.reportLoopCount(inliningTarget, index < 0 ? s.length() : index + 1); + return index; } @Specialization @@ -3330,21 +3378,23 @@ static SequenceStorage doNativeInt(Node inliningTarget, NativeIntSequenceStorage } @Specialization - static SequenceStorage doNativeBytes(NativeByteSequenceStorage s) { + static SequenceStorage doNativeBytes(Node inliningTarget, NativeByteSequenceStorage s) { byte[] bytes = new byte[s.length()]; for (int i = 0; i < bytes.length; i++) { bytes[i] = (byte) GetNativeItemScalarNode.doNativeByte(s, i); } + LoopNode.reportLoopCount(inliningTarget, bytes.length); return new ByteSequenceStorage(bytes); } @Specialization - static SequenceStorage doNativeObjects(NativeObjectSequenceStorage s, + static SequenceStorage doNativeObjects(Node inliningTarget, NativeObjectSequenceStorage s, @Cached(inline = false) GetNativeItemScalarNode getItem) { Object[] objects = new Object[s.length()]; for (int i = 0; i < objects.length; i++) { objects[i] = getItem.execute(s, i); } + LoopNode.reportLoopCount(inliningTarget, objects.length); return new ObjectSequenceStorage(objects); } @@ -3355,6 +3405,7 @@ static SequenceStorage doForeign(Node inliningTarget, ForeignSequenceStorage s, for (int i = 0; i < objects.length; i++) { objects[i] = readNode.execute(inliningTarget, s, i); } + LoopNode.reportLoopCount(inliningTarget, objects.length); return new ObjectSequenceStorage(objects); } } @@ -3372,23 +3423,23 @@ public static Object[] executeUncached(SequenceStorage s) { } @Specialization - static Object[] doInt(IntSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doInt(Node inliningTarget, IntSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization - static Object[] doDouble(DoubleSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doDouble(Node inliningTarget, DoubleSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization - static Object[] doByte(ByteSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doByte(Node inliningTarget, ByteSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization - static Object[] doLong(LongSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doLong(Node inliningTarget, LongSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization @@ -3397,8 +3448,8 @@ static Object[] doObject(ObjectSequenceStorage storage) { } @Specialization - static Object[] doBool(BoolSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doBool(Node inliningTarget, BoolSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization @@ -3412,12 +3463,13 @@ static Object[] doEmpty(@SuppressWarnings("unused") EmptySequenceStorage s) { } @Specialization - static Object[] doNative(NativeSequenceStorage s, + static Object[] doNative(Node inliningTarget, NativeSequenceStorage s, @Cached(inline = false) GetNativeItemScalarNode getNativeItemScalarNode) { Object[] result = new Object[s.length()]; for (int i = 0; i < s.length(); i++) { result[i] = getNativeItemScalarNode.execute(s, i); } + LoopNode.reportLoopCount(inliningTarget, result.length); return result; } } @@ -3704,6 +3756,7 @@ static void multipleSteps(SequenceStorage self, SliceInfo sinfo, memove.execute(inliningTarget, self, cur - i, cur + 1, lim); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, slicelen)); /*- Move the tail of the bytes, in one chunk */ cur = start + slicelen * step; if (cur < len) { @@ -3898,6 +3951,7 @@ private static Object[] materializeGeneric(Node inliningTarget, SequenceStorage for (int i = 0; i < barr.length; i++) { barr[i] = getItemNode.execute(inliningTarget, s, i); } + LoopNode.reportLoopCount(inliningTarget, barr.length); return barr; } @@ -4092,6 +4146,7 @@ protected static SequenceStorage doNativeObjectStorage(Node inliningTarget, Nati for (int i = storage.length(); i > index; i--) { writePtrArrayElement(storage.getPtr(), i, readPtrArrayElement(storage.getPtr(), i - 1)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) storage.length() - index))); Object promoted = ensurePythonObjectNode.execute(PythonContext.get(inliningTarget), value, false); writePtrArrayElement(storage.getPtr(), index, toNative.executeNewRef(inliningTarget, promoted)); storage.setNewLength(newLength); @@ -4107,6 +4162,7 @@ protected static SequenceStorage doNativeByteStorage(Node inliningTarget, Native for (int i = storage.length(); i > index; i--) { writeByteArrayElement(storage.getPtr(), i, readByteArrayElement(storage.getPtr(), i - 1)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) storage.length() - index))); writeByteArrayElement(storage.getPtr(), index, castToByteNode.execute(null, value)); storage.setNewLength(newLength); return storage; @@ -4259,7 +4315,7 @@ private SequenceStorage createStorageUninitialized(VirtualFrame frame, Node inli value = nextNode.execute(frame, inliningTarget, iterator); } catch (IteratorExhausted e) { LoopNode.reportLoopCount(this, i); - return SequenceStorageFactory.createStorage(PythonUtils.arrayCopyOf(elements, i)); + return SequenceStorageFactory.createStorage(inliningTarget, PythonUtils.arrayCopyOf(elements, i)); } if (i >= elements.length) { // Intentionally not profiled, because "size" can be reprofiled after this diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java index 65fe319642..f57858bfe1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java @@ -300,6 +300,7 @@ void sort(VirtualFrame frame, SequenceStorage storage, Object keyfunc, boolean r for (int i = 0; i < len; i++) { array[i] = getItemScalarNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, len); if (keyfunc instanceof PNone) { sortWithoutKey(frame, array, len, reverse, callContext); } else { @@ -308,6 +309,7 @@ void sort(VirtualFrame frame, SequenceStorage storage, Object keyfunc, boolean r for (int i = 0; i < len; i++) { setItemScalarNode.execute(inliningTarget, storage, i, array[i]); } + LoopNode.reportLoopCount(inliningTarget, len); } private void sortWithoutKey(VirtualFrame frame, Object[] array, int len, boolean reverse, CallContext callContext) { @@ -421,6 +423,7 @@ private void sortWithKey(VirtualFrame frame, Object[] array, int len, Object key } pairArray[reverse ? len - i - 1 : i] = new SortingPair(key, array[i]); } + LoopNode.reportLoopCount(this, len - 1); if (keySortComparator != null) { callSortWithKey(pairArray, len, keySortComparator); } else { @@ -449,6 +452,7 @@ private void sortWithKey(VirtualFrame frame, Object[] array, int len, Object key for (int i = 0; i < len; i++) { array[reverse ? len - i - 1 : i] = pairArray[i].value; } + LoopNode.reportLoopCount(this, len); } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java index eea0ba1d95..c5b498b3c0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java @@ -130,6 +130,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -320,6 +321,7 @@ int doGeneric(VirtualFrame frame, PDeque self, Object value, throw PRaiseNode.raiseStatic(this, RuntimeError, ErrorMessages.DEQUE_MUTATED_DURING_ITERATION); } } + LoopNode.reportLoopCount(inliningTarget, self.getSize()); return n; } } @@ -430,6 +432,7 @@ static int doWithIntSlice(VirtualFrame frame, PDeque self, Object value, int sta Object item = next(iterator); if (normStart <= idx) { if (eqNode.execute(frame, inliningTarget, item, value, RichCmpOp.Py_EQ)) { + LoopNode.reportLoopCount(inliningTarget, idx + 1); return idx; } if (startState != self.getState()) { @@ -572,6 +575,7 @@ Object doGeneric(VirtualFrame frame, PDeque self, Object value, Object removed = self.popLeft(); assert removed != null; DequeRotateNode.doRight(self, i); + LoopNode.reportLoopCount(inliningTarget, i + 1); return PNone.NONE; } else { // this is basically 'DequeRotateNode.doLeft(self, -1)' diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.java index 5ee9041776..f2c0b6cc5c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.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 @@ -67,6 +67,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -100,8 +101,13 @@ static PDequeIter doGeneric(VirtualFrame frame, @SuppressWarnings("unused") Obje PDequeIter dequeIter = PFactory.createDequeIter(language, (PDeque) deque); if (indexNoneProfile.profile(inliningTarget, indexObj != PNone.NO_VALUE)) { int index = castToJavaIntExactNode.execute(inliningTarget, toIndexNode.execute(frame, inliningTarget, indexObj)); - for (int i = 0; i < index; i++) { - getNextNode.execute(dequeIter); + int i = 0; + try { + for (; i < index; i++) { + getNextNode.execute(dequeIter); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } } return dequeIter; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java index 9918a13f9c..361d4164ed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -67,6 +67,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -100,8 +101,13 @@ static PDequeIter doGeneric(VirtualFrame frame, @SuppressWarnings("unused") Obje PDequeIter dequeIter = PFactory.createDequeRevIter(language, (PDeque) deque); if (indexNoneProfile.profile(inliningTarget, indexObj != PNone.NO_VALUE)) { int index = castToJavaIntExactNode.execute(inliningTarget, toIndexNode.execute(frame, inliningTarget, indexObj)); - for (int i = 0; i < index; i++) { - getNextNode.execute(dequeIter); + int i = 0; + try { + for (; i < index; i++) { + getNextNode.execute(dequeIter); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } } return dequeIter; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java index 5add0517ba..b31b48637a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java @@ -111,6 +111,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -196,6 +197,7 @@ static PBaseExceptionGroup doManaged(VirtualFrame frame, Object cls, Object mess throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ITEM_D_OF_SECOND_ARGUMENT_EXCEPTIONS_IS_NOT_AN_EXCEPTION, i); } } + LoopNode.reportLoopCount(inliningTarget, exceptions.length); if (isSameTypeNode.execute(inliningTarget, cls, PythonBuiltinClassType.PBaseExceptionGroup)) { if (!nestedBaseExceptions) { /* diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java index 0c1d2072c0..163c7ffd49 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java @@ -45,7 +45,7 @@ import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; -public class PBaseExceptionGroup extends PBaseException { +public final class PBaseExceptionGroup extends PBaseException { private final TruffleString message; private final Object[] exceptions; private PException parent; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java index 8a25b39ce5..858b8102b5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java @@ -116,6 +116,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.object.Shape; @@ -1050,11 +1051,13 @@ static PTuple get(Object selfObj, ++exponent; mantissa /= 2; } + LoopNode.reportLoopCount(inliningTarget, exponent); } else if (mantissa < 0.5) { while (mantissa < 0.5) { --exponent; mantissa *= 2; } + LoopNode.reportLoopCount(inliningTarget, -exponent); } if (neg) { mantissa = -mantissa; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java index 423c5d4b8e..1bde08c560 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java @@ -92,6 +92,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -317,6 +318,7 @@ protected Object doIt(VirtualFrame frame, Object object, memberString = switchEncodingNode.execute(memberString, TS_ENCODING); addNode.execute(frame, attributes, memberString); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, size))); } catch (UnsupportedMessageException | InvalidArrayIndexException e) { throw CompilerDirectives.shouldNotReachHere(e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java index 10dd053c17..149bb989f3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java @@ -164,12 +164,14 @@ private static PDict snapshot(PFrameLocalsProxy self, PythonLanguage language, N PDict result = PFactory.createDict(language); BytecodeFrame bytecodeFrame = self.getBytecodeFrame(); BytecodeDSLFrameInfo info = bytecodeFrame == null ? null : (BytecodeDSLFrameInfo) bytecodeFrame.getFrameDescriptorInfo(); - for (int i = 0; info != null && i < info.getVariableCount(); i++) { + int varCount = info == null ? 0 : info.getVariableCount(); + for (int i = 0; i < varCount; i++) { Object value = getSlotValue(self, i); if (value != null) { result.setDictStorage(setItem.execute(inliningTarget, result.getDictStorage(), info.getVariableName(i), value)); } } + LoopNode.reportLoopCount(inliningTarget, varCount); PDict extra = self.getFrame().getExtraLocals(); if (extra != null) { result.update(extra); @@ -289,11 +291,13 @@ private static int count(PFrameLocalsProxy self, Node inliningTarget, HashingSto int count = 0; BytecodeFrame bytecodeFrame = self.getBytecodeFrame(); BytecodeDSLFrameInfo info = bytecodeFrame == null ? null : (BytecodeDSLFrameInfo) bytecodeFrame.getFrameDescriptorInfo(); - for (int i = 0; info != null && i < info.getVariableCount(); i++) { + int varCount = info == null ? 0 : info.getVariableCount(); + for (int i = 0; i < varCount; i++) { if (getSlotValue(self, i) != null) { count++; } } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, varCount)); PDict extra = self.getFrame().getExtraLocals(); return count + (extra == null ? 0 : storageLen.execute(inliningTarget, extra.getDictStorage())); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java index 921d1ec4ab..34c53e7714 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java @@ -98,6 +98,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; @@ -358,6 +359,7 @@ static Object[] doString(Object iterableObj, // TODO: GR-37219: use SubstringNode with lazy=true? result[i++] = fromCodePointNode.execute(nextNode.execute(it, TS_ENCODING), TS_ENCODING, true); } + LoopNode.reportLoopCount(inliningTarget, result.length); return result; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.java index 563041a21f..615e340608 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.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. @@ -151,13 +151,18 @@ static Object doNext(VirtualFrame frame, PZip self, @Cached CallSlotTpIterNextNode callIterNext) { Object[] iterators = self.getIterators(); Object[] tupleElements = new Object[iterators.length]; - for (int i = 0; i < iterators.length; i++) { - Object it = iterators[i]; - /* - * Not using PyIterNext because the non-strict version should pass through existing - * StopIteration - */ - tupleElements[i] = callIterNext.execute(frame, inliningTarget, getSlots.execute(inliningTarget, it).tp_iternext(), it); + int i = 0; + try { + for (; i < iterators.length; i++) { + Object it = iterators[i]; + /* + * Not using PyIterNext because the non-strict version should pass through existing + * StopIteration + */ + tupleElements[i] = callIterNext.execute(frame, inliningTarget, getSlots.execute(inliningTarget, it).tp_iternext(), it); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return PFactory.createTuple(language, tupleElements); } @@ -175,6 +180,7 @@ static Object doNext(VirtualFrame frame, PZip self, try { tupleElements[i] = nextNode.execute(frame, inliningTarget, iterators[i]); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, i + 1); if (i > 0) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.ZIP_ARG_D_IS_SHORTER_THEN_ARG_SD, i + 1, i == 1 ? " " : "s 1-", i); } @@ -189,6 +195,7 @@ static Object doNext(VirtualFrame frame, PZip self, throw e; } } + LoopNode.reportLoopCount(inliningTarget, iterators.length); return PFactory.createTuple(language, tupleElements); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java index 0ce339cc57..0ece90105d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java @@ -73,6 +73,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.PBatched) @@ -140,32 +141,36 @@ static Object next(VirtualFrame frame, PBatched bo, if (bo.it == null) { throw raiseNode.raiseStopIteration(inliningTarget, null); } - int i; + int i = 0; int n = bo.batchSize; Object it = bo.it; Object[] items = new Object[n]; - for (i = 0; i < n; i++) { - try { + try { + for (; i < n; i++) { try { - items[i] = nextNode.execute(frame, inliningTarget, it); - } catch (IteratorExhausted e) { - if (i == 0) { - bo.it = null; - return TpIterNextBuiltin.iteratorExhausted(); + try { + items[i] = nextNode.execute(frame, inliningTarget, it); + } catch (IteratorExhausted e) { + if (i == 0) { + bo.it = null; + return TpIterNextBuiltin.iteratorExhausted(); + } + if (bo.isStrict()) { + bo.it = null; + throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BATCHED_INCOMPLETE_BATCH); + } + items = PythonUtils.arrayCopyOf(items, i); + break; } - if (bo.isStrict()) { - bo.it = null; - throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BATCHED_INCOMPLETE_BATCH); - } - items = PythonUtils.arrayCopyOf(items, i); - break; + } catch (PException e) { + /* Handle input raised an exception other than StopIteration */ + bo.it = null; + throw e; } - } catch (PException e) { - /* Handle input raised an exception other than StopIteration */ - bo.it = null; - throw e; } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return PFactory.createTuple(language, items); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java index d42d9186d9..42a4a7335e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java @@ -91,6 +91,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; @@ -142,6 +143,7 @@ static Object construct(VirtualFrame frame, Object cls, Object iterable, int r, for (int i = 0; indicesLoopProfile.inject(i < r); i++) { indices[i] = i; } + LoopNode.reportLoopCount(inliningTarget, r); self.setIndices(indices); self.setR(r); self.setLastResult(null); @@ -182,6 +184,7 @@ static Object nextNoResult(PAbstractCombinations self, int idx = self.getIndices()[i]; result[i] = self.getPool()[idx]; } + LoopNode.reportLoopCount(inliningTarget, result.length); self.setLastResult(result); return PFactory.createTuple(language, result); } @@ -216,6 +219,7 @@ private static Object nextInternal(Node inliningTarget, PAbstractCombinations se while (i >= 0 && self.getIndices()[i] == self.getMaximum(poolLen, i)) { i -= 1; } + LoopNode.reportLoopCount(inliningTarget, (int) ((long) self.getR() - i - 1)); // If i is negative, then the indices are all at their maximum value and we're done if (i < 0) { @@ -230,6 +234,7 @@ private static Object nextInternal(Node inliningTarget, PAbstractCombinations se for (int j = i + 1; indexLoopProfile.inject(inliningTarget, j < self.getR()); j++) { self.getIndices()[j] = self.maxIndex(j); } + LoopNode.reportLoopCount(inliningTarget, self.getR() - i - 1); // Update the result for the new indices starting with i, the leftmost index that // changed @@ -239,6 +244,7 @@ private static Object nextInternal(Node inliningTarget, PAbstractCombinations se Object elem = self.getPool()[index]; result[j] = elem; } + LoopNode.reportLoopCount(inliningTarget, self.getR() - i); self.setLastResult(result); return PFactory.createTuple(PythonLanguage.get(inliningTarget), result); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.java index c37d68f1a9..afbcb5ccb3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.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 @@ -221,29 +221,36 @@ static Object next(PPermutations self, for (int i = 0; resultLoopProfile.inject(inliningTarget, i < r); i++) { result[i] = pool[indices[i]]; } + LoopNode.reportLoopCount(inliningTarget, r); int[] cycles = self.getCycles(); int i = r - 1; - while (mainLoopProfile.profile(inliningTarget, i >= 0)) { - int j = cycles[i] - 1; - if (j > 0) { - jProfile.enter(inliningTarget); - cycles[i] = j; - int tmp = indices[i]; - indices[i] = indices[indices.length - j]; - indices[indices.length - j] = tmp; - return PFactory.createTuple(language, result); - } - cycles[i] = indices.length - i; - int n1 = indices.length - 1; - assert n1 >= 0; - int num = indices[i]; - shiftIndicesProfile.profileCounted(inliningTarget, n1 - i); - for (int k = i; shiftIndicesProfile.profile(inliningTarget, k < n1); k++) { - indices[k] = indices[k + 1]; + try { + while (mainLoopProfile.profile(inliningTarget, i >= 0)) { + int j = cycles[i] - 1; + if (j > 0) { + jProfile.enter(inliningTarget); + cycles[i] = j; + int tmp = indices[i]; + indices[i] = indices[indices.length - j]; + indices[indices.length - j] = tmp; + return PFactory.createTuple(language, result); + } + cycles[i] = indices.length - i; + int n1 = indices.length - 1; + assert n1 >= 0; + int num = indices[i]; + shiftIndicesProfile.profileCounted(inliningTarget, n1 - i); + for (int k = i; shiftIndicesProfile.profile(inliningTarget, k < n1); k++) { + indices[k] = indices[k + 1]; + } + indices[n1] = num; + i = i - 1; } - indices[n1] = num; - i = i - 1; + } finally { + // approximation + long iterations = 2 * (r - 1L - i) * (indices.length - r); + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, iterations)); } self.setStopped(true); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java index 201ba903be..ca224a80aa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java @@ -115,7 +115,7 @@ static Object constructNoneRepeat(VirtualFrame frame, Object cls, Object[] itera @SuppressWarnings("unused") @Cached.Shared("typeNode") @Cached TypeNodes.IsTypeNode isTypeNode, @Cached.Shared @Cached TypeNodes.GetInstanceShape getInstanceShape) { PProduct self = PFactory.createProduct(cls, getInstanceShape.execute(cls)); - constructOneRepeat(frame, self, iterables, toArrayNode); + constructOneRepeat(frame, inliningTarget, self, iterables, toArrayNode); return self; } @@ -145,27 +145,27 @@ static Object constructRepeat(VirtualFrame frame, Object cls, Object[] iterables self.setStopped(false); } else if (repeatInt == 1) { oneProfile.enter(inliningTarget); - constructOneRepeat(frame, self, iterables, toArrayNode); + constructOneRepeat(frame, inliningTarget, self, iterables, toArrayNode); } else { genericProfile.enter(inliningTarget); - Object[][] lists = unpackIterables(frame, iterables, toArrayNode); + Object[][] lists = unpackIterables(frame, inliningTarget, iterables, toArrayNode); Object[][] gears = new Object[lists.length * repeatInt][]; loopProfile.profileCounted(inliningTarget, repeatInt); LoopNode.reportLoopCount(inliningTarget, repeatInt); for (int i = 0; loopProfile.inject(inliningTarget, i < repeatInt); i++) { PythonUtils.arraycopy(lists, 0, gears, i * lists.length, lists.length); } - construct(self, gears); + construct(inliningTarget, self, gears); } return self; } - private static void constructOneRepeat(VirtualFrame frame, PProduct self, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { - Object[][] gears = unpackIterables(frame, iterables, toArrayNode); - construct(self, gears); + private static void constructOneRepeat(VirtualFrame frame, Node inliningTarget, PProduct self, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { + Object[][] gears = unpackIterables(frame, inliningTarget, iterables, toArrayNode); + construct(inliningTarget, self, gears); } - private static void construct(PProduct self, Object[][] gears) { + private static void construct(Node inliningTarget, PProduct self, Object[][] gears) { self.setGears(gears); for (int i = 0; i < gears.length; i++) { if (gears[i].length == 0) { @@ -175,16 +175,18 @@ private static void construct(PProduct self, Object[][] gears) { return; } } + LoopNode.reportLoopCount(inliningTarget, gears.length); self.setIndices(new int[gears.length]); self.setLst(null); self.setStopped(false); } - private static Object[][] unpackIterables(VirtualFrame frame, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { + private static Object[][] unpackIterables(VirtualFrame frame, Node inliningTarget, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { Object[][] lists = new Object[iterables.length][]; for (int i = 0; i < lists.length; i++) { lists[i] = toArrayNode.execute(frame, iterables[i]); } + LoopNode.reportLoopCount(inliningTarget, lists.length); return lists; } @@ -220,6 +222,7 @@ static Object next(PProduct self, for (int i = 0; loopProfile.inject(inliningTarget, i < lst.length); i++) { lst[i] = self.getGears()[i][0]; } + LoopNode.reportLoopCount(inliningTarget, lst.length); self.setLst(lst); return PFactory.createTuple(language, lst); } @@ -275,19 +278,23 @@ private static void rotatePreviousGear(Node inliningTarget, PProduct self, Inlin indices[x] = 0; x = x - 1; // the outer loop runs as long as we have a carry - while (loopProfile.profile(inliningTarget, x >= 0)) { - Object[] gear = gears[x]; - int index = indices[x] + 1; - if (index < gear.length) { - // no carry: done - doneProfile.enter(inliningTarget); - lst[x] = gear[index]; - indices[x] = index; - return; + try { + while (loopProfile.profile(inliningTarget, x >= 0)) { + Object[] gear = gears[x]; + int index = indices[x] + 1; + if (index < gear.length) { + // no carry: done + doneProfile.enter(inliningTarget); + lst[x] = gear[index]; + indices[x] = index; + return; + } + lst[x] = gear[0]; + indices[x] = 0; + x = x - 1; } - lst[x] = gear[0]; - indices[x] = 0; - x = x - 1; + } finally { + LoopNode.reportLoopCount(inliningTarget, gears.length - 2 - x); } self.setLst(null); self.setStopped(true); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.java index 7ef9362f44..192306692d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.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 @@ -163,28 +163,33 @@ static Object next(VirtualFrame frame, PZipLongest self, Object fillValue = isNullFillProfile.profile(inliningTarget, isNullFillValue(self)) ? PNone.NONE : self.getFillValue(); Object[] result = new Object[self.getItTuple().length]; loopProfile.profileCounted(inliningTarget, result.length); - for (int i = 0; loopProfile.inject(inliningTarget, i < result.length); i++) { - Object it = self.getItTuple()[i]; - Object item; - if (noItProfile.profile(inliningTarget, it == PNone.NONE)) { - item = fillValue; - } else { - try { - item = nextNode.execute(frame, inliningTarget, it); - } catch (IteratorExhausted e) { - self.setNumActive(self.getNumActive() - 1); - if (noActiveProfile.profile(inliningTarget, self.getNumActive() == 0)) { - throw iteratorExhausted(); - } else { - item = fillValue; - self.getItTuple()[i] = PNone.NONE; + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < result.length); i++) { + Object it = self.getItTuple()[i]; + Object item; + if (noItProfile.profile(inliningTarget, it == PNone.NONE)) { + item = fillValue; + } else { + try { + item = nextNode.execute(frame, inliningTarget, it); + } catch (IteratorExhausted e) { + self.setNumActive(self.getNumActive() - 1); + if (noActiveProfile.profile(inliningTarget, self.getNumActive() == 0)) { + throw iteratorExhausted(); + } else { + item = fillValue; + self.getItTuple()[i] = PNone.NONE; + } + } catch (PException e) { + self.setNumActive(0); + throw e; } - } catch (PException e) { - self.setNumActive(0); - throw e; } + result[i] = item; } - result[i] = item; + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return PFactory.createTuple(PythonLanguage.get(inliningTarget), result); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java index b699d11c46..ccc2edb21b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java @@ -225,6 +225,7 @@ public TruffleString repr(VirtualFrame frame, Object self, Object value = getItem.execute(storage, index); appendStringNode.execute(buf, reprNode.execute(frame, inliningTarget, value)); } + LoopNode.reportLoopCount(inliningTarget, length); appendStringNode.execute(buf, T_RBRACKET); return toStringNode.execute(buf); } finally { @@ -260,6 +261,7 @@ static PNone listRange(PList list, PIntRange range, array[i] = value; value += step; } + LoopNode.reportLoopCount(inliningTarget, len); list.setSequenceStorage(new IntSequenceStorage(array)); return PNone.NONE; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java index f83a46fc57..39fdea5365 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -77,6 +77,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; @@ -115,6 +116,7 @@ static PMap doit(VirtualFrame frame, Object cls, Object[] args, PKeyword[] keywo for (int i = 0; loopProfile.inject(inliningTarget, i < iterators.length); i++) { iterators[i] = getIter.execute(frame, inliningTarget, args[i + 1]); } + LoopNode.reportLoopCount(inliningTarget, iterators.length); map.setIterators(iterators); return map; } @@ -145,10 +147,15 @@ static Object doNext(VirtualFrame frame, PMap self, Object[] iterators = self.getIterators(); Object[] arguments = new Object[iterators.length]; loopProfile.profileCounted(inliningTarget, iterators.length); - for (int i = 0; loopProfile.inject(inliningTarget, i < iterators.length); i++) { - Object iterator = iterators[i]; - TpSlot iternext = getSlots.execute(inliningTarget, iterator).tp_iternext(); - arguments[i] = callTpIternext.execute(frame, inliningTarget, iternext, iterator); + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < iterators.length); i++) { + Object iterator = iterators[i]; + TpSlot iternext = getSlots.execute(inliningTarget, iterator).tp_iternext(); + arguments[i] = callTpIternext.execute(frame, inliningTarget, iternext, iterator); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return callNode.execute(frame, self.getFunction(), arguments); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java index b68a8c7486..3b1bc39d04 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java @@ -129,6 +129,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -301,6 +302,7 @@ static void setitem(VirtualFrame frame, PMemoryView self, PSlice slice, Object o MemoryViewNodes.MemoryPointer destPtr = pointerLookupNode.execute(frame, destView, i); writeBytesAtNode.execute(inliningTarget, srcBytes, i * itemsize, itemsize, self, destPtr.ptr, destPtr.offset); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, destView.getBufferShape()[0])); } finally { releaseNode.execute(frame, destView); } @@ -688,6 +690,7 @@ private static int[] shapeFromStorage(VirtualFrame frame, Node inliningTarget, S throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.MEMORYVIEW_CAST_ELEMENTS_MUST_BE_POSITIVE_INTEGERS); } } + LoopNode.reportLoopCount(inliningTarget, ndim); return shape; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java index 2fcbda6741..d259aca3b5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java @@ -90,6 +90,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedIntValueProfile; @@ -130,7 +131,7 @@ public static int executeUncached(int ndim, int itemsize, int[] shape, int[] str } @Specialization - static int compute(int ndim, int itemsize, int[] shape, int[] strides, int[] suboffsets) { + static int compute(Node inliningTarget, int ndim, int itemsize, int[] shape, int[] strides, int[] suboffsets) { if (ndim == 0) { return PMemoryView.FLAG_C | PMemoryView.FLAG_FORTRAN | PMemoryView.FLAG_SCALAR; } else if (suboffsets != null) { @@ -146,6 +147,7 @@ static int compute(int ndim, int itemsize, int[] shape, int[] strides, int[] sub } expectedStride *= dim; } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, ndim)); expectedStride = itemsize; for (int i = 0; i < ndim; i++) { int dim = shape[i]; @@ -155,6 +157,7 @@ static int compute(int ndim, int itemsize, int[] shape, int[] strides, int[] sub } expectedStride *= dim; } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, ndim)); return flags; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index 0134458d6e..f9f8367d5c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -154,6 +154,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -572,6 +573,7 @@ static void doSlice(VirtualFrame frame, PMMap self, PSlice slice, Object valueOb for (int cur = info.start, i = 0; i < info.sliceLength; cur += info.step, i++) { posixSupportLib.mmapWriteByte(context.getPosixSupport(), self.getPosixSupportHandle(), cur, bufferLib.readByte(buffer, i)); } + LoopNode.reportLoopCount(inliningTarget, info.sliceLength); } } catch (PosixException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, ex); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java index cdc8d373fa..d6fc757b50 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java @@ -110,6 +110,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.strings.TruffleString; @@ -180,6 +181,7 @@ static Object init(VirtualFrame frame, PSimpleNamespace self, Object[] args, PKe for (PKeyword keyword : kwargs) { writeAttrNode.execute(self, keyword.getName(), keyword.getValue()); } + LoopNode.reportLoopCount(inliningTarget, kwargs.length); return PNone.NONE; } } @@ -248,8 +250,9 @@ static Object replace(VirtualFrame frame, PSimpleNamespace self, @SuppressWarnin if (!(resultObject instanceof PSimpleNamespace result)) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.SIMPLE_NAMESPACE_REPLACE_WRONG_TYPE, self, resultObject); } - for (Object key : getKeyArrayNode.execute(self)) { - if (key instanceof TruffleString name) { + Object[] keys = getKeyArrayNode.execute(self); + for (int i = 0; i < keys.length; i++) { + if (keys[i] instanceof TruffleString name) { Object value = readAttrNode.execute(inliningTarget, self, name, PNone.NO_VALUE); if (value != PNone.NO_VALUE) { writeAttrNode.execute(result, name, value); @@ -259,6 +262,7 @@ static Object replace(VirtualFrame frame, PSimpleNamespace self, @SuppressWarnin for (PKeyword change : changes) { writeAttrNode.execute(result, change.getName(), change.getValue()); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) keys.length + changes.length)); return result; } } @@ -296,6 +300,7 @@ public void appendToTruffleStringBuilder(TruffleStringBuilderUTF32 sb, TruffleSt appendStringNode.execute(sb, T_EQ); appendStringNode.execute(sb, item.getRight()); } + LoopNode.reportLoopCount(appendStringNode, items.size()); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java index fb01ce9774..eb488a5cbb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java @@ -161,6 +161,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -582,6 +583,7 @@ static Object getstate(VirtualFrame frame, Node inliningTarget, Object obj, bool haveSlots = true; } } + LoopNode.reportLoopCount(inliningTarget, slotnames.length); if (haveSlots) { /* * If we found some slot attributes, pack them in a tuple along the original @@ -705,6 +707,7 @@ static Object reduceNewObj(VirtualFrame frame, Node inliningTarget, Object obj, for (int i = 0; i < argsLen; i++) { newargsVals[i + 1] = getItemNode.execute(frame, inliningTarget, args, i); } + LoopNode.reportLoopCount(inliningTarget, argsLen); } else { newargsVals = new Object[]{cls}; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java index 5dc13a4b3a..98eb90a514 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java @@ -132,6 +132,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -356,6 +357,7 @@ static void update(VirtualFrame frame, Node inliningTarget, Object self, Object throw raiseNode.raise(inliningTarget, RuntimeError, ErrorMessages.MUTATED_DURING_UPDATE, "dict"); } } + LoopNode.reportLoopCount(inliningTarget, initialSize); } else { Object keysAttribute = lookupKeys.execute(frame, inliningTarget, mapping, T_KEYS); if (keysAttribute != PNone.NO_VALUE) { @@ -368,6 +370,7 @@ static void update(VirtualFrame frame, Node inliningTarget, Object self, Object for (PKeyword keyword : kwargs) { setItem.execute(frame, inliningTarget, self, keyword.getName(), keyword.getValue()); } + LoopNode.reportLoopCount(inliningTarget, kwargs.length); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.java index ab11fb3522..e0c75dd82f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.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. @@ -118,6 +118,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -1058,6 +1059,7 @@ static Object containsIterator(VirtualFrame frame, PIntRange self, Object elem, break; } if (eqNode.executeEq(frame, inliningTarget, elem, item)) { + LoopNode.reportLoopCount(inliningTarget, idx); return idx; } if (idx == SysModuleBuiltins.MAXSIZE) { @@ -1065,6 +1067,7 @@ static Object containsIterator(VirtualFrame frame, PIntRange self, Object elem, } idx++; } + LoopNode.reportLoopCount(inliningTarget, idx); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.D_IS_NOT_IN_RANGE, elem); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java index eb2dc10cd0..b57a8317b4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java @@ -86,6 +86,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.PPoll) @@ -226,6 +227,7 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, resultSize++; } } + LoopNode.reportLoopCount(inliningTarget, pollRevents.length); Object[] result = new Object[resultSize]; int resultIndex = 0; for (int i = 0; i < pollRevents.length; i++) { @@ -233,6 +235,7 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, result[resultIndex++] = PFactory.createTuple(language, new Object[]{pollFds[i], pollRevents[i]}); } } + LoopNode.reportLoopCount(inliningTarget, pollRevents.length); return PFactory.createList(language, result); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java index b183fda862..cd6bb91da5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java @@ -107,6 +107,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleStringBuilder; @@ -233,6 +234,7 @@ static Object reduce(VirtualFrame frame, PBaseSet self, assert hasNext; keysArray[i] = getIterKey.execute(inliningTarget, storage, it); } + LoopNode.reportLoopCount(inliningTarget, len); PTuple contents = PFactory.createTuple(language, new Object[]{PFactory.createList(language, keysArray)}); Object state = getStateNode.execute(frame, inliningTarget, self); return PFactory.createTuple(language, new Object[]{getClassNode.execute(inliningTarget, self), contents, state}); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java index d1b18929bf..4b19dc96e9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java @@ -74,6 +74,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; /** @@ -179,6 +180,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PFrozenSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = intersectNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createFrozenSet(language, result); } @@ -258,6 +260,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PFrozenSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = diffNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createFrozenSet(language, result); } @@ -306,6 +309,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PBaseSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = addAllToOther.execute(frame, inliningTarget, getHashingStorage.execute(frame, inliningTarget, args[i]), result); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createFrozenSet(language, result); } } @@ -343,6 +347,7 @@ public static long computeHash(VirtualFrame frame, PFrozenSet self, long tmp = hashNode.execute(frame, inliningTarget, key); hash ^= shuffleBits(tmp); } + LoopNode.reportLoopCount(inliningTarget, len); // TODO: // Remove the effect of an odd number of NULL entries diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java index b97df64f4a..211a083064 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java @@ -99,6 +99,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -260,6 +261,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = addAllToOther.execute(frame, inliningTarget, getSetStorageNode.execute(frame, inliningTarget, args[i]), result); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createSet(language, result); } } @@ -315,6 +317,7 @@ static void updateMappingproxy(VirtualFrame frame, PHashingCollection collection Object key = storageIterKey.execute(inliningTarget, source, iterator); curStorage = setStorageItem.execute(frame, inliningTarget, curStorage, key, PNone.NONE); } + LoopNode.reportLoopCount(inliningTarget, size); collection.setDictStorage(curStorage); } @@ -337,6 +340,7 @@ static void doBuiltin(VirtualFrame frame, PHashingCollection collection, @Suppre Object key = getItemScalarNode.execute(inliningTarget, sequenceStorage, i); curStorage = setStorageItem.execute(frame, inliningTarget, curStorage, key, PNone.NONE); } + LoopNode.reportLoopCount(inliningTarget, length); collection.setDictStorage(curStorage); } @@ -412,6 +416,7 @@ static PNone doSet(VirtualFrame frame, PSet self, Object[] args, for (Object o : args) { storage = addAllToOther.execute(frame, inliningTarget, getSetStorageNode.execute(frame, inliningTarget, o), storage); } + LoopNode.reportLoopCount(inliningTarget, args.length); self.setDictStorage(storage); return PNone.NONE; } @@ -496,6 +501,7 @@ Object doGeneric(VirtualFrame frame, PSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = intersectNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return createResult(self, result); } @@ -608,6 +614,7 @@ static PNone doSetArgs(VirtualFrame frame, PSet self, Object[] args, for (Object o : args) { result = xorNode.executeMutatingLeft(frame, inliningTarget, result, getHashingStorage.execute(frame, inliningTarget, o)); } + LoopNode.reportLoopCount(inliningTarget, args.length); self.setDictStorage(result); return PNone.NONE; } @@ -682,6 +689,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = diffNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createSet(language, result); } @@ -733,6 +741,7 @@ static PNone doSet(VirtualFrame frame, PSet self, Object[] args, for (Object o : args) { result = diffNode.execute(frame, inliningTarget, result, getHashingStorage.execute(frame, inliningTarget, o)); } + LoopNode.reportLoopCount(inliningTarget, args.length); self.setDictStorage(result); return PNone.NONE; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index fe3facd298..540faf870e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -112,6 +112,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleString.Encoding; @@ -324,7 +325,7 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, * getaddrinfo(), which can handle translation from interface name to interface * index */ - if ((family == AF_INET6.value || family == AF_UNSPEC.value) && !hasScopeId(name)) { + if ((family == AF_INET6.value || family == AF_UNSPEC.value) && !hasScopeId(inliningTarget, name)) { byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixLib, posixSupport, AF_INET6.value, name); if (bytes != null) { return posixLib.createUniversalSockAddrInet6(posixSupport, new Inet6SockAddr(0, bytes, 0, 0)); @@ -377,12 +378,14 @@ static byte[] doParse(PosixSupportLibrary posixLib, Object posixSupport, int fam } } - private static boolean hasScopeId(byte[] name) { - for (byte b : name) { - if (b == '%') { + private static boolean hasScopeId(Node inliningTarget, byte[] name) { + for (int i = 0; i < name.length; i++) { + if (name[i] == '%') { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, name.length); return false; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java index 913bc283c9..aae749a196 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java @@ -146,6 +146,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -977,6 +978,7 @@ static char[] doBytes(PBytesLike bytes, for (int i = 0; i < res.length; i++) { res[i] = (char) data[i]; } + LoopNode.reportLoopCount(inliningTarget, res.length); return res; } @@ -1087,11 +1089,14 @@ Object getCerts(VirtualFrame frame, PSSLContext self, @SuppressWarnings("unused" @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { List result = PythonUtils.newList(); - for (X509Certificate cert : self.getCACerts()) { + X509Certificate[] certs = self.getCACerts(); + for (int i = 0; i < certs.length; i++) { + X509Certificate cert = certs[i]; if (CertUtils.isCA(cert, CertUtils.getKeyUsage(cert))) { PythonUtils.add(result, CertUtils.decodeCertificate(inliningTarget, constructAndRaiseNode, cert, language)); } } + LoopNode.reportLoopCount(inliningTarget, certs.length); return PFactory.createList(language, PythonUtils.toArray(result)); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateParsingException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseSSLError(frame, SSLErrorCode.ERROR_SSL, ex); @@ -1100,14 +1105,18 @@ Object getCerts(VirtualFrame frame, PSSLContext self, @SuppressWarnings("unused" @Specialization(guards = "binary_form") static Object getCertsBinary(PSSLContext self, @SuppressWarnings("unused") boolean binary_form, + @Bind Node inliningTarget, @Bind PythonLanguage language) { try { List result = PythonUtils.newList(); - for (X509Certificate cert : self.getCACerts()) { + X509Certificate[] certs = self.getCACerts(); + for (int i = 0; i < certs.length; i++) { + X509Certificate cert = certs[i]; if (CertUtils.isCA(cert, CertUtils.getKeyUsage(cert))) { PythonUtils.add(result, PFactory.createBytes(language, CertUtils.getEncoded(cert))); } } + LoopNode.reportLoopCount(inliningTarget, certs.length); return PFactory.createList(language, PythonUtils.toArray(result)); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateEncodingException ex) { throw PConstructAndRaiseNode.raiseUncachedSSLError(SSLErrorCode.ERROR_SSL, ex); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java index 286809358a..396bf4aa4c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java @@ -188,6 +188,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -704,9 +705,11 @@ static boolean doTuple(Object selfObj, Object subStrs, int start, int end, Op op TruffleString subStr = castPrefixNode.cast(inliningTarget, element, ErrorMessages.INVALID_ELEMENT_TYPE, op.methodName(), element); int subStrLen = codePointLengthNode.execute(subStr, TS_ENCODING); if (doIt(self, subStr, cpStart, cpEnd, selfLen, subStrLen, regionEqualNode, op)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, storage.length()); return false; } @@ -871,6 +874,7 @@ static int count(TruffleString self, TruffleString sub, int start, int end, cnt++; pos = i + subLen; } + LoopNode.reportLoopCount(indexOfStringNode, cnt); return cnt; } @@ -1035,6 +1039,7 @@ static PDict doString(VirtualFrame frame, Object cls, Object from, Object to, Ob int value = nextNode.execute(toIt, TS_ENCODING); storage = setHashingStorageItem.execute(frame, inliningTarget, storage, key, value); } + LoopNode.reportLoopCount(inliningTarget, fromLen); assert !toIt.hasNext(); if (hasZ) { TruffleStringIterator zIt = createCodePointIteratorNode.execute(zString, TS_ENCODING); @@ -1307,6 +1312,7 @@ static PList doStringSep(TruffleString self, TruffleString sep, int maxsplit, appendNode.execute(list, substringNode.execute(self, lastEnd, nextIndex - lastEnd, TS_ENCODING, false)); lastEnd = nextIndex + sepLen; } + LoopNode.reportLoopCount(inliningTarget, (maxsplit < 0 ? Integer.MAX_VALUE : maxsplit) - splits); appendNode.execute(list, substringNode.execute(self, lastEnd, selfLen - lastEnd, TS_ENCODING, false)); return list; } @@ -1367,7 +1373,7 @@ private static PList splitfields(TruffleString s, int maxsplit, AppendNode appen // Start next segment search at that point start = index; } - + LoopNode.reportLoopCount(appendNode, splits); return list; } } @@ -1416,6 +1422,7 @@ static PList doStringSepMaxsplit(VirtualFrame frame, TruffleString self, Truffle end = idx; splits++; } + LoopNode.reportLoopCount(inliningTarget, splits); appendNode.execute(list, substringNode.execute(self, 0, end, TS_ENCODING, true)); reverseNode.execute(frame, list); @@ -1447,8 +1454,8 @@ static PList doStringMaxsplit(VirtualFrame frame, TruffleString s, @SuppressWarn // emitted in ws->non-ws transition and at the end boolean hasSegment = false; int start = 0, end = length, splits = 0; - - for (int i = length - 1; i >= 0; i--) { + int i = length - 1; + for (; i >= 0; i--) { if (StringUtils.isSpace(codePointAtIndexNode.execute(s, i))) { if (hasSegment) { appendNode.execute(list, substringNode.execute(s, start, end - start, TS_ENCODING, false)); @@ -1464,6 +1471,7 @@ static PList doStringMaxsplit(VirtualFrame frame, TruffleString s, @SuppressWarn start = i; } } + LoopNode.reportLoopCount(inliningTarget, length - 1 - i); if (hasSegment) { appendNode.execute(list, substringNode.execute(s, 0, end, TS_ENCODING, false)); } @@ -1545,6 +1553,7 @@ static PList doStringKeepends(Node inliningTarget, TruffleString self, boolean k TruffleString line = substringNode.execute(self, substringStartByteIndex, substringByteLength, TS_ENCODING, false); appendNode.execute(list, line); } while (matchFound); + LoopNode.reportLoopCount(inliningTarget, list.getSequenceStorage().length()); return list; } @@ -2276,6 +2285,7 @@ static TruffleString doString(TruffleString self, } end++; } + LoopNode.reportLoopCount(nextNode, end); if (start != end) { appendSegment(self, language, appendStringNode, substringNode, toJavaStringNode, fromJavaStringNode, sb, start, end - 1); } @@ -2432,6 +2442,7 @@ static TruffleString doGenericCachedStep(TruffleString value, SliceInfo slice, appendCodePointNode.execute(sb, codePointAtIndexNode.execute(value, i), 1, true); j++; } + LoopNode.reportLoopCount(inliningTarget, len); return toStringNode.execute(sb); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java index 95b83c24f3..9c9dfc5ad9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java @@ -104,6 +104,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -477,6 +478,7 @@ static TruffleString doPSequence(TruffleString self, PSequence sequence, item = getItemNode.execute(storage, i); appendStringNode.execute(sb, castToStringNode.execute(inliningTarget, item)); } + LoopNode.reportLoopCount(inliningTarget, len - 1); return toStringNode.execute(sb); } catch (OutOfMemoryError e) { throw raise.raise(inliningTarget, MemoryError); @@ -679,6 +681,7 @@ public abstract static class StringReplaceNode extends Node { @Specialization static TruffleString doReplace(TruffleString self, TruffleString old, TruffleString with, int maxCountArg, + @Bind Node inliningTarget, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfStringNode indexOfStringNode, @Cached TruffleString.SubstringNode substringNode, @@ -702,16 +705,20 @@ static TruffleString doReplace(TruffleString self, TruffleString old, TruffleStr int replacements = 0; TruffleStringIterator it = createCodePointIteratorNode.execute(self, TS_ENCODING); int i = 0; - while (it.hasNext()) { - if (replacements++ >= maxCount) { - TruffleString rest = substringNode.execute(self, i, selfCpLen - i, TS_ENCODING, true); - appendStringNode.execute(sb, rest); - return toStringNode.execute(sb); + try { + while (it.hasNext()) { + if (replacements++ >= maxCount) { + TruffleString rest = substringNode.execute(self, i, selfCpLen - i, TS_ENCODING, true); + appendStringNode.execute(sb, rest); + return toStringNode.execute(sb); + } + appendStringNode.execute(sb, with); + int codePoint = nextNode.execute(it, TS_ENCODING); + appendCodePointNode.execute(sb, codePoint, 1, true); + ++i; } - appendStringNode.execute(sb, with); - int codePoint = nextNode.execute(it, TS_ENCODING); - appendCodePointNode.execute(sb, codePoint, 1, true); - ++i; + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } if (replacements < maxCount) { appendStringNode.execute(sb, with); @@ -737,6 +744,7 @@ static TruffleString doReplace(TruffleString self, TruffleString old, TruffleStr } idx = indexOfStringNode.execute(self, old, start, selfCpLen, TS_ENCODING); } while (idx >= 0); + LoopNode.reportLoopCount(inliningTarget, replacements); TruffleString rest = substringNode.execute(self, start, selfCpLen - start, TS_ENCODING, true); appendStringNode.execute(sb, rest); return toStringNode.execute(sb); @@ -756,6 +764,7 @@ public abstract static class StringReprNode extends Node { @Specialization static TruffleString doString(TruffleString self, + @Bind Node inliningTarget, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, @Cached TruffleString.CreateCodePointIteratorNode createCodePointIteratorNode, @@ -802,6 +811,7 @@ static TruffleString doString(TruffleString self, break; } } + LoopNode.reportLoopCount(inliningTarget, selfLen); appendCodePointNode.execute(sb, (byte) (useDoubleQuotes ? '"' : '\''), 1, true); return toStringNode.execute(sb); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java index a88f049a89..210150954b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java @@ -182,6 +182,7 @@ public static TruffleString strip(TruffleString str, StripKind stripKind, Truffl j++; } + LoopNode.reportLoopCount(substringNode, len - j + i); return substringNode.execute(str, i, j - i, TS_ENCODING, false); } @@ -215,6 +216,7 @@ public static TruffleString strip(TruffleString str, TruffleString chars, StripK j++; } + LoopNode.reportLoopCount(substringNode, len - j + i); return substringNode.execute(str, i, j - i, TS_ENCODING, false); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java index 7f14c44e24..14f4fd1aa0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java @@ -114,6 +114,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -130,6 +131,7 @@ static void packInternal(VirtualFrame frame, PStruct self, StructNodes.PackValue buffer_offset += code.size; } } + LoopNode.reportLoopCount(packValueNode, (int) Math.min(Integer.MAX_VALUE, (long) codes.length + pos)); } public static Object[] unpackInternal(PStruct self, StructNodes.UnpackValueNode unpackValueNode, byte[] bytes, int offset) { @@ -144,6 +146,7 @@ public static Object[] unpackInternal(PStruct self, StructNodes.UnpackValueNode buffer_offset += code.size; } } + LoopNode.reportLoopCount(unpackValueNode, (int) Math.min(Integer.MAX_VALUE, (long) codes.length + pos)); return values; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java index 30912d0891..f7a29ee665 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java @@ -71,6 +71,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -162,6 +163,7 @@ static PTuple withDict(VirtualFrame frame, Object cls, Object sequence, Object d dst[i] = PNone.NONE; } } + LoopNode.reportLoopCount(inliningTarget, dst.length); return PFactory.createTuple(cls, getInstanceShape.execute(cls), new ObjectSequenceStorage(dst, minLen)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java index 5980476d9a..7a48ac9df7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java @@ -99,6 +99,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleStringBuilder; @@ -219,6 +220,7 @@ static TruffleString repr(VirtualFrame frame, PTuple self, appendStringNode.execute(sb, T_EQ); appendStringNode.execute(sb, reprNode.execute(frame, inliningTarget, getItemNode.execute(inliningTarget, tupleStore, i))); } + LoopNode.reportLoopCount(inliningTarget, visibleSize - 1); } appendStringNode.execute(sb, T_RPAREN); return toStringNode.execute(sb); @@ -259,6 +261,7 @@ static PTuple reduce(VirtualFrame frame, PTuple self, // We're reading past length, GetItemScalarNode doesn't do a bounds check dictSetItem.execute(inliningTarget, dict, n, getSeqItem.execute(inliningTarget, storage, i)); } + LoopNode.reportLoopCount(inliningTarget, nFields - nVisibleFields); } return PFactory.createTuple(language, new Object[]{type, PFactory.createTuple(language, new Object[]{tuple, dict})}); } @@ -294,6 +297,7 @@ static PTuple replace(VirtualFrame frame, PTuple self, @SuppressWarnings("unused for (int i = 0; i < nFields; i++) { values[i] = getItemNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, nFields); TruffleString[] fieldNames = getFieldNamesNode.execute(inliningTarget, type); boolean[] matched = new boolean[changes.length]; @@ -306,6 +310,7 @@ static PTuple replace(VirtualFrame frame, PTuple self, @SuppressWarnings("unused } } } + LoopNode.reportLoopCount(inliningTarget, nFields); checkUnexpected(changes, matched, inliningTarget, raiseNode, language); return PFactory.createTuple(type, getInstanceShapeNode.execute(type), new ObjectSequenceStorage(values, storage.length())); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java index b91de2043f..58d983c819 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java @@ -107,6 +107,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -218,6 +219,7 @@ static long count(VirtualFrame frame, Object self, Object value, count++; } } + LoopNode.reportLoopCount(inliningTarget, tupleStore.length()); return count; } } @@ -273,6 +275,7 @@ public static TruffleString repr(VirtualFrame frame, Object self, appendStringNode.execute(buf, toString(frame, inliningTarget, getItemNode.execute(tupleStore, i), reprNode)); appendStringNode.execute(buf, T_COMMA_SPACE); } + LoopNode.reportLoopCount(inliningTarget, len - 1); if (len > 0) { appendStringNode.execute(buf, toString(frame, inliningTarget, getItemNode.execute(tupleStore, len - 1), reprNode)); @@ -482,6 +485,7 @@ private static long doComputeHash(VirtualFrame frame, Node inliningTarget, Seque hash = (hash ^ tmp) * multiplier; multiplier += 82520 + len + len; } + LoopNode.reportLoopCount(inliningTarget, len); hash += 97531; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java index a7f65a0181..88cd6e0912 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java @@ -401,7 +401,9 @@ Object generic(@SuppressWarnings("unused") Object cls, @SuppressWarnings("unused private Object calculateMetaclass(VirtualFrame frame, Node inliningTarget, Object cls, PTuple bases, GetClassNode getClassNode, IsTypeNode isTypeNode, PyObjectLookupAttr lookupMroEntries, GetObjectArrayNode getObjectArrayNode) { Object winner = cls; - for (Object base : getObjectArrayNode.execute(inliningTarget, bases)) { + Object[] basesArray = getObjectArrayNode.execute(inliningTarget, bases); + for (int i = 0; i < basesArray.length; i++) { + Object base = basesArray[i]; if (!isTypeNode.execute(inliningTarget, base) && lookupMroEntries.execute(frame, inliningTarget, base, T___MRO_ENTRIES__) != NO_VALUE) { throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.TYPE_DOESNT_SUPPORT_MRO_ENTRY_RESOLUTION); } @@ -417,6 +419,7 @@ private Object calculateMetaclass(VirtualFrame frame, Node inliningTarget, Objec } throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.METACLASS_CONFLICT); } + LoopNode.reportLoopCount(inliningTarget, basesArray.length); return winner; } @@ -739,6 +742,7 @@ static Object setBases(VirtualFrame frame, PythonClass cls, Object value, throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.MUST_BE_TUPLE_OF_CLASSES_NOT_P, cls, "__bases__", a[i]); } } + LoopNode.reportLoopCount(inliningTarget, a.length); Object newBestBase = getBestBase.execute(inliningTarget, baseClasses); if (newBestBase == null) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java index d187c24935..52aee987f2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java @@ -242,6 +242,7 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.ControlFlowException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -816,7 +817,7 @@ static PythonAbstractClass[] doNative(Node inliningTarget, PythonNativeClass obj SequenceStorage storage = tuple.getSequenceStorage(); Object[] values = toArrayNode.execute(inliningTarget, storage); try { - return cast(values, storage); + return cast(inliningTarget, values, storage); } catch (ClassCastException e) { throw raise.raise(inliningTarget, PythonBuiltinClassType.SystemError, ErrorMessages.UNSUPPORTED_OBJ_IN, "tp_bases"); } @@ -824,7 +825,7 @@ static PythonAbstractClass[] doNative(Node inliningTarget, PythonNativeClass obj int length = Math.toIntExact(readLongField(nativeTuple.getPtr(), CFields.PyVarObject__ob_size)); Object[] values = getTpBasesNode.readPyObjectArray(CStructAccess.getFieldPtr(nativeTuple.getPtr(), PyTupleObject__ob_item), length); try { - return cast(values, length); + return cast(inliningTarget, values, length); } catch (ClassCastException e) { throw raise.raise(inliningTarget, PythonBuiltinClassType.SystemError, ErrorMessages.UNSUPPORTED_OBJ_IN, "tp_bases"); } @@ -833,15 +834,16 @@ static PythonAbstractClass[] doNative(Node inliningTarget, PythonNativeClass obj } // TODO: get rid of this - private static PythonAbstractClass[] cast(Object[] arr, SequenceStorage storage) { - return cast(arr, storage.length()); + private static PythonAbstractClass[] cast(Node inliningTarget, Object[] arr, SequenceStorage storage) { + return cast(inliningTarget, arr, storage.length()); } - private static PythonAbstractClass[] cast(Object[] arr, int length) { + private static PythonAbstractClass[] cast(Node inliningTarget, Object[] arr, int length) { PythonAbstractClass[] bases = new PythonAbstractClass[length]; for (int i = 0; i < length; i++) { bases[i] = (PythonAbstractClass) arr[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return bases; } } @@ -942,6 +944,7 @@ private static PythonAbstractClass bestBase(Node inliningTarget, PythonAbstractC throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.MULTIPLE_BASES_LAYOUT_CONFLICT); } } + LoopNode.reportLoopCount(inliningTarget, bases.length); return base; } } @@ -2049,6 +2052,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple throw raise.raise(inliningTarget, PythonBuiltinClassType.NotImplementedError, ErrorMessages.CREATING_CLASS_NON_CLS_BASES); } } + LoopNode.reportLoopCount(inliningTarget, array.length); } // check for possible layout conflicts PythonAbstractClass base = getBestBaseNode.execute(inliningTarget, basesArray); @@ -2139,6 +2143,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple ctx.addWeak = true; } } + LoopNode.reportLoopCount(inliningTarget, slotlen); // Make slots into a tuple Object state = BoundaryCallContext.enter(frame, language, context, boundaryCallData); try { @@ -2150,7 +2155,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple BoundaryCallContext.exit(frame, language, context, state); } /* Secondary bases may provide weakrefs or dict */ - typeNewSlotBases(ctx, base, basesArray); + typeNewSlotBases(inliningTarget, ctx, base, basesArray); } int indexedSlotCount = getIndexedSlotsCountNode.execute(inliningTarget, base); @@ -2159,6 +2164,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple IndexedSlotDescriptor slotDesc = PFactory.createIndexedSlotDescriptor(language, slotName, indexedSlotCount++, pythonClass); pythonClass.setAttribute(slotName, slotDesc); } + LoopNode.reportLoopCount(inliningTarget, ctx.copiedSlots.length); } pythonClass.setIndexedSlotCount(indexedSlotCount); @@ -2179,7 +2185,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple } // equivalent of type_new_slot_bases in CPython - private static void typeNewSlotBases(TypeNewContext ctx, Object primaryBase, PythonAbstractClass[] basesArray) { + private static void typeNewSlotBases(Node inliningTarget, TypeNewContext ctx, Object primaryBase, PythonAbstractClass[] basesArray) { if (basesArray.length > 1 && (ctx.mayAddDict && !ctx.addDict || ctx.mayAddWeak && !ctx.addWeak)) { for (PythonAbstractClass base : basesArray) { if (base == primaryBase) { @@ -2196,6 +2202,7 @@ private static void typeNewSlotBases(TypeNewContext ctx, Object primaryBase, Pyt break; } } + LoopNode.reportLoopCount(inliningTarget, basesArray.length); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java index 625397545d..7325e16c0c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java @@ -98,6 +98,7 @@ 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.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -240,6 +241,7 @@ static boolean check(VirtualFrame frame, PUnionType self, Object other, // Cannot break here, the check for GenericAlias needs to check all args } } + LoopNode.reportLoopCount(inliningTarget, argsStorage.length()); return result; } } @@ -269,6 +271,7 @@ static boolean check(VirtualFrame frame, PUnionType self, Object other, // Cannot break here, the check for GenericAlias needs to check all args } } + LoopNode.reportLoopCount(inliningTarget, argsStorage.length()); return result; } } @@ -315,6 +318,7 @@ Object getitem(VirtualFrame frame, PUnionType self, Object item, for (int i = 1; i < newargs.length; i++) { result = orNode.execute(frame, result, newargs[i]); } + LoopNode.reportLoopCount(inliningTarget, newargs.length - 1); return result; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java index 69550330c5..b99e4689ed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java @@ -76,6 +76,7 @@ import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -138,6 +139,7 @@ static void doMerge(VirtualFrame frame, Node inliningTarget, Object target, PDic throw raiseNode.raise(inliningTarget, RuntimeError, ErrorMessages.MUTATED_DURING_UPDATE, "dict"); } } + LoopNode.reportLoopCount(inliningTarget, initialSize); updateStorageNode.execute(inliningTarget, target, targetStorage, newStorage); } } @@ -165,6 +167,7 @@ static void doMerge(VirtualFrame frame, Node inliningTarget, Object target, Obje Object value = getItem.execute(frame, inliningTarget, mapping, key); setItem.execute(frame, inliningTarget, target, key, value); } + LoopNode.reportLoopCount(inliningTarget, keysLen); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java index 58c19a75d5..ef2c3a07c0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java @@ -59,6 +59,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.UnadoptableNode; @@ -130,11 +131,14 @@ private boolean callRecursiveWithNodeTruffleBoundary(Node inliningTarget, Object private static boolean loopRecursive(VirtualFrame frame, Object arg, Object clsTuple, Node inliningTarget, TupleNodes.GetTupleStorage getTupleStorage, SequenceStorageNodes.ToArrayNode toArrayNode, PyObjectRecursiveBinaryCheckNode node, int depth) { - for (Object cls : getTupleArray(inliningTarget, clsTuple, getTupleStorage, toArrayNode)) { - if (node.executeInternal(frame, arg, cls, depth)) { + Object[] classes = getTupleArray(inliningTarget, clsTuple, getTupleStorage, toArrayNode); + for (int i = 0; i < classes.length; i++) { + if (node.executeInternal(frame, arg, classes[i], depth)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, classes.length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java index e4f633836a..3e670fc2e2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java @@ -86,6 +86,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -286,6 +287,7 @@ static PException doUncached(Object[] pArguments, Object callable, Signature sig kwonly_given += 1; } } + LoopNode.reportLoopCount(inliningTarget, co_kwonlyargcount); boolean forgotSelf = methodcall && avail + 1 == co_argcount && (signature.getParameterIds().length == 0 || !equalNode.execute(signature.getParameterIds()[0], T_SELF, TS_ENCODING)); TruffleString name = getName(callable, signature); throw raiseTooManyArguments(inliningTarget, name, co_argcount - adjustCount, ndefaults, avail - adjustCount, forgotSelf, kwonly_given, raise); @@ -544,6 +546,7 @@ static void applyUncached(Object callee, Signature calleeSignature, Object[] pAr lastWrongKeyword = name; } } + LoopNode.reportLoopCount(inliningTarget, kwLen); storeKeywordsOrRaise(callee, pArguments, kwargsIndex, unusedKeywords, k, additionalKwds, lastWrongKeyword, posArgOnlyPassedAsKeywordNames, inliningTarget, posArgOnlyPassedAsKeywordProfile, raise, calleeSignature); } @@ -726,6 +729,7 @@ static void doUncached(Object callable, Signature signature, Object[] pArguments missingNames[missingCnt++] = signature.getParameterIds()[i]; } } + LoopNode.reportLoopCount(inliningTarget, missingNames.length); if (missingProfile.profile(inliningTarget, missingCnt > 0)) { throw raiseMissing(inliningTarget, callable, missingNames, missingCnt, toTruffleStringUncached("positional"), raise, signature); } @@ -804,6 +808,7 @@ static void doUncached(Object callable, Object[] pArguments, Signature signature missingNames[missingCnt++] = kwname; } } + LoopNode.reportLoopCount(inliningTarget, missingNames.length); if (missingProfile.profile(inliningTarget, missingCnt > 0)) { throw raiseMissing(inliningTarget, callable, missingNames, missingCnt, toTruffleStringUncached("keyword-only"), raise, signature); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java index 88b789d1c7..bc1e7a69a7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java @@ -72,6 +72,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @ImportStatic(PythonOptions.class) @@ -141,6 +142,7 @@ static Object[] starargs(VirtualFrame frame, Object object, Object next = nextNode.execute(frame, inliningTarget, iterator); internalStorage.add(next); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, internalStorage.size()); return internalStorage.toArray(new Object[0]); } } @@ -178,6 +180,7 @@ static Object[] doIt(Node inliningTarget, HashingStorage storage, assert hasNext; args[i] = iteratorKey.execute(inliningTarget, storage, it); } + LoopNode.reportLoopCount(inliningTarget, args.length); return args; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java index 33dda2c045..bda1effcfc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java @@ -75,6 +75,7 @@ import com.oracle.truffle.api.nodes.EncapsulatingNodeReference; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -188,6 +189,7 @@ static Object generic(Object type, Object objectType, TruffleString key, while (i < mro.length && !isSameTypeNode.execute(inliningTarget, type, mro[i])) { i++; } + LoopNode.reportLoopCount(inliningTarget, i); if (i + 1 >= mro.length) { return NO_MRO_SUFFIX; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java index d03f0d28c0..4b36baf96a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java @@ -62,6 +62,7 @@ import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -108,6 +109,7 @@ void doImport(VirtualFrame frame, TruffleString moduleName, int level, TruffleString name = TruffleString.fromJavaStringUncached(attrName, TS_ENCODING); setItemNode.execute(frame, inliningTarget, locals, name, attr); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, len)); } catch (UnknownIdentifierException | UnsupportedMessageException | InvalidArrayIndexException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw new IllegalStateException(e); @@ -116,10 +118,14 @@ void doImport(VirtualFrame frame, TruffleString moduleName, int level, try { Object attrAll = getAttrNode.execute(frame, inliningTarget, importedModule, T___ALL__); int n = sizeNode.execute(frame, inliningTarget, attrAll); - for (int i = 0; i < n; i++) { - Object attrName = getItemNode.execute(frame, inliningTarget, attrAll, i); - writeAttributeToLocals(frame, inliningTarget, moduleName, (PythonModule) importedModule, locals, attrName, true, castToTruffleStringNode, codePointLengthNode, - codePointAtIndexNode, getAttrNode, setItemNode); + try { + for (int i = 0; i < n; i++) { + Object attrName = getItemNode.execute(frame, inliningTarget, attrAll, i); + writeAttributeToLocals(frame, inliningTarget, moduleName, (PythonModule) importedModule, locals, attrName, true, castToTruffleStringNode, codePointLengthNode, + codePointAtIndexNode, getAttrNode, setItemNode); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, n); } } catch (PException e) { e.expectAttributeError(inliningTarget, isAttributeErrorProfile); 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 997fd78c0f..d25e3fca4f 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 @@ -325,6 +325,7 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.InvalidAssumptionException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.SlowPathException; @@ -3947,6 +3948,7 @@ public static Object[] doUnpackIterable(VirtualFrame virtualFrame, Object collec Object item = getNextNode.execute(virtualFrame, inliningTarget, iterator); result.add(item); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, result.size()); return result.toArray(new Object[0]); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java index 607266d01c..e5ff5b774c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java @@ -143,7 +143,7 @@ SequenceStorage createSequenceStorage(Object[] objectElements, int length) { private SequenceStorage initialize(Object[] objectElements) { SequenceStorage storage; try { - storage = SequenceStorageFactory.createStorage(objectElements); + storage = SequenceStorageFactory.createStorage(this, objectElements); type = storage.getElementType(); } catch (Throwable t) { // we do not want to repeatedly deopt if a value execution @@ -189,7 +189,7 @@ public abstract static class ListFromArrayNode extends SequenceFromArrayNode imp private static final ListFromArrayNode UNCACHED = new ListFromArrayNode() { @Override public PList execute(PythonLanguage language, Object[] elements) { - return PFactory.createList(language, SequenceStorageFactory.createStorage(elements)); + return PFactory.createList(language, SequenceStorageFactory.createStorage(this, elements)); } }; @@ -252,7 +252,7 @@ public abstract static class TupleFromArrayNode extends SequenceFromArrayNode { private static final TupleFromArrayNode UNCACHED = new TupleFromArrayNode() { @Override public PTuple execute(PythonLanguage language, Object[] elements) { - return PFactory.createTuple(language, SequenceStorageFactory.createStorage(elements)); + return PFactory.createTuple(language, SequenceStorageFactory.createStorage(this, elements)); } }; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java index 3260807424..d3ba3dac71 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -62,6 +62,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @GenerateUncached @@ -133,11 +134,13 @@ static boolean doSubclass(VirtualFrame frame, @SuppressWarnings("unused") Object } private static boolean loopUnexploded(VirtualFrame frame, Object cachedCls, AbstractObjectIsSubclassNode isSubclassNode, Object[] basesAry, int depth) { - for (Object baseCls : basesAry) { - if (isSubclassNode.executeInternal(frame, baseCls, cachedCls, depth + 1)) { + for (int i = 0; i < basesAry.length; i++) { + if (isSubclassNode.executeInternal(frame, basesAry[i], cachedCls, depth + 1)) { + LoopNode.reportLoopCount(isSubclassNode, i); return true; } } + LoopNode.reportLoopCount(isSubclassNode, basesAry.length); return false; } @@ -194,11 +197,14 @@ private static boolean doGeneric(VirtualFrame frame, Node inliningTarget, Object return false; } - for (Object baseCls : getObjectArrayNode.execute(inliningTarget, bases)) { - if (isSubclassNode.executeInternal(frame, baseCls, cls, depth + 1)) { + Object[] basesArray = getObjectArrayNode.execute(inliningTarget, bases); + for (int i = 0; i < basesArray.length; i++) { + if (isSubclassNode.executeInternal(frame, basesArray[i], cls, depth + 1)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, basesArray.length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java index 563e9a35fd..53ec418b54 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java @@ -64,6 +64,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -304,11 +305,14 @@ static boolean issubTypeGeneric(Object derived, Object cls, if (builtinClassIsSubtypeProfile.profile(inliningTarget, isBuiltinClass(derived) && !isBuiltinClass(cls))) { return false; } - for (PythonAbstractClass n : getMro.execute(inliningTarget, derived).getInternalClassArray()) { - if (isSameType(inliningTarget, isSameTypeNode, n, cls)) { + PythonAbstractClass[] mro = getMro.execute(inliningTarget, derived).getInternalClassArray(); + for (int i = 0; i < mro.length; i++) { + if (isSameType(inliningTarget, isSameTypeNode, mro[i], cls)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, mro.length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java index 8babbe6225..b94d8fffd8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java @@ -60,6 +60,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -111,6 +112,7 @@ public static Object matchExceptions(VirtualFrame frame, exceptionGroupList.add(exceptionObj); } } + LoopNode.reportLoopCount(inliningTarget, exceptionGroup.getExceptions().length); } else { exceptionGroup.setTraceback(exceptionOrigUnreified.getTraceback()); return PException.fromExceptionInfo(exceptionGroup, PythonOptions.isPExceptionWithJavaStacktrace(language)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java index 44593245aa..f17f8a059b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java @@ -67,6 +67,7 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @ImportStatic(PGuards.class) @@ -138,9 +139,11 @@ public static boolean matchTuple(Object e, Object clause, for (int i = 0; i < length; i++) { Object clauseType = getItemNode.execute(inliningTarget, storage, i); if (recursiveNode.executeMatch(e, clauseType)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java index a3461128c3..7ef541a90f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -63,6 +63,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -118,6 +119,7 @@ public static Object addToAcc( for (Object exc : exceptionGroupAcc.getExceptions()) { exceptionGroupsInAcc.add(exc); } + LoopNode.reportLoopCount(inliningTarget, exceptionGroupAcc.getExceptions().length); if (clause == PNone.NONE) { // uncaught grouped exceptions should be bundled together with @@ -156,6 +158,7 @@ public static Object addToAcc( for (Object exc : exceptionGroupAcc.getExceptions()) { exceptionGroupsInAcc.add(exc); } + LoopNode.reportLoopCount(inliningTarget, exceptionGroupAcc.getExceptions().length); exceptionGroupsInAcc.add(exceptionToAdd.getUnreifiedException()); outerExceptionGroup = (PBaseExceptionGroup) deriveExceptionGroup.execute( frame, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java index 3c2f86889a..ce94b8dc4c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java @@ -61,6 +61,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedIntValueProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -141,6 +142,7 @@ PDict doIt(BytecodeFrame locals, storage = setItem.execute(inliningTarget, storage, name, value); } } + LoopNode.reportLoopCount(inliningTarget, varCount); return PFactory.createDict(language, storage); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java index 212c1cde89..dbab409377 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java @@ -95,6 +95,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -577,6 +578,7 @@ TruffleString resolveName(VirtualFrame frame, TruffleString name, PDict globals, } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.max(0L, (long) level - 1)); TruffleString base = substringNode.execute(pkgString, 0, lastDotIdx, TS_ENCODING, true); if (name.isEmpty()) { return base; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 0653be98fe..c74a14fe87 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -147,6 +147,7 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.AbstractTruffleString; import com.oracle.truffle.api.strings.InternalByteArray; @@ -883,10 +884,12 @@ public int[] pipe() throws PosixException { } @ExportMessage - public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { + public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout, + @Bind Node inliningTarget) throws PosixException { int largestFD = findMax(readfds, -1); largestFD = findMax(writefds, largestFD); largestFD = findMax(errorfds, largestFD); + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) readfds.length + writefds.length + errorfds.length)); // This will be treated as boolean array (output parameter), each item indicating if given // FD was selected or not byte[] selected = new byte[readfds.length + writefds.length + errorfds.length]; @@ -939,7 +942,8 @@ private static boolean[] selectFillInResult(int[] fds, byte[] selected, int sele private static int findMax(int[] items, int currentMax) { int max = currentMax; - for (int item : items) { + for (int i = 0; i < items.length; i++) { + int item = items[i]; if (item > max) { max = item; } @@ -1956,7 +1960,8 @@ public void unsetenv(Object name) throws PosixException { @ExportMessage public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, + @Bind Node inliningTarget) throws PosixException { // The following strings and string arrays need to be present in the native function: // - char** of executable names ('\0'-terminated strings with an extra NULL at the end) @@ -1987,16 +1992,16 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en try { offsetsLen = executables.length + 1; - dataLen = addLengthsOfCStrings(0, executables); + dataLen = addLengthsOfCStrings(inliningTarget, 0, executables); argsPos = offsetsLen; offsetsLen += args.length + 1; - dataLen = addLengthsOfCStrings(dataLen, args); + dataLen = addLengthsOfCStrings(inliningTarget, dataLen, args); if (env != null) { envPos = offsetsLen; offsetsLen += env.length + 1; - dataLen = addLengthsOfCStrings(dataLen, env); + dataLen = addLengthsOfCStrings(inliningTarget, dataLen, env); } else { envPos = -1; } @@ -2069,7 +2074,8 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en } @ExportMessage - public void execv(Object pathname, Object[] args) throws PosixException { + public void execv(Object pathname, Object[] args, + @Bind Node inliningTarget) throws PosixException { if (WINDOWS) { throw newPosixException(OSErrorEnum.ENOSYS.getNumber()); @@ -2095,7 +2101,7 @@ public void execv(Object pathname, Object[] args) throws PosixException { try { // The +1 can overflow only if the buffer contains 2^63-1 bytes, which is impossible // since we are using Java arrays limited to 2^31-1. - dataLen = addLengthsOfCStrings(pathnameLen + 1L, args); + dataLen = addLengthsOfCStrings(inliningTarget, pathnameLen + 1L, args); } catch (OverflowException e) { throw newPosixException(OSErrorEnum.E2BIG.getNumber()); } @@ -2139,11 +2145,12 @@ public int system(Object command) { } } - private static long addLengthsOfCStrings(long prevLen, Object[] src) throws OverflowException { + private static long addLengthsOfCStrings(Node inliningTarget, long prevLen, Object[] src) throws OverflowException { long len = prevLen; - for (Object o : src) { - len = PythonUtils.addExact(len, ((Buffer) o).length); + for (int i = 0; i < src.length; i++) { + len = PythonUtils.addExact(len, ((Buffer) src[i]).length); } + LoopNode.reportLoopCount(inliningTarget, src.length); return PythonUtils.addExact(len, src.length); // add space for terminating '\0' } @@ -3376,7 +3383,7 @@ public Object createPathFromString(TruffleString path, TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); } - return checkNarrowPath(encodeFSDefaultNode.execute(null, inliningTarget, path)); + return checkNarrowPath(inliningTarget, encodeFSDefaultNode.execute(null, inliningTarget, path)); } @ExportMessage @@ -3391,7 +3398,7 @@ public Object createPathFromBytes(byte[] path, TruffleString utf16 = switchEncodingNode.execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(inliningTarget, path)); return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); } - return checkNarrowPath(path); + return checkNarrowPath(inliningTarget, path); } @ExportMessage @@ -3450,12 +3457,13 @@ public Object createCStringFromString(TruffleString string, @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, @Exclusive @Cached TruffleString.IsValidNode isValidNode, @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - return checkCString(getUTF8StringBytes(inliningTarget, string, switchEncodingNode, isValidNode, copyToByteArrayNode)); + return checkCString(inliningTarget, getUTF8StringBytes(inliningTarget, string, switchEncodingNode, isValidNode, copyToByteArrayNode)); } @ExportMessage - public Object createCStringFromBytes(byte[] bytes) { - return checkCString(bytes); + public Object createCStringFromBytes(byte[] bytes, + @Bind Node inliningTarget) { + return checkCString(inliningTarget, bytes); } @ExportMessage @@ -3526,20 +3534,22 @@ private static PException raiseSurrogatesEncodeError(Node node, TruffleString st return PRaiseNode.raiseExceptionObjectStatic(node, exception); } - private static Buffer checkCString(byte[] path) { - for (byte b : path) { - if (b == 0) { + private static Buffer checkCString(Node inliningTarget, byte[] path) { + for (int i = 0; i < path.length; i++) { + if (path[i] == 0) { + LoopNode.reportLoopCount(inliningTarget, i); return null; } } + LoopNode.reportLoopCount(inliningTarget, path.length); // TODO we keep a byte[] provided by the caller, who can potentially change it, making our // check for embedded nulls pointless. Maybe we should copy it and while on it, might as // well add the terminating null character, avoiding the copy we do later in pathToCString. return Buffer.wrap(path); } - private static NarrowPath checkNarrowPath(byte[] path) { - return checkCString(path) == null ? null : new NarrowPath(path); + private static NarrowPath checkNarrowPath(Node inliningTarget, byte[] path) { + return checkCString(inliningTarget, path) == null ? null : new NarrowPath(path); } private static WidePath checkWidePath(byte[] path) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.java index 256bd20354..3f117403a6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.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. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.CompilerDirectives; public final class BoolSequenceStorage extends ArrayBasedSequenceStorage { @@ -122,7 +124,7 @@ public Object getCopyOfInternalArrayObject() { return PythonUtils.arrayCopyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -132,6 +134,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java index 2b752b5a92..6a5e12609c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.nio.ByteOrder; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import java.util.Arrays; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; @@ -141,7 +143,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -151,6 +153,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = getIntItemNormalized(i); } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.java index 1a90f0fff4..897c29d998 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.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. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.util.Arrays; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; @@ -136,7 +138,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -146,6 +148,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java index a675b713c4..a1aaf8addb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -64,6 +64,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -229,6 +230,7 @@ static void clear(Node inliningTarget, ForeignSequenceStorage storage, for (int i = size - 1; i >= 0; i--) { removeNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, size); storage.setNewLength(0); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.java index f450c1a47f..a3bdd83e39 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.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. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.util.Arrays; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; @@ -136,7 +138,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -146,6 +148,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.java index fbbe102bfc..6e820e6219 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.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. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.util.Arrays; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; @@ -136,7 +138,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -146,6 +148,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java index 00ae70afde..a9ea0b1c10 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java @@ -25,13 +25,16 @@ */ package com.oracle.graal.python.runtime.sequence.storage; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; + public abstract class SequenceStorageFactory { private SequenceStorageFactory() { // no instances } - public static SequenceStorage createStorage(Object[] values) { + public static SequenceStorage createStorage(Node inliningTarget, Object[] values) { assert values != null; assert values.getClass() == Object[].class : "cannot use non-Object array for modifiable list"; @@ -42,36 +45,38 @@ public static SequenceStorage createStorage(Object[] values) { return EmptySequenceStorage.INSTANCE; } - if (canSpecializeToInt(values)) { - return new IntSequenceStorage(specializeToInt(values)); - } else if (canSpecializeToDouble(values)) { - return new DoubleSequenceStorage(specializeToDouble(values)); - } else if (canSpecializeToLong(values)) { - return new LongSequenceStorage(specializeToLong(values)); - } else if (canSpecializeToBool(values)) { - return new BoolSequenceStorage(specializeToBool(values)); + if (canSpecializeToInt(inliningTarget, values)) { + return new IntSequenceStorage(specializeToInt(inliningTarget, values)); + } else if (canSpecializeToDouble(inliningTarget, values)) { + return new DoubleSequenceStorage(specializeToDouble(inliningTarget, values)); + } else if (canSpecializeToLong(inliningTarget, values)) { + return new LongSequenceStorage(specializeToLong(inliningTarget, values)); + } else if (canSpecializeToBool(inliningTarget, values)) { + return new BoolSequenceStorage(specializeToBool(inliningTarget, values)); } else { return new ObjectSequenceStorage(values); } } - private static boolean canSpecializeToInt(Object[] values) { - for (Object item : values) { - if (!(item instanceof Integer)) { + private static boolean canSpecializeToInt(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + if (!(values[i] instanceof Integer)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static int[] specializeToInt(Object[] values) { + private static int[] specializeToInt(Node inliningTarget, Object[] values) { final int[] intVals = new int[values.length]; for (int i = 0; i < values.length; i++) { intVals[i] = (int) values[i]; } + LoopNode.reportLoopCount(inliningTarget, values.length); return intVals; } @@ -95,63 +100,70 @@ private static byte[] specializeToByte(Object[] values) { return byteVals; } - private static boolean canSpecializeToLong(Object[] values) { - for (Object item : values) { + private static boolean canSpecializeToLong(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + Object item = values[i]; if (!(item instanceof Long || item instanceof Integer)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static long[] specializeToLong(Object[] values) { + private static long[] specializeToLong(Node inliningTarget, Object[] values) { final long[] intVals = new long[values.length]; for (int i = 0; i < values.length; i++) { long value = (values[i] instanceof Integer) ? (long) ((int) values[i]) : (long) values[i]; intVals[i] = value; } + LoopNode.reportLoopCount(inliningTarget, values.length); return intVals; } - private static boolean canSpecializeToDouble(Object[] values) { - for (Object item : values) { - if (!(item instanceof Double)) { + private static boolean canSpecializeToDouble(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + if (!(values[i] instanceof Double)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static double[] specializeToDouble(Object[] values) { + private static double[] specializeToDouble(Node inliningTarget, Object[] values) { final double[] doubles = new double[values.length]; for (int i = 0; i < values.length; i++) { doubles[i] = (double) values[i]; } + LoopNode.reportLoopCount(inliningTarget, values.length); return doubles; } - private static boolean canSpecializeToBool(Object[] values) { - for (Object item : values) { - if (!(item instanceof Boolean)) { + private static boolean canSpecializeToBool(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + if (!(values[i] instanceof Boolean)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static boolean[] specializeToBool(Object[] values) { + private static boolean[] specializeToBool(Node inliningTarget, Object[] values) { final boolean[] bools = new boolean[values.length]; for (int i = 0; i < values.length; i++) { bools[i] = (boolean) values[i]; } + LoopNode.reportLoopCount(inliningTarget, values.length); return bools; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java index 66b8f999aa..d34b3c7652 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java @@ -97,6 +97,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.InvalidAssumptionException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeUtil; import com.oracle.truffle.api.nodes.NodeVisitor; @@ -803,6 +804,7 @@ public static TruffleString[] objectArrayToTruffleStringArray(Node inliningTarge for (int i = 0; i < array.length; i++) { result[i] = PythonUtils.internString(cast.execute(inliningTarget, array[i])); } + LoopNode.reportLoopCount(inliningTarget, array.length); return result; } @@ -922,11 +924,12 @@ public static Object pythonObjectFromConstantValue(ConstantValue v) { } } - public static long crc32(int initialValue, byte[] bytes, int offset, int length) { + public static long crc32(Node inliningTarget, int initialValue, byte[] bytes, int offset, int length) { int crc = ~initialValue; for (int i = 0; i < length; ++i) { crc = CRC_32_TAB[(crc ^ bytes[offset + i]) & 0xff] ^ (crc >>> 8); } + LoopNode.reportLoopCount(inliningTarget, length); return ~crc & 0xFFFFFFFFL; } @@ -965,11 +968,12 @@ public static long crc32(int initialValue, byte[] bytes, int offset, int length) 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; - public static long crcHqx(int initialValue, byte[] bytes, int offset, int length) { + public static long crcHqx(Node inliningTarget, int initialValue, byte[] bytes, int offset, int length) { int crc = initialValue & 0xffff; for (int i = offset; i < length; i++) { crc = ((crc << 8) & 0xff00) ^ CRC_HQX_TAB[(crc >>> 8) ^ (bytes[i] & 0xff)]; } + LoopNode.reportLoopCount(inliningTarget, length - offset); return crc; } From 41154e57d648ae5e6f72cdaad35f4ca81aee126b Mon Sep 17 00:00:00 2001 From: stepan Date: Tue, 6 Oct 2026 12:20:26 +0200 Subject: [PATCH 002/129] Fix PBaseExceptionGroup copyright year (cherry picked from commit 5022a3ab9b008b6f97bb563d9b76b7394974c75d) --- .../python/builtins/objects/exception/PBaseExceptionGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java index 163c7ffd49..9aa81b46bc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 From 408297cd657d1424137e8adb0b5abb86cff4f918 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 19:17:12 +0200 Subject: [PATCH 003/129] Implement basic Windows console support (cherry picked from commit ff9eddd706124c2da12edbac338d5542a306ba1c) --- .../graal/python/shell/GraalPythonMain.java | 6 + .../graal/python/builtins/Python3Core.java | 4 + .../builtins/PythonBuiltinClassType.java | 3 +- .../builtins/modules/SysModuleBuiltins.java | 38 ++- .../io/AbstractBufferedIOBuiltins.java | 4 +- .../modules/io/BufferedWriterBuiltins.java | 11 +- .../modules/io/CommonFileIOBuiltins.java | 247 ++++++++++++++++++ .../builtins/modules/io/FileIOBuiltins.java | 175 +------------ .../python/builtins/modules/io/PFileIO.java | 1 - .../modules/io/WindowsConsoleIOBuiltins.java | 224 ++++++++++++++++ .../graal/python/nodes/ErrorMessages.java | 5 + .../python/runtime/EmulatedPosixSupport.java | 14 + .../python/runtime/LoggingPosixSupport.java | 18 ++ .../python/runtime/NativePosixSupport.java | 26 ++ .../python/runtime/PosixSupportLibrary.java | 5 + .../python/runtime/PreInitPosixSupport.java | 16 ++ .../graal/python/runtime/PythonOptions.java | 3 + graalpython/python-libposix/src/posix.c | 131 ++++++++++ 18 files changed, 745 insertions(+), 186 deletions(-) create mode 100644 graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/CommonFileIOBuiltins.java create mode 100644 graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java diff --git a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java index dcc72a50c3..b082c7b78b 100644 --- a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java +++ b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java @@ -157,6 +157,7 @@ private static void appendDecodedChars(StringBuilder builder, CharBuffer out) { private boolean noUserSite = false; private boolean noSite = false; private boolean unbufferedIO = false; + private boolean legacyWindowsStdio = false; private boolean multiContext = false; private int repeatedRuns = 1; private boolean snaptshotStartup = false; @@ -794,6 +795,7 @@ protected void launch(Builder contextBuilder) { safePath = safePath || getBoolEnv("PYTHONSAFEPATH"); verboseFlag = verboseFlag || getBoolEnv("PYTHONVERBOSE"); unbufferedIO = unbufferedIO || getBoolEnv("PYTHONUNBUFFERED"); + legacyWindowsStdio = getBoolEnv("PYTHONLEGACYWINDOWSSTDIO"); dontWriteBytecode = dontWriteBytecode || getBoolEnv("PYTHONDONTWRITEBYTECODE"); String maxStrDigitsEnv = getEnv("PYTHONINTMAXSTRDIGITS"); if (intMaxStrDigits < 0 && maxStrDigitsEnv != null) { @@ -877,6 +879,9 @@ protected void launch(Builder contextBuilder) { } contextBuilder.option("python.IgnoreEnvironmentFlag", Boolean.toString(ignoreEnv)); contextBuilder.option("python.UnbufferedIO", Boolean.toString(unbufferedIO)); + if (IS_WINDOWS) { + contextBuilder.option("python.LegacyWindowsStdio", Boolean.toString(legacyWindowsStdio)); + } ConsoleHandler consoleHandler = createConsoleHandler(System.in, System.out); contextBuilder.arguments(getLanguageId(), programArgs.toArray(new String[programArgs.size()])); @@ -1288,6 +1293,7 @@ protected void printHelp(OptionCategory maxCategory) { "PYTHON_CPU_COUNT: override the return value of os.cpu_count() (-X cpu_count).\n" + "PYTHONCASEOK : ignore case in 'import' statements (Windows).\n" + "PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n" + + "PYTHONLEGACYWINDOWSSTDIO: use legacy Windows console I/O.\n" + "PYTHONHASHSEED: if this variable is set to 'random', the effect is the same\n" + " as specifying the -R option: a random value is used to seed the hashes of\n" + " str, bytes and datetime objects. It can also be set to an integer\n" + 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 80d97b5b94..0269286bc3 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 @@ -179,6 +179,7 @@ import com.oracle.graal.python.builtins.modules.io.BufferedWriterBuiltins; import com.oracle.graal.python.builtins.modules.io.BufferedWriterMixinBuiltins; import com.oracle.graal.python.builtins.modules.io.BytesIOBuiltins; +import com.oracle.graal.python.builtins.modules.io.CommonFileIOBuiltins; import com.oracle.graal.python.builtins.modules.io.FileIOBuiltins; import com.oracle.graal.python.builtins.modules.io.IOBaseBuiltins; import com.oracle.graal.python.builtins.modules.io.IOBaseDictBuiltins; @@ -188,6 +189,7 @@ import com.oracle.graal.python.builtins.modules.io.StringIOBuiltins; import com.oracle.graal.python.builtins.modules.io.TextIOBaseBuiltins; import com.oracle.graal.python.builtins.modules.io.TextIOWrapperBuiltins; +import com.oracle.graal.python.builtins.modules.io.WindowsConsoleIOBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONEncoderBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONModuleBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONScannerBuiltins; @@ -632,7 +634,9 @@ private static PythonBuiltins[] initializeBuiltins(TruffleLanguage.Env env) { new BufferedReaderMixinBuiltins(), new BufferedWriterMixinBuiltins(), new BufferedIOMixinBuiltins(), + new CommonFileIOBuiltins(), new FileIOBuiltins(), + new WindowsConsoleIOBuiltins(), new TextIOWrapperBuiltins(), new IncrementalNewlineDecoderBuiltins(), new BufferedRWPairBuiltins(), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index 416b1ccd48..a96555806d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -120,6 +120,7 @@ import com.oracle.graal.python.builtins.modules.io.IncrementalNewlineDecoderBuiltins; import com.oracle.graal.python.builtins.modules.io.StringIOBuiltins; import com.oracle.graal.python.builtins.modules.io.TextIOWrapperBuiltins; +import com.oracle.graal.python.builtins.modules.io.WindowsConsoleIOBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONEncoderBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONScannerBuiltins; import com.oracle.graal.python.builtins.modules.lsprof.ProfilerBuiltins; @@ -921,7 +922,7 @@ It can be called either on the class (e.g. C.f()) or on an instance "BufferedRandom", PBufferedIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(BufferedReaderMixinBuiltins.SLOTS, BufferedIOMixinBuiltins.SLOTS, BufferedRandomBuiltins.SLOTS)), - PWindowsConsoleIO("_WindowsConsoleIO", PRawIOBase, newBuilder().moduleName("_io").basetype()), + PWindowsConsoleIO("_WindowsConsoleIO", PRawIOBase, newBuilder().moduleName("_io").basetype().addDict().slots(WindowsConsoleIOBuiltins.SLOTS)), PFileIO("FileIO", PRawIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(FileIOBuiltins.SLOTS)), PTextIOWrapper("TextIOWrapper", PTextIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(TextIOWrapperBuiltins.SLOTS)), PIncrementalNewlineDecoder("IncrementalNewlineDecoder", PythonObject, newBuilder().publishInModule("_io").basetype().slots(IncrementalNewlineDecoderBuiltins.SLOTS)), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index d7b29a3966..08d77d6b44 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -50,6 +50,7 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.DeprecationWarning; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ImportError; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PWindowsConsoleIO; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeWarning; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; @@ -174,6 +175,7 @@ import com.oracle.graal.python.builtins.modules.io.PFileIO; import com.oracle.graal.python.builtins.modules.io.PTextIO; import com.oracle.graal.python.builtins.modules.io.TextIOWrapperNodesFactory.TextIOWrapperInitNodeGen; +import com.oracle.graal.python.builtins.modules.io.WindowsConsoleIOBuiltins; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PythonAbstractObject; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; @@ -811,15 +813,33 @@ static void initStd(Python3Core core) { BufferedReaderBuiltins.BufferedReaderInit.internalInit(stdinBuffer, stdinFileIO, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); setWrapper(T_STDIN, T___STDIN__, T_R, stdioEncoding, stdioError, PNone.NONE, stdinBuffer, sysModule, language, true); - PFileIO stdoutFileIO = PFactory.createFileIO(language); - FileIOBuiltins.FileIOInit.internalInit(stdoutFileIO, toTruffleStringUncached(""), 1, IOMode.WB); + PFileIO stdoutFileIO = createStdoutRaw(context, language, posixSupport, posixLib, toTruffleStringUncached(""), 1); Object stdoutBuffer = createBufferedIO(buffering, language, stdoutFileIO, posixSupport, posixLib); - setWrapper(T_STDOUT, T___STDOUT__, T_W, stdioEncoding, stdioError, PNone.NONE, stdoutBuffer, sysModule, language, buffering); + TruffleString stdoutEncoding = isWindowsConsoleIO(stdoutFileIO) ? StringLiterals.T_UTF8 : stdioEncoding; + setWrapper(T_STDOUT, T___STDOUT__, T_W, stdoutEncoding, stdioError, PNone.NONE, stdoutBuffer, sysModule, language, buffering); - PFileIO stderr = PFactory.createFileIO(language); - FileIOBuiltins.FileIOInit.internalInit(stderr, toTruffleStringUncached(""), 2, IOMode.WB); + PFileIO stderr = createStdoutRaw(context, language, posixSupport, posixLib, toTruffleStringUncached(""), 2); Object stderrBuffer = createBufferedIO(buffering, language, stderr, posixSupport, posixLib); - setWrapper(T_STDERR, T___STDERR__, T_W, stdioEncoding, T_BACKSLASHREPLACE, PNone.NONE, stderrBuffer, sysModule, language, buffering); + TruffleString stderrEncoding = isWindowsConsoleIO(stderr) ? StringLiterals.T_UTF8 : stdioEncoding; + setWrapper(T_STDERR, T___STDERR__, T_W, stderrEncoding, T_BACKSLASHREPLACE, PNone.NONE, stderrBuffer, sysModule, language, buffering); + } + + private static PFileIO createStdoutRaw(PythonContext context, PythonLanguage language, Object posixSupport, PosixSupportLibrary posixLib, TruffleString name, int fd) { + if (getPythonOS() == PLATFORM_WIN32 && !context.getOption(PythonOptions.LegacyWindowsStdio)) { + int consoleType = posixLib.getWindowsConsoleType(posixSupport, fd); + if (consoleType != 0) { + PFileIO consoleIO = WindowsConsoleIOBuiltins.create(language); + WindowsConsoleIOBuiltins.internalInit(consoleIO, name, fd, IOMode.WB, consoleType); + return consoleIO; + } + } + PFileIO fileIO = PFactory.createFileIO(language); + FileIOBuiltins.FileIOInit.internalInit(fileIO, name, fd, IOMode.WB); + return fileIO; + } + + private static boolean isWindowsConsoleIO(PFileIO fileIO) { + return getPythonOS() == PLATFORM_WIN32 && fileIO.getPythonClass() == PWindowsConsoleIO; } private static Object createBufferedIO(boolean buffering, PythonLanguage language, PFileIO fileIo, Object posixSupport, PosixSupportLibrary posixLib) { @@ -827,7 +847,11 @@ private static Object createBufferedIO(boolean buffering, PythonLanguage languag return fileIo; } PBuffered writer = PFactory.createBufferedWriter(language); - BufferedWriterBuiltins.BufferedWriterInit.internalInit(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); + if (isWindowsConsoleIO(fileIo)) { + BufferedWriterBuiltins.BufferedWriterInit.internalInitConsole(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language); + } else { + BufferedWriterBuiltins.BufferedWriterInit.internalInit(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); + } return writer; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java index 63de30bfea..c32199d450 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.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 @@ -104,7 +104,7 @@ static void bufferSizeError(PBuffered self, int bufferSize, throw PRaiseNode.raiseStatic(inliningTarget, ValueError, BUF_SIZE_POS); } - private static void init(PBuffered self, int bufferSize, PythonLanguage language) { + static void init(PBuffered self, int bufferSize, PythonLanguage language) { self.initBuffer(bufferSize); self.setLock(PFactory.createLock(language)); self.setOwner(0); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java index 5fd24560bf..82339302c7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.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 @@ -125,6 +125,15 @@ public static void internalInit(PBuffered self, PFileIO raw, int bufferSize, Pyt self.setOK(true); } + + public static void internalInitConsole(PBuffered self, PFileIO raw, int bufferSize, PythonLanguage language) { + self.setDetached(false); + self.setRaw(raw, false); + BufferedInitNode.init(self, bufferSize, language); + self.resetWrite(); + self.setPos(0); + self.setOK(true); + } } // BufferedWriter(raw[, buffer_size=DEFAULT_BUFFER_SIZE]) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/CommonFileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/CommonFileIOBuiltins.java new file mode 100644 index 0000000000..c2128c6f1f --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/CommonFileIOBuiltins.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 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 + * + * 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.builtins.modules.io; + +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PFileIO; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PRawIOBase; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PWindowsConsoleIO; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSED; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSEFD; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_FILENO; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_MODE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READABLE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITABLE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.T_CLOSE; +import static com.oracle.graal.python.nodes.ErrorMessages.IO_CLOSED; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; + +import java.util.List; + +import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins; +import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltins; +import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.lib.PyErrChainExceptions; +import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +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.strings.TruffleString; + +@CoreFunctions(extendClasses = {PFileIO, PWindowsConsoleIO}) +public final class CommonFileIOBuiltins extends PythonBuiltins { + @Override + protected List> getNodeFactories() { + return CommonFileIOBuiltinsFactory.getFactories(); + } + + @Builtin(name = J_CLOSE, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class CloseNode extends PythonUnaryBuiltinNode { + @Specialization(guards = "!self.isCloseFD()") + static Object simple(VirtualFrame frame, PFileIO self, + @Bind Node inliningTarget, + @Exclusive @Cached PyObjectCallMethodObjArgs callClose) { + try { + callClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); + } catch (PException e) { + self.setClosed(); + throw e; + } + self.setClosed(); + return PNone.NONE; + } + + @Specialization(guards = {"self.isCloseFD()", "!self.isFinalizing()"}) + static Object common(VirtualFrame frame, PFileIO self, + @Bind Node inliningTarget, + @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, + @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, + @Shared @Cached PyErrChainExceptions chainExceptions) { + try { + callSuperClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); + } catch (PException e) { + try { + FileIOBuiltins.internalClose(frame, self, posixClose); + } catch (PException ee) { + throw chainExceptions.execute(inliningTarget, ee, e); + } + throw e; + } + FileIOBuiltins.internalClose(frame, self, posixClose); + return PNone.NONE; + } + + @Specialization(guards = {"self.isCloseFD()", "self.isFinalizing()"}) + static Object slow(VirtualFrame frame, PFileIO self, + @Bind Node inliningTarget, + @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, + @Cached WarningsModuleBuiltins.WarnNode warnNode, + @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, + @Shared @Cached PyErrChainExceptions chainExceptions) { + PException rawIOException = null; + PythonContext context = PythonContext.get(inliningTarget); + try { + callSuperClose.execute(frame, inliningTarget, context.lookupType(PRawIOBase), T_CLOSE, self); + } catch (PException e) { + rawIOException = e; + } + FileIOBuiltins.deallocWarn(frame, self, warnNode); + try { + FileIOBuiltins.internalClose(frame, self, posixClose); + } catch (PException ee) { + if (rawIOException != null) { + throw chainExceptions.execute(inliningTarget, ee, rawIOException); + } else { + throw ee; + } + } + if (rawIOException != null) { + throw rawIOException; + } + return PNone.NONE; + } + } + + @Builtin(name = J_READABLE, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class ReadableNode extends PythonUnaryBuiltinNode { + @Specialization(guards = "!self.isClosed()") + static Object readable(PFileIO self) { + return self.isReadable(); + } + + @Specialization(guards = "self.isClosed()") + static Object closedError(@SuppressWarnings("unused") PFileIO self, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + } + + @Builtin(name = J_WRITABLE, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class WritableNode extends PythonUnaryBuiltinNode { + @Specialization(guards = "!self.isClosed()") + static Object writable(PFileIO self) { + return self.isWritable(); + } + + @Specialization(guards = "self.isClosed()") + static Object closedError(@SuppressWarnings("unused") PFileIO self, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + } + + @Builtin(name = J_FILENO, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class FilenoNode extends PythonBuiltinNode { + @Specialization(guards = "!self.isClosed()") + static Object fileno(PFileIO self) { + return self.getFD(); + } + + @Specialization(guards = "self.isClosed()") + static Object closedError(@SuppressWarnings("unused") PFileIO self, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + } + + @Builtin(name = J_CLOSED, minNumOfPositionalArgs = 1, isGetter = true) + @GenerateNodeFactory + abstract static class ClosedNode extends PythonUnaryBuiltinNode { + @Specialization + static Object doit(PFileIO self) { + return self.getFD() < 0; + } + } + + @Builtin(name = J_CLOSEFD, minNumOfPositionalArgs = 1, isGetter = true) + @GenerateNodeFactory + abstract static class CloseFDNode extends PythonUnaryBuiltinNode { + @Specialization + static Object doit(PFileIO self) { + return self.isCloseFD(); + } + } + + @Builtin(name = J_MODE, minNumOfPositionalArgs = 1, isGetter = true) + @GenerateNodeFactory + abstract static class ModeNode extends PythonUnaryBuiltinNode { + private static final TruffleString T_XB = tsLiteral("xb"); + private static final TruffleString T_XBP = tsLiteral("xb+"); + private static final TruffleString T_AB = tsLiteral("ab"); + private static final TruffleString T_ABP = tsLiteral("ab+"); + private static final TruffleString T_RB = tsLiteral("rb"); + private static final TruffleString T_RBP = tsLiteral("rb+"); + private static final TruffleString T_WB = tsLiteral("wb"); + + @Specialization + static TruffleString mode(PFileIO self) { + if (self.isCreated()) { + return self.isReadable() ? T_XBP : T_XB; + } + if (self.isAppending()) { + return self.isReadable() ? T_ABP : T_AB; + } else if (self.isReadable()) { + return self.isWritable() ? T_RBP : T_RB; + } + return T_WB; + } + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index b308aaf531..c462d056a4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -42,33 +42,24 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IOUnsupportedOperation; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.OverflowError; -import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PRawIOBase; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError; import static com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.mapPythonSeekWhenceToPosix; import static com.oracle.graal.python.builtins.modules.io.BufferedIOUtil.SEEK_CUR; import static com.oracle.graal.python.builtins.modules.io.BufferedIOUtil.SEEK_END; import static com.oracle.graal.python.builtins.modules.io.IOBaseBuiltins.BUFSIZ; import static com.oracle.graal.python.builtins.modules.io.IOModuleBuiltins.DEFAULT_BUFFER_SIZE; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSE; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSED; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSEFD; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_FILENO; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_ISATTY; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_MODE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READ; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READABLE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READALL; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READINTO; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_SEEK; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_SEEKABLE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_TELL; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_TRUNCATE; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITABLE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J__BLKSIZE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J__DEALLOC_WARN; import static com.oracle.graal.python.builtins.modules.io.IONodes.J__FINALIZING; -import static com.oracle.graal.python.builtins.modules.io.IONodes.T_CLOSE; import static com.oracle.graal.python.builtins.modules.io.IONodes.T_NAME; import static com.oracle.graal.python.builtins.objects.bytes.BytesUtils.append; import static com.oracle.graal.python.builtins.objects.bytes.BytesUtils.createOutputStream; @@ -127,10 +118,8 @@ import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TypeNodes; -import com.oracle.graal.python.lib.PyErrChainExceptions; import com.oracle.graal.python.lib.PyIndexCheckNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; -import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectIsTrueNode; import com.oracle.graal.python.lib.PyObjectLookupAttr; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; @@ -159,7 +148,6 @@ import com.oracle.truffle.api.ThreadLocalAction.Access; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; @@ -877,74 +865,6 @@ static Object closedError(PFileIO self, Object posobj, } } - @Builtin(name = J_CLOSE, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class CloseNode extends PythonUnaryBuiltinNode { - @Specialization(guards = "!self.isCloseFD()") - static Object simple(VirtualFrame frame, PFileIO self, - @Bind Node inliningTarget, - @Exclusive @Cached PyObjectCallMethodObjArgs callClose) { - try { - callClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); - } catch (PException e) { - self.setClosed(); - throw e; - } - self.setClosed(); - return PNone.NONE; - } - - @Specialization(guards = {"self.isCloseFD()", "!self.isFinalizing()"}) - static Object common(VirtualFrame frame, PFileIO self, - @Bind Node inliningTarget, - @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, - @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, - @Shared @Cached PyErrChainExceptions chainExceptions) { - try { - callSuperClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); - } catch (PException e) { - try { - internalClose(frame, self, posixClose); - } catch (PException ee) { - throw chainExceptions.execute(inliningTarget, ee, e); - } - throw e; - } - internalClose(frame, self, posixClose); - return PNone.NONE; - } - - @Specialization(guards = {"self.isCloseFD()", "self.isFinalizing()"}) - static Object slow(VirtualFrame frame, PFileIO self, - @Bind Node inliningTarget, - @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, - @Cached WarningsModuleBuiltins.WarnNode warnNode, - @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, - @Shared @Cached PyErrChainExceptions chainExceptions) { - PException rawIOException = null; - PythonContext context = PythonContext.get(inliningTarget); - try { - callSuperClose.execute(frame, inliningTarget, context.lookupType(PRawIOBase), T_CLOSE, self); - } catch (PException e) { - rawIOException = e; - } - deallocWarn(frame, self, warnNode); - try { - internalClose(frame, self, posixClose); - } catch (PException ee) { - if (rawIOException != null) { - throw chainExceptions.execute(inliningTarget, ee, rawIOException); - } else { - throw ee; - } - } - if (rawIOException != null) { - throw rawIOException; - } - return PNone.NONE; - } - } - @Builtin(name = J_SEEKABLE, minNumOfPositionalArgs = 1) @GenerateNodeFactory abstract static class SeekableNode extends PythonUnaryBuiltinNode { @@ -978,51 +898,6 @@ static Object closedError(@SuppressWarnings("unused") PFileIO self, } } - @Builtin(name = J_READABLE, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class ReadableNode extends PythonUnaryBuiltinNode { - @Specialization(guards = "!self.isClosed()") - static Object readable(PFileIO self) { - return self.isReadable(); - } - - @Specialization(guards = "self.isClosed()") - static Object closedError(@SuppressWarnings("unused") PFileIO self, - @Bind Node inliningTarget) { - throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); - } - } - - @Builtin(name = J_WRITABLE, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class WritableNode extends PythonUnaryBuiltinNode { - @Specialization(guards = "!self.isClosed()") - static Object writable(PFileIO self) { - return self.isWritable(); - } - - @Specialization(guards = "self.isClosed()") - static Object closedError(@SuppressWarnings("unused") PFileIO self, - @Bind Node inliningTarget) { - throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); - } - } - - @Builtin(name = J_FILENO, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class FilenoNode extends PythonBuiltinNode { - @Specialization(guards = "!self.isClosed()") - static Object fileno(PFileIO self) { - return self.getFD(); - } - - @Specialization(guards = "self.isClosed()") - static Object closedError(@SuppressWarnings("unused") PFileIO self, - @Bind Node inliningTarget) { - throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); - } - } - @Builtin(name = J_ISATTY, minNumOfPositionalArgs = 1) @GenerateNodeFactory abstract static class IsattyNode extends PythonUnaryBuiltinNode { @@ -1056,54 +931,6 @@ static Object deallocWarn(VirtualFrame frame, PFileIO self, } } - @Builtin(name = J_CLOSED, minNumOfPositionalArgs = 1, isGetter = true) - @GenerateNodeFactory - abstract static class ClosedNode extends PythonUnaryBuiltinNode { - @Specialization - static Object doit(PFileIO self) { - return self.getFD() < 0; - } - } - - @Builtin(name = J_CLOSEFD, minNumOfPositionalArgs = 1, isGetter = true) - @GenerateNodeFactory - abstract static class CloseFDNode extends PythonUnaryBuiltinNode { - @Specialization - static Object doit(PFileIO self) { - return self.isCloseFD(); - } - } - - @Builtin(name = J_MODE, minNumOfPositionalArgs = 1, isGetter = true) - @GenerateNodeFactory - abstract static class ModeNode extends PythonUnaryBuiltinNode { - - public static final TruffleString T_XB = tsLiteral("xb"); - public static final TruffleString T_XBP = tsLiteral("xb+"); - public static final TruffleString T_AB = tsLiteral("ab"); - public static final TruffleString T_ABP = tsLiteral("ab+"); - public static final TruffleString T_RB = tsLiteral("rb"); - public static final TruffleString T_RBP = tsLiteral("rb+"); - public static final TruffleString T_WB = tsLiteral("wb"); - - static TruffleString modeString(PFileIO self) { - if (self.isCreated()) { - return self.isReadable() ? T_XBP : T_XB; - } - if (self.isAppending()) { - return self.isReadable() ? T_ABP : T_AB; - } else if (self.isReadable()) { - return self.isWritable() ? T_RBP : T_RB; - } - return T_WB; - } - - @Specialization - static TruffleString doit(PFileIO self) { - return modeString(self); - } - } - @Builtin(name = J__BLKSIZE, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true) @GenerateNodeFactory abstract static class BlksizeNode extends PythonBinaryBuiltinNode { @@ -1155,7 +982,7 @@ static TruffleString doit(VirtualFrame frame, PFileIO self, @Cached PyObjectReprAsTruffleStringNode repr, @Cached SimpleTruffleStringFormatNode simpleTruffleStringFormatNode, @Cached PRaiseNode raiseNode) { - TruffleString mode = ModeNode.modeString(self); + TruffleString mode = CommonFileIOBuiltins.ModeNode.mode(self); TruffleString closefd = self.isCloseFD() ? T_TRUE : T_FALSE; Object nameobj = lookupName.execute(frame, inliningTarget, self, T_NAME); if (nameobj instanceof PNone) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java index f2ff239b55..ca9c15aa0d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java @@ -80,7 +80,6 @@ public int getFD() { } public void setFD(int fd, PythonContext context) { - assert this.fd == null : "'fd' has not been closed!"; if (closefd) { this.fd = new FD(fd, context); } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java new file mode 100644 index 0000000000..be004a262d --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 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 + * + * 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.builtins.modules.io; + +import static com.oracle.graal.python.annotations.PythonOS.PLATFORM_WIN32; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IOUnsupportedOperation; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PWindowsConsoleIO; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_ISATTY; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.T_NAME; +import static com.oracle.graal.python.nodes.ErrorMessages.CANNOT_OPEN_CONSOLE_INPUT_BUFFER_FOR_WRITING; +import static com.oracle.graal.python.nodes.ErrorMessages.CANNOT_OPEN_NON_CONSOLE_FILE; +import static com.oracle.graal.python.nodes.ErrorMessages.CONSOLE_BUFFER_DOES_NOT_SUPPORT_WRITING; +import static com.oracle.graal.python.nodes.ErrorMessages.CONSOLE_INPUT_IS_NOT_SUPPORTED; +import static com.oracle.graal.python.nodes.ErrorMessages.IO_CLOSED; +import static com.oracle.graal.python.nodes.ErrorMessages.MUST_HAVE_EXACTLY_ONE_OF_READ_WRITE_MODE; +import static com.oracle.graal.python.nodes.ErrorMessages.NEG_FILE_DESC; + +import java.util.List; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.ArgumentClinic; +import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.annotations.Slot; +import com.oracle.graal.python.annotations.Slot.SlotKind; +import com.oracle.graal.python.annotations.Slot.SlotSignature; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; +import com.oracle.graal.python.builtins.objects.type.TpSlots; +import com.oracle.graal.python.builtins.objects.type.TypeNodes; +import com.oracle.graal.python.nodes.PConstructAndRaiseNode; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; +import com.oracle.graal.python.runtime.GilNode; +import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; +import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +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.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; + +@CoreFunctions(extendClasses = PWindowsConsoleIO, os = PLATFORM_WIN32) +public final class WindowsConsoleIOBuiltins extends PythonBuiltins { + private static final int CONSOLE_WRITE = 'w'; + public static final TpSlots SLOTS = WindowsConsoleIOBuiltinsSlotsGen.SLOTS; + + @Override + protected List> getNodeFactories() { + return WindowsConsoleIOBuiltinsFactory.getFactories(); + } + + public static PFileIO create(PythonLanguage language) { + return PFactory.createFileIO(PWindowsConsoleIO, PWindowsConsoleIO.getInstanceShape(language)); + } + + public static void internalInit(PFileIO self, Object name, int fd, IONodes.IOMode mode, int consoleType) { + if (mode.reading == mode.writing || mode.text || mode.universal || mode.isInvalid) { + throw PRaiseNode.raiseStatic(null, ValueError, MUST_HAVE_EXACTLY_ONE_OF_READ_WRITE_MODE); + } + if (mode.reading) { + throw PRaiseNode.raiseStatic(null, ValueError, CONSOLE_INPUT_IS_NOT_SUPPORTED); + } + if (consoleType != CONSOLE_WRITE) { + throw PRaiseNode.raiseStatic(null, ValueError, CANNOT_OPEN_CONSOLE_INPUT_BUFFER_FOR_WRITING); + } + self.setCloseFD(false); + self.setFD(fd, null); + self.setWritable(); + self.setBlksize(IOModuleBuiltins.DEFAULT_BUFFER_SIZE); + WriteAttributeToObjectNode.getUncached().execute(self, T_NAME, name); + } + + @Slot(value = SlotKind.tp_new, isComplex = true) + @SlotSignature(name = "_WindowsConsoleIO", minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true) + @GenerateNodeFactory + abstract static class NewNode extends PythonBuiltinNode { + @Specialization + static PFileIO create(Object cls, @SuppressWarnings("unused") Object file, + @Cached TypeNodes.GetInstanceShape getInstanceShape) { + return PFactory.createFileIO(cls, getInstanceShape.execute(cls)); + } + } + + @Slot(value = SlotKind.tp_init, isComplex = true) + @SlotSignature(name = "_WindowsConsoleIO", minNumOfPositionalArgs = 2, parameterNames = {"$self", "file", "mode", "closefd", "opener"}) + @ArgumentClinic(name = "file", conversion = ArgumentClinic.ClinicConversion.Index) + @ArgumentClinic(name = "mode", conversionClass = IONodes.CreateIOModeNode.class, args = "false") + @ArgumentClinic(name = "closefd", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "true", useDefaultForNone = true) + @GenerateNodeFactory + public abstract static class InitNode extends PythonClinicBuiltinNode { + @Override + protected ArgumentClinicProvider getArgumentClinic() { + return WindowsConsoleIOBuiltinsClinicProviders.InitNodeClinicProviderGen.INSTANCE; + } + + @Specialization + static PNone init(PFileIO self, int file, IONodes.IOMode mode, @SuppressWarnings("unused") boolean closefd, @SuppressWarnings("unused") Object opener, + @Bind Node inliningTarget, + @Bind PythonContext context, + @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { + if (file < 0) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, NEG_FILE_DESC); + } + // We don't release the GIL because CPython doesn't do it + int consoleType = posixLib.getWindowsConsoleType(context.getPosixSupport(), file); + if (consoleType == 0) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, CANNOT_OPEN_NON_CONSOLE_FILE); + } + internalInit(self, file, file, mode, consoleType); + return PNone.NONE; + } + } + + @Builtin(name = J_WRITE, minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 2, parameterNames = {"$self", "b"}) + @ArgumentClinic(name = "b", conversion = ArgumentClinic.ClinicConversion.ReadableBuffer) + @GenerateNodeFactory + abstract static class WriteNode extends PythonBinaryClinicBuiltinNode { + @Override + protected ArgumentClinicProvider getArgumentClinic() { + return WindowsConsoleIOBuiltinsClinicProviders.WriteNodeClinicProviderGen.INSTANCE; + } + + @Specialization(limit = "3") + static Object write(VirtualFrame frame, PFileIO self, Object buffer, + @Bind Node inliningTarget, + @Bind PythonContext context, + @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, + @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached GilNode gil, + @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { + try { + if (self.isClosed()) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + if (!self.isWritable()) { + throw PRaiseNode.raiseStatic(inliningTarget, IOUnsupportedOperation, CONSOLE_BUFFER_DOES_NOT_SUPPORT_WRITING); + } + byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); + int length = bufferLib.getBufferLength(buffer); + try { + gil.release(true); + try { + return posixLib.writeWindowsConsole(context.getPosixSupport(), self.getFD(), new Buffer(bytes, length)); + } finally { + gil.acquire(); + } + } catch (PosixException e) { + throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); + } + } finally { + bufferLib.release(buffer); + } + } + } + + @Builtin(name = J_ISATTY, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class IsattyNode extends PythonUnaryBuiltinNode { + @Specialization + static boolean isatty(PFileIO self, + @Bind Node inliningTarget, + @Cached PRaiseNode raise) { + if (self.isClosed()) { + throw raise.raise(inliningTarget, ValueError, IO_CLOSED); + } + return true; + } + } + +} 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 e8c7d2ad1d..faba298067 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 @@ -1155,6 +1155,11 @@ public abstract class ErrorMessages { public static final TruffleString DETACHED_BUFFER = tsLiteral("underlying buffer has been detached"); public static final TruffleString UNSUPPORTED_WHENCE = tsLiteral("whence value %d unsupported"); public static final TruffleString IO_CLOSED = tsLiteral("I/O operation on closed file."); + public static final TruffleString CANNOT_OPEN_CONSOLE_INPUT_BUFFER_FOR_WRITING = tsLiteral("Cannot open console input buffer for writing"); + public static final TruffleString CANNOT_OPEN_NON_CONSOLE_FILE = tsLiteral("Cannot open non-console file"); + public static final TruffleString CONSOLE_BUFFER_DOES_NOT_SUPPORT_WRITING = tsLiteral("Console buffer does not support writing"); + public static final TruffleString CONSOLE_INPUT_IS_NOT_SUPPORTED = tsLiteral("Console input is not supported"); + public static final TruffleString MUST_HAVE_EXACTLY_ONE_OF_READ_WRITE_MODE = tsLiteral("Must have exactly one of read or write mode"); public static final TruffleString MUST_BE_NON_NEG_OR_NEG_1 = tsLiteral("read length must be non-negative or -1"); public static final TruffleString BUF_SIZE_POS = tsLiteral("buffer size must be strictly positive"); public static final TruffleString S_SHOULD_RETURN_BYTES = tsLiteral("%s should return bytes"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 92241c2cf8..43c6d963b6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -514,6 +514,20 @@ public long write(int fd, Buffer data, } } + @ExportMessage + @SuppressWarnings("unused") + public int getWindowsConsoleType(int fd) { + return 0; + } + + @ExportMessage + public long writeWindowsConsole(int fd, Buffer data, + @Bind Node inliningTarget, + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + return write(fd, data, inliningTarget, errorBranch, eqNode); + } + @TruffleBoundary(allowInlining = true) private static int doWriteOp(ByteBuffer data, WritableByteChannel channel) throws IOException { return channel.write(data); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index f6407c5abc..7313ce5349 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -198,6 +198,24 @@ final long write(int fd, Buffer data, } } + @ExportMessage + final int getWindowsConsoleType(int fd, + @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + logEnter("getWindowsConsoleType", "%d", fd); + return logExit("getWindowsConsoleType", "%d", lib.getWindowsConsoleType(delegate, fd)); + } + + @ExportMessage + final long writeWindowsConsole(int fd, Buffer data, + @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + logEnter("writeWindowsConsole", "%d, %d", fd, data.length); + try { + return logExit("writeWindowsConsole", "%d", lib.writeWindowsConsole(delegate, fd, data)); + } catch (PosixException e) { + throw logException("writeWindowsConsole", e); + } + } + @ExportMessage final int dup(int fd, @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index c74a14fe87..8710d7c53c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -232,6 +232,12 @@ abstract static class PosixNativeFunctionInvoker { @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, POINTER, SINT64}) abstract long call_write(int fd, long buf, long count); + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_get_windows_console_type(int fd); + + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, POINTER, SINT64}) + abstract long call_write_windows_console(int fd, long buf, long count); + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) abstract int call_dup(int fd); @@ -796,6 +802,26 @@ public long write(int fd, Buffer data) throws PosixException { } } + @ExportMessage + public int getWindowsConsoleType(int fd) { + return posixNativeFunctionInvoker.call_get_windows_console_type(fd); + } + + @ExportMessage + public long writeWindowsConsole(int fd, Buffer data) throws PosixException { + long nativeBuffer = NativeMemory.mallocByteArrayOrNull(data.length); + try { + NativeMemory.writeByteArrayElements(nativeBuffer, 0, data.data, 0, (int) data.length); + long n = posixNativeFunctionInvoker.call_write_windows_console(fd, nativeBuffer, data.length); + if (n < 0) { + throw getErrnoAndThrowPosixException(); + } + return n; + } finally { + NativeMemory.free(nativeBuffer); + } + } + @ExportMessage public int dup(int fd) throws PosixException { int newFd = posixNativeFunctionInvoker.call_dup(fd); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 1d4ddb47be..3a7b18cc1f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -96,6 +96,11 @@ public abstract class PosixSupportLibrary extends Library { public abstract long write(Object receiver, int fd, Buffer data) throws PosixException; + /** Returns {@code 'r'}, {@code 'w'}, or zero when {@code fd} is not a Windows console. */ + public abstract int getWindowsConsoleType(Object receiver, int fd); + + public abstract long writeWindowsConsole(Object receiver, int fd, Buffer data) throws PosixException; + public abstract int dup(Object receiver, int fd) throws PosixException; public abstract int dup2(Object receiver, int fd, int fd2, boolean inheritable) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index eff964a8bd..81d70eafda 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -212,6 +212,22 @@ final long write(int fd, Buffer data, return nativeLib.write(nativePosixSupport, fd, data); } + @ExportMessage + final int getWindowsConsoleType(int fd, + @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + if (inPreInitialization) { + return 0; + } + return nativeLib.getWindowsConsoleType(nativePosixSupport, fd); + } + + @ExportMessage + final long writeWindowsConsole(int fd, Buffer data, + @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + checkNotInPreInitialization(); + return nativeLib.writeWindowsConsole(nativePosixSupport, fd, data); + } + @ExportMessage final int dup(int fd, @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java index 962f9298e7..dc51eceb29 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java @@ -143,6 +143,9 @@ private PythonOptions() { @Option(category = OptionCategory.USER, help = "Equivalent to the Python -u flag. Force stdout and stderr to be unbuffered.", usageSyntax = "true|false", stability = OptionStability.STABLE) // public static final OptionKey UnbufferedIO = new OptionKey<>(false); + @Option(category = OptionCategory.USER, help = "Equivalent to setting the PYTHONLEGACYWINDOWSSTDIO environment variable for the standard launcher.", usageSyntax = "true|false", stability = OptionStability.STABLE) // + public static final OptionKey LegacyWindowsStdio = new OptionKey<>(false); + @Option(category = OptionCategory.USER, help = "Equivalent to the Python -I flag. Isolate from the users environment by not adding the cwd to the path", usageSyntax = "true|false", stability = OptionStability.STABLE) // public static final OptionKey IsolateFlag = new OptionKey<>(false); diff --git a/graalpython/python-libposix/src/posix.c b/graalpython/python-libposix/src/posix.c index df8d2bb45b..ae205e8e31 100644 --- a/graalpython/python-libposix/src/posix.c +++ b/graalpython/python-libposix/src/posix.c @@ -1161,6 +1161,123 @@ GP_EXPORT int64_t call_write(int32_t fd, void *buf, uint64_t count) { return write_noraise(fd, buf, count > INT_MAX ? INT_MAX : (unsigned int) count); } +GP_EXPORT int32_t call_get_windows_console_type(int32_t fd) { + intptr_t osfhandle = get_osfhandle_noraise(fd); + if (osfhandle == -1) { + return 0; + } + HANDLE handle = (HANDLE) osfhandle; + DWORD mode; + if (!GetConsoleMode(handle, &mode)) { + return 0; + } + DWORD event_count; + return GetNumberOfConsoleInputEvents(handle, &event_count) ? 'r' : 'w'; +} + +/* Copied from CPython's Modules/_io/winconsoleio.c (_find_last_utf8_boundary). */ +static uint32_t find_last_utf8_boundary(const unsigned char *buf, uint32_t len) { + for (uint32_t count = 1; count < 4 && count <= len; count++) { + unsigned char c = buf[len - count]; + if (c < 0x80) { + return len; + } + if (c >= 0xc0) { + if (c < 0xe0 ? count < 2 : c < 0xf0 ? count < 3 : c < 0xf8 ? count < 4 : 0) { + return len - count; + } + return len; + } + } + return len; +} + +static uint32_t wchar_to_utf8_count(const unsigned char *s, uint32_t len, uint32_t n) { + uint32_t start = 0; + while (1) { + uint32_t mid = 0; + for (uint32_t i = len / 2; i <= len; i++) { + mid = find_last_utf8_boundary(s, i); + if (mid != 0) { + break; + } + } + if (mid == len) { + uint32_t wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) s, len, NULL, 0); + return wlen <= n ? start + len : start; + } + if (mid == 0) { + mid = len > 1 ? len - 1 : 1; + } + uint32_t wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) s, mid, NULL, 0); + if (wlen <= n) { + s += mid; + start += mid; + len -= mid; + n -= wlen; + } else { + len = mid; + } + } +} + +GP_EXPORT int64_t call_write_windows_console(int32_t fd, const unsigned char *buf, uint64_t count) { + intptr_t osfhandle = get_osfhandle_noraise(fd); + if (osfhandle == -1) { + capture_errno(); + return -1; + } + if (count == 0) { + return 0; + } + + const uint32_t max_wlen = 32766U / sizeof(wchar_t); + // Like CPython, write at most one bounded chunk and let the caller handle partial writes. + uint32_t len = count > max_wlen * 3U ? max_wlen * 3U : (uint32_t) count; + uint32_t wlen; + while (1) { + uint32_t boundary = find_last_utf8_boundary(buf, len); + // If the whole chunk is incomplete UTF-8, convert it to replacement characters rather + // than returning zero forever when a buffered caller tries to flush it. + if (boundary != 0) { + len = boundary; + } + wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) buf, len, NULL, 0); + if (wlen == 0) { + set_win_errno(GetLastError()); + return -1; + } + if (wlen <= max_wlen) { + break; + } + len /= 2; + } + + wchar_t *wbuf = (wchar_t *) malloc(wlen * sizeof(wchar_t)); + if (wbuf == NULL) { + set_posix_errno(ENOMEM); + return -1; + } + wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) buf, len, wbuf, wlen); + DWORD written = 0; + BOOL result = wlen && WriteConsoleW((HANDLE) osfhandle, wbuf, wlen, &written, NULL); + if (!result) { + DWORD error = GetLastError(); + free(wbuf); + set_win_errno(error); + return -1; + } + free(wbuf); + if (written < wlen) { + len = wchar_to_utf8_count(buf, len, written); + } + if (len == 0) { + set_posix_errno(EIO); + return -1; + } + return len; +} + GP_EXPORT int32_t call_dup(int32_t fd) { if (win_socket_entry_index(fd) >= 0) { return win_socket_dup(fd); @@ -2443,6 +2560,20 @@ int64_t call_write(int32_t fd, void *buf, uint64_t count) { CAPTURE_ERRNO_AND_RETURN(-1, write(fd, buf, count)); } +int32_t call_get_windows_console_type(int32_t fd) { + (void) fd; + return 0; +} + +int64_t call_write_windows_console(int32_t fd, const void *buf, uint64_t count) { + (void) fd; + (void) buf; + (void) count; + errno = ENOSYS; + capture_errno(); + return -1; +} + int32_t call_dup(int32_t fd) { CAPTURE_ERRNO_AND_RETURN(-1, fcntl(fd, F_DUPFD_CLOEXEC, 0)); } From d1c99392cd715a3da682cb89ea30f21939d282c1 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 7 Oct 2026 17:00:11 +0200 Subject: [PATCH 004/129] Fix async generator aclose Fixes #1196 (cherry picked from commit 2bedaad9a80bfd452e7dc1de0895016601ebf03b) --- .../src/tests/test_generators.py | 27 +++++++++++++++++++ .../src/tests/unittest_tags/test_asyncgen.txt | 4 +++ .../asyncio/AsyncGenThrowBuiltins.java | 7 ++--- .../graal/python/nodes/ErrorMessages.java | 1 + 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py b/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py index 643e8d2cde..3ef5a5b2eb 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py @@ -9,6 +9,33 @@ from tests import util +class AsyncGeneratorTest(unittest.TestCase): + def test_aclose_await_in_finally(self): + resumed = [] + + class Suspend: + def __await__(self): + return (yield "suspended") + + async def gen(): + try: + yield 1 + finally: + resumed.append(await Suspend()) + + g = gen() + with self.assertRaises(StopIteration) as cm: + g.__anext__().send(None) + self.assertEqual(cm.exception.value, 1) + + close = g.aclose() + self.assertEqual(close.send(None), "suspended") + self.assertEqual(resumed, []) + with self.assertRaises(StopIteration): + close.send(42) + self.assertEqual(resumed, [42]) + + class ExceptionTest(unittest.TestCase): # Tests for the issue #23353: check that the currently handled exception # is correctly saved/restored in PyEval_EvalFrameEx(). diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt index e3259b3eec..5e63c3f0e5 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt @@ -14,8 +14,12 @@ test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_aiter_class @ darwin-arm64 test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_01 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_02 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_03 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_06 @ linux-x86_64 +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_07 @ linux-x86_64 +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_08 @ linux-x86_64 test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_10 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_11 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_12 @ linux-x86_64 test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_anext_04 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_anext_05 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_anext_06 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.java index 749e361a53..c03e05b545 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.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 @@ -41,7 +41,7 @@ package com.oracle.graal.python.builtins.objects.asyncio; import static com.oracle.graal.python.builtins.objects.asyncio.PAsyncGenASend.AwaitableState; -import static com.oracle.graal.python.nodes.ErrorMessages.GENERATOR_IGNORED_EXIT; +import static com.oracle.graal.python.nodes.ErrorMessages.ASYNCGEN_IGNORED_EXIT; import static com.oracle.graal.python.nodes.ErrorMessages.SEND_NON_NONE_TO_UNSTARTED_GENERATOR; import java.util.List; @@ -174,6 +174,7 @@ public Object send(VirtualFrame frame, PAsyncGenAThrow self, Object sent, if (isAGWrappedValue.profileObject(inliningTarget, retval, PythonBuiltinClassType.PAsyncGenAWrappedValue)) { throw yieldClose(inliningTarget, self, gen); } + return retval; } else { // athrow mode try { @@ -212,7 +213,7 @@ public Object send(VirtualFrame frame, PAsyncGenAThrow self, Object sent, static PException yieldClose(Node inliningTarget, PAsyncGenAThrow athrow, PAsyncGen gen) { gen.setRunningAsync(false); athrow.setState(AwaitableState.CLOSED); - return PRaiseNode.raiseStatic(inliningTarget, PythonBuiltinClassType.RuntimeError, GENERATOR_IGNORED_EXIT); + return PRaiseNode.raiseStatic(inliningTarget, PythonBuiltinClassType.RuntimeError, ASYNCGEN_IGNORED_EXIT); } static PException checkError(PAsyncGenAThrow athrow, PAsyncGen gen, PException exception, 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 faba298067..c3b1c1ec55 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 @@ -1468,6 +1468,7 @@ public abstract class ErrorMessages { public static final TruffleString AGEN_ALREADY_RUNNING = tsLiteral("anext(): asynchronous generator is already running"); public static final TruffleString CORO_ALREADY_AWAITED = tsLiteral("coroutine is being awaited already"); public static final TruffleString ANEXT_INVALID_OBJECT = tsLiteral("'async for' received an invalid object from __anext__: %p"); + public static final TruffleString ASYNCGEN_IGNORED_EXIT = tsLiteral("async generator ignored GeneratorExit"); public static final TruffleString ASYNCGEN_RAISED_ASYNCSTOPITER = tsLiteral("async generator raised StopAsyncIteration"); public static final TruffleString MAXSIZE_SHOULD_BE_INTEGER_OR_NONE = tsLiteral("maxsize should be integer or None"); public static final TruffleString THE_FIRST_ARGUMENT_MUST_BE_CALLABLE = tsLiteral("the first argument must be callable"); From 5ee2973fc8ef18b79f30af6921e9bcbdac273258 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 10 Sep 2026 13:07:41 +0200 Subject: [PATCH 005/129] Keep native method descriptors unbound (cherry picked from commit bfa12ea86190cb5d5d45190fd944a1d051098d53) --- .../com.oracle.graal.python.cext/src/object.c | 8 ++ .../src/tests/cpyext/test_object.py | 82 +++++++++++++++++++ .../cext/PythonCextObjectBuiltins.java | 29 +++++++ 3 files changed, 119 insertions(+) diff --git a/graalpython/com.oracle.graal.python.cext/src/object.c b/graalpython/com.oracle.graal.python.cext/src/object.c index 4f6d29b17d..2a67cf1cf6 100644 --- a/graalpython/com.oracle.graal.python.cext/src/object.c +++ b/graalpython/com.oracle.graal.python.cext/src/object.c @@ -1645,6 +1645,14 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) } } + /* GraalPy change: Native extension types inherit GraalPy's managed + object.__getattribute__ slot rather than PyObject_GenericGetAttr. + Do the LOAD_METHOD-style lookup on the managed side so that method + descriptors stay unbound. */ + if (tp->tp_getattro == PyBaseObject_Type.tp_getattro && PyUnicode_CheckExact(name)) { + return GraalPyPrivate_Object_GetMethod(obj, name, method); + } + if (tp->tp_getattro != PyObject_GenericGetAttr || !PyUnicode_CheckExact(name)) { *method = PyObject_GetAttr(obj, name); return 0; diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py index 8f05308339..c7743751de 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py @@ -92,6 +92,88 @@ def __getattribute__(self, key): class TestObject(unittest.TestCase): + def test_get_method_keeps_method_descriptors_unbound(self): + module = compile_module_from_string( + """ + #include + + PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *, PyObject *, PyObject **); + + static PyObject* get_method(PyObject* self, PyObject* args) { + PyObject* obj; + PyObject* name; + if (!PyArg_ParseTuple(args, "OO:get_method", &obj, &name)) { + return NULL; + } + PyObject* method = NULL; + int is_method = _PyObject_GetMethod(obj, name, &method); + if (method == NULL) { + return NULL; + } + PyObject* result = PyTuple_New(2); + if (result == NULL) { + Py_DECREF(method); + return NULL; + } + PyTuple_SET_ITEM(result, 0, PyBool_FromLong(is_method)); + PyTuple_SET_ITEM(result, 1, method); + return result; + } + + static PyMethodDef methods[] = { + {"get_method", get_method, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} + }; + + static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, "test_get_method", NULL, -1, methods + }; + + PyMODINIT_FUNC PyInit_test_get_method(void) { + return PyModule_Create(&module); + } + """, + "test_get_method", + ) + + class C: + def method(self): + return self + + obj = C() + is_method, method = module.get_method(obj, "method") + assert is_method is True + assert method(obj) is obj + + Native = CPyExtType( + "GetMethodNative", + """ + static PyObject* get_self(PyObject* self, PyObject* unused) { + return Py_NewRef(self); + } + """, + tp_methods='{"get_self", (PyCFunction)get_self, METH_NOARGS, ""}', + ) + native_obj = Native() + is_method, method = module.get_method(native_obj, "get_self") + assert is_method is True + assert method(native_obj) is native_obj + + obj.method = lambda: "instance attribute" + is_method, method = module.get_method(obj, "method") + assert is_method is False + assert method() == "instance attribute" + + class WithGetAttribute: + def __getattribute__(self, name): + if name == "method": + return lambda: "custom getattribute" + return object.__getattribute__(self, name) + + is_method, method = module.get_method(WithGetAttribute(), "method") + assert is_method is False + assert method() == "custom getattribute" + def test_iter_dict_before_getattr_property(self): module = compile_module_from_string( """ diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 398655635e..16e4264da2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -50,6 +50,7 @@ import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Pointer; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObject; +import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectAsTruffleString; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectConstPtr; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectPtr; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectRawPointer; @@ -119,6 +120,7 @@ import com.oracle.graal.python.lib.PyObjectGetAttr; import com.oracle.graal.python.lib.PyObjectGetAttrO; import com.oracle.graal.python.lib.PyObjectGetIter; +import com.oracle.graal.python.lib.PyObjectGetMethod; import com.oracle.graal.python.lib.PyObjectHashNode; import com.oracle.graal.python.lib.PyObjectIsInstanceNode; import com.oracle.graal.python.lib.PyObjectIsSubclassNode; @@ -136,6 +138,7 @@ import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; import com.oracle.graal.python.nodes.builtins.TupleNodes.GetTupleStorage; +import com.oracle.graal.python.nodes.call.BoundDescriptor; import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode; import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode; @@ -487,6 +490,32 @@ static int getOptionalAttr(Object obj, Object attr, long resultPointer, } } + @CApiBuiltin(ret = Int, args = {PyObject, PyObjectAsTruffleString, PyObjectPtr}, call = Ignored) + abstract static class GraalPyPrivate_Object_GetMethod extends CApiTernaryBuiltinNode { + @Specialization + static int getMethod(Object receiver, TruffleString name, long resultPointer, + @Bind Node inliningTarget, + @Bind PythonContext context, + @Cached PyObjectGetMethod getMethodNode, + @Cached EnsurePythonObjectNode ensureNode, + @Cached PythonToNativeInternalNode toNativeNode, + @Cached InlinedConditionProfile isBoundProfile) { + long resultPointerValue = NULLPTR; + try { + Object result = getMethodNode.execute(null, inliningTarget, receiver, name); + boolean isBound = isBoundProfile.profile(inliningTarget, result instanceof BoundDescriptor); + if (isBound) { + result = ((BoundDescriptor) result).descriptor; + } + resultPointerValue = toNativeNode.executeNewRef(inliningTarget, + ensureNode.execute(context, result, false)); + return isBound ? 0 : 1; + } finally { + writePtr(resultPointer, resultPointerValue); + } + } + } + @CApiBuiltin(ret = Int, args = {PyObject, ConstCharPtr, PyObjectPtr}, call = Ignored) abstract static class GraalPyPrivate_Object_GetOptionalAttrString extends CApiTernaryBuiltinNode { @Specialization From 0e49dc8f2c713ceed490c72ce5962b0215c8fd2b Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 10 Sep 2026 16:07:48 +0200 Subject: [PATCH 006/129] Enable Cython fast calling conventions (cherry picked from commit 7436733b09bb3b5bcf319513683eb7dde1fb15df) --- .../lib-graalpython/patches/cython-3.2.4.patch | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/graalpython/lib-graalpython/patches/cython-3.2.4.patch b/graalpython/lib-graalpython/patches/cython-3.2.4.patch index 2fa5ffd2a9..1307d88a10 100644 --- a/graalpython/lib-graalpython/patches/cython-3.2.4.patch +++ b/graalpython/lib-graalpython/patches/cython-3.2.4.patch @@ -256,6 +256,24 @@ index 8131c86..aa67eda 100644 #endif ((__pyx_CyFunctionObject *) func)->flags, ((__pyx_CyFunctionObject *) func)->func_qualname, +diff --git a/Cython/Utility/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c +index ddaffbd..c8e7962 100644 +--- a/Cython/Utility/ModuleSetupCode.c ++++ b/Cython/Utility/ModuleSetupCode.c +@@ -96,9 +96,11 @@ + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL +- #define CYTHON_METH_FASTCALL 0 ++ #define CYTHON_METH_FASTCALL 1 + #undef CYTHON_FAST_PYCALL +- #define CYTHON_FAST_PYCALL 0 ++ #define CYTHON_FAST_PYCALL 1 ++ #undef CYTHON_FAST_PYCCALL ++ #define CYTHON_FAST_PYCCALL 1 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif diff --git a/Cython/Utility/Optimize.c b/Cython/Utility/Optimize.c index b731f74..300758b 100644 --- a/Cython/Utility/Optimize.c From 654fdd4e06fdd310f46bb6704ae21b068dcc7d64 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 10 Sep 2026 16:08:04 +0200 Subject: [PATCH 007/129] Use vectorcall for native tp_call slots (cherry picked from commit 92ce61b2a58f51ef74ab428d0053612508f3a20c) --- .../src/tests/cpyext/test_tp_slots.py | 51 +++++++ .../cext/capi/ExternalFunctionNodes.java | 1 + .../cext/capi/ExternalFunctionSignature.java | 4 +- .../objects/type/slots/TpSlotVarargs.java | 144 +++++++++++++++++- 4 files changed, 191 insertions(+), 9 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py index 2b6132af44..da45148006 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py @@ -1670,6 +1670,57 @@ def __call__(self, *args, **kwargs): assert obj.__call__({'b': 2}, a=1) == {'a': 1, 'b': 2} +def test_native_vectorcall(): + NativeVectorcall = CPyExtType( + name='NativeVectorcall', + cmembers='vectorcallfunc vectorcall;', + code=r''' + static PyObject* native_vectorcall(PyObject* self, PyObject* const* args, size_t nargsf, PyObject* kwnames) { + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + Py_ssize_t nkwargs = kwnames ? PyTuple_GET_SIZE(kwnames) : 0; + PyObject* positional = PyTuple_New(nargs); + PyObject* keywords = PyDict_New(); + if (!positional || !keywords) { + Py_XDECREF(positional); + Py_XDECREF(keywords); + return NULL; + } + for (Py_ssize_t i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + PyTuple_SET_ITEM(positional, i, args[i]); + } + for (Py_ssize_t i = 0; i < nkwargs; i++) { + if (PyDict_SetItem(keywords, PyTuple_GET_ITEM(kwnames, i), args[nargs + i]) < 0) { + Py_DECREF(positional); + Py_DECREF(keywords); + return NULL; + } + } + return Py_BuildValue("NN", positional, keywords); + } + + static PyObject* native_tp_call(PyObject* self, PyObject* args, PyObject* kwargs) { + return PyUnicode_FromString("tp_call"); + } + + static PyObject* native_vectorcall_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) { + NativeVectorcallObject* self = (NativeVectorcallObject*)type->tp_alloc(type, 0); + if (self) { + self->vectorcall = native_vectorcall; + } + return (PyObject*)self; + } + ''', + tp_flags='Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL', + tp_vectorcall_offset='offsetof(NativeVectorcallObject, vectorcall)', + tp_call='native_tp_call', + tp_new='native_vectorcall_new', + ) + + callable_obj = NativeVectorcall() + assert callable_obj(1, 2, keyword=3) == ((1, 2), {'keyword': 3}) + + def test_richcmp(): MyNativeIntSubType = CPyExtType("MyNativeIntSubTypeForRichCmpTest", ready_code = "MyNativeIntSubTypeForRichCmpTestType.tp_new = PyLong_Type.tp_new;", diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 4d05162c15..f3f18b0b54 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -2374,6 +2374,7 @@ static long doGeneric(PythonContext context, Object[] args, * instances. */ @GenerateInline(false) + @GenerateUncached public abstract static class CreateNativeKwNamesTupleNode extends Node { public abstract long execute(PythonContext context, Object[] args); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java index 53d9624e82..25fa86bf80 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java @@ -254,7 +254,9 @@ public enum ExternalFunctionSignature implements NativeCExtSymbol { // TODO(fa): should be an implicit signature GCCOLLECT(false, Py_ssize_t, Int), - GETDICTPTRFUN(true, Pointer, PyObject); + GETDICTPTRFUN(true, Pointer, PyObject), + // typedef PyObject *(*vectorcallfunc)(PyObject *, PyObject *const *, size_t, PyObject *); + VECTORCALL(false, PyObjectReturn, PyObject, Pointer, Py_ssize_t, PyObject); public final ArgDescriptor returnValue; public final ArgDescriptor[] arguments; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java index 5fdd80f32a..5b307050fc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java @@ -41,11 +41,16 @@ package com.oracle.graal.python.builtins.objects.type.slots; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; +import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyObject__ob_type; +import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_flags; +import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_vectorcall_offset; +import static com.oracle.graal.python.builtins.objects.type.TypeFlags.HAVE_VECTORCALL; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___CALL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INIT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEW__; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; +import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import java.lang.ref.Reference; @@ -55,9 +60,11 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionInvoker; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.CreateNativeArgsTupleNode; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.CreateNativeKwNamesTupleNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.EagerTupleState; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PyObjectCheckFunctionResultNode; @@ -66,6 +73,8 @@ import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonInternalNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeInternalNode; import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.TransformExceptionFromNativeNode; +import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess; +import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction; import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; @@ -99,13 +108,17 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode; import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; +import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.GetThreadStateNode; import com.oracle.graal.python.runtime.PythonContext.PythonThreadState; +import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.RootCallTarget; @@ -124,7 +137,9 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; public final class TpSlotVarargs { @@ -314,16 +329,109 @@ static Object callPython(VirtualFrame frame, Node inliningTarget, TpSlotPythonSi } } - private static final CApiTiming C_API_TIMING = CApiTiming.create(true, ""); + private static final CApiTiming C_API_TIMING_TP_CALL = CApiTiming.create(true, "tp_call"); + private static final CApiTiming C_API_TIMING_TP_INIT = CApiTiming.create(true, "tp_init"); + private static final CApiTiming C_API_TIMING_TP_NEW = CApiTiming.create(true, "tp_new"); + private static final CApiTiming C_API_TIMING_VECTORCALL = CApiTiming.create(true, "vectorcall"); + + @GenerateInline(false) + @GenerateUncached + abstract static class CallNativeVectorcallNode extends Node { + + abstract Object execute(VirtualFrame frame, Object callable, long vectorcallPointer, Object[] args, PKeyword[] keywords); + + @Specialization + static Object callNative(VirtualFrame frame, Object callable, long vectorcallPointer, Object[] args, PKeyword[] keywords, + @Bind Node inliningTarget, + @Bind PythonContext context, + @Cached GetThreadStateNode getThreadStateNode, + @Cached EnsurePythonObjectNode ensurePythonObjectNode, + @Cached PythonToNativeInternalNode toNativeNode, + @Cached CreateNativeKwNamesTupleNode createNativeKwNamesTupleNode, + @Cached ReleaseNativeArgsTupleNode releaseNativeKwNamesTupleNode, + @Cached NativeToPythonInternalNode toPythonNode, + @Cached PyObjectCheckFunctionResultNode checkResultNode, + @Cached("createFor($node)") BoundaryCallData boundaryCallData) { + PythonThreadState threadState = getThreadStateNode.execute(inliningTarget, context); + Object promotedCallable = ensurePythonObjectNode.execute(context, callable, false); + Object[] fastcallArgs = new Object[args.length + keywords.length]; + for (int i = 0; i < args.length; i++) { + fastcallArgs[i] = ensurePythonObjectNode.execute(context, args[i], false); + } + LoopNode.reportLoopCount(inliningTarget, args.length); + + long nativeArgs = NULLPTR; + Object[] keywordNames = null; + long keywordNamesPtr = NULLPTR; + try { + if (keywords.length > 0) { + keywordNames = new Object[keywords.length]; + for (int i = 0; i < keywords.length; i++) { + keywordNames[i] = keywords[i].getName(); + fastcallArgs[args.length + i] = ensurePythonObjectNode.execute(context, keywords[i].getValue(), false); + } + LoopNode.reportLoopCount(inliningTarget, keywordNames.length); + keywordNamesPtr = createNativeKwNamesTupleNode.execute(context, keywordNames); + } + nativeArgs = createNativeArguments(fastcallArgs, toNativeNode, inliningTarget); + + long nativeResult = invokeVectorcall(frame, vectorcallPointer, context, boundaryCallData, threadState, + toNativeNode.execute(inliningTarget, promotedCallable), nativeArgs, args.length, keywordNamesPtr); + return checkResultNode.execute(threadState, T___CALL__, toPythonNode.executeTransferAndRelease(inliningTarget, nativeResult)); + } finally { + if (nativeArgs != NULLPTR) { + NativeMemory.free(nativeArgs); + } + if (keywordNames != null) { + releaseNativeKwNamesTupleNode.execute(keywordNamesPtr, keywordNames); + } + Reference.reachabilityFence(promotedCallable); + Reference.reachabilityFence(fastcallArgs); + Reference.reachabilityFence(keywordNames); + } + } + + private static long createNativeArguments(Object[] args, PythonToNativeInternalNode toNativeNode, Node inliningTarget) { + if (args.length == 0) { + return NULLPTR; + } + long pointer = NativeMemory.mallocPtrArray(args.length); + for (int i = 0; i < args.length; i++) { + assert EnsurePythonObjectNode.doesNotNeedPromotion(args[i]); + NativeMemory.writePtrArrayElement(pointer, i, toNativeNode.execute(inliningTarget, args[i])); + } + LoopNode.reportLoopCount(inliningTarget, args.length); + return pointer; + } + + private static long invokeVectorcall(VirtualFrame frame, long vectorcallPointer, PythonContext context, BoundaryCallData boundaryCallData, PythonThreadState threadState, + long callable, long args, long nargs, long keywordNames) { + Object state = BoundaryCallContext.enter(frame, threadState, boundaryCallData); + CApiTiming.enter(); + try { + return ExternalFunctionInvoker.invokeVECTORCALL(vectorcallPointer, callable, args, nargs, keywordNames); + } catch (Throwable exception) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + GilNode.uncachedAcquire(); + throw CompilerDirectives.shouldNotReachHere(exception); + } finally { + CApiTiming.exit(C_API_TIMING_VECTORCALL); + if (frame != null && threadState.getCaughtException() != null) { + PArguments.setException(frame, threadState.getCaughtException()); + } + BoundaryCallContext.exit(frame, threadState, state); + } + } + } @GenerateInline(false) @GenerateUncached abstract static class CallNativeTernaryfuncNode extends Node { - abstract Object execute(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name); + abstract Object execute(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name, CApiTiming timing); @Specialization - static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name, + static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name, CApiTiming timing, @Bind Node inliningTarget, @Bind PythonContext context, @Cached GetThreadStateNode getThreadStateNode, @@ -351,7 +459,7 @@ static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object kwargsDict = keywords.length > 0 ? PFactory.createDict(language, keywords) : NO_VALUE; assert EnsurePythonObjectNode.doesNotNeedPromotion(kwargsDict); try { - long nativeResult = ExternalFunctionInvoker.invokeTERNARYFUNC(frame, C_API_TIMING, context.ensureNativeContext(), boundaryCallData, state, slot.callable, + long nativeResult = ExternalFunctionInvoker.invokeTERNARYFUNC(frame, timing, context.ensureNativeContext(), boundaryCallData, state, slot.callable, toNativeNode.execute(inliningTarget, promotedSelf), argsTuplePtr, toNativeNode.execute(inliningTarget, kwargsDict)); @@ -419,7 +527,7 @@ static Object callNative(VirtualFrame frame, Node inliningTarget, TpSlotCExtNati Object kwargsDict = keywords.length > 0 ? PFactory.createDict(language, keywords) : NO_VALUE; assert EnsurePythonObjectNode.doesNotNeedPromotion(kwargsDict); try { - int nativeResult = ExternalFunctionInvoker.invokeINITPROC(frame, C_API_TIMING, context.ensureNativeContext(), boundaryCallData, state, slot.callable, + int nativeResult = ExternalFunctionInvoker.invokeINITPROC(frame, C_API_TIMING_TP_INIT, context.ensureNativeContext(), boundaryCallData, state, slot.callable, toNativeNode.execute(inliningTarget, promotedSelf), argsTuplePtr, toNativeNode.execute(inliningTarget, kwargsDict)); @@ -512,7 +620,7 @@ static boolean hasDefaultMetatype(Node inliningTarget, Object self, GetClassNode static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, @Cached CallNativeTernaryfuncNode callNode) { // 'tp_new' slot's C type is actually 'newfunc' but that is compatible to 'ternaryfunc'. - return callNode.execute(frame, slot, self, args, keywords, T___NEW__); + return callNode.execute(frame, slot, self, args, keywords, T___NEW__, C_API_TIMING_TP_NEW); } } @@ -535,9 +643,29 @@ static Object callPython(VirtualFrame frame, Node inliningTarget, TpSlotPythonSi @Specialization @InliningCutoff - static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, + static Object callNative(VirtualFrame frame, Node inliningTarget, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, + @Cached InlinedConditionProfile vectorcallProfile, + @Cached CallNativeVectorcallNode callVectorcallNode, @Cached CallNativeTernaryfuncNode callNode) { - return callNode.execute(frame, slot, self, args, keywords, T___CALL__); + if (self instanceof PythonNativeObject nativeObject) { + long vectorcallPointer = getVectorcallPointer(nativeObject); + if (vectorcallProfile.profile(inliningTarget, vectorcallPointer != NULLPTR)) { + return callVectorcallNode.execute(frame, self, vectorcallPointer, args, keywords); + } + } + return callNode.execute(frame, slot, self, args, keywords, T___CALL__, C_API_TIMING_TP_CALL); + } + + /** Reads the vectorcall pointer without resolving any native object or its type. */ + private static long getVectorcallPointer(PythonNativeObject callable) { + long callablePtr = callable.getPtr(); + long obType = CStructAccess.readPtrField(callablePtr, PyObject__ob_type); + if ((CStructAccess.readLongField(obType, PyTypeObject__tp_flags) & HAVE_VECTORCALL) == 0) { + return NULLPTR; + } + long vectorcallOffset = CStructAccess.readLongField(obType, PyTypeObject__tp_vectorcall_offset); + assert vectorcallOffset > 0; + return NativeMemory.readPtr(callablePtr + vectorcallOffset); } } From a350288a2293ad7998f6104db3087143629464b7 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 10 Sep 2026 17:34:55 +0200 Subject: [PATCH 008/129] Optimize vectorcall method dispatch (cherry picked from commit e36ab501032c9e88e664b038de3944fc0fc6e41f) --- .../com.oracle.graal.python.cext/src/call.c | 13 ++++ .../src/tests/cpyext/test_functions.py | 42 +++++++++++++ .../cext/PythonCextObjectBuiltins.java | 60 +++++++++++++++++++ 3 files changed, 115 insertions(+) diff --git a/graalpython/com.oracle.graal.python.cext/src/call.c b/graalpython/com.oracle.graal.python.cext/src/call.c index 954f70eed0..a1bf261e69 100644 --- a/graalpython/com.oracle.graal.python.cext/src/call.c +++ b/graalpython/com.oracle.graal.python.cext/src/call.c @@ -929,6 +929,19 @@ PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, assert(args != NULL); assert(PyVectorcall_NARGS(nargsf) >= 1); + /* GraalPy change: Perform the method lookup and call in a single upcall if the receiver is + managed, or if a native extension type inherited GraalPy's managed object.__getattribute__ + slot. In the latter case, _PyObject_GetMethod would upcall for the lookup anyway, only to + return to native and potentially upcall again to invoke the resulting managed method. + Receivers with a genuinely native attribute lookup continue through CPython's native fast + path below. */ + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (points_to_py_handle_space(args[0]) || + (Py_TYPE(args[0])->tp_getattro == PyBaseObject_Type.tp_getattro && PyUnicode_CheckExact(name))) { + return GraalPyPrivate_Object_VectorcallMethod(name, args[0], args + 1, + nargs - 1, kwnames); + } + PyThreadState *tstate = _PyThreadState_GET(); PyObject *callable = NULL; /* Use args[0] as "self" argument */ diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py index eedd1c10cd..ae4d463fde 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py @@ -147,6 +147,14 @@ class TypeWithAttrInDict: NativeTypeWithAttr.attr = "str" +class VectorcallMethodReceiver: + def combine(self, positional, *, keyword="default"): + return type(self).__name__, positional, keyword + + +NativeTypeWithAttr.combine = VectorcallMethodReceiver.combine + + class DelAttrObject: def __init__(self): self.a = 1 @@ -401,6 +409,40 @@ def __hash__(self): argspec="Oss", callfunction="PyObject_CallMethod" ) + test_PyObject_VectorcallMethod = CPyExtFunction( + lambda args: getattr(args[0], args[1])( + args[2], **({} if args[3] is None else {"keyword": args[3]})), + lambda: ( + (VectorcallMethodReceiver(), "combine", "managed-positional", "managed-keyword"), + (VectorcallMethodReceiver(), "combine", "managed-positional", None), + (NativeTypeWithAttr(), "combine", "native-positional", "native-keyword"), + (NativeTypeWithAttr(), "combine", "native-positional", None), + ), + code=''' + static PyObject* wrap_PyObject_VectorcallMethod(PyObject* receiver, PyObject* name, + PyObject* positional, PyObject* keyword_value) { + PyObject* args[3] = {receiver, positional, keyword_value}; + PyObject* keyword_names = NULL; + if (keyword_value != Py_None) { + PyObject* keyword_name = PyUnicode_FromString("keyword"); + if (keyword_name == NULL) { + return NULL; + } + keyword_names = PyTuple_Pack(1, keyword_name); + Py_DECREF(keyword_name); + if (keyword_names == NULL) { + return NULL; + } + } + PyObject* result = PyObject_VectorcallMethod(name, args, 2, keyword_names); + Py_XDECREF(keyword_names); + return result; + } + ''', + arguments=["PyObject* receiver", "PyObject* name", "PyObject* positional", "PyObject* keyword_value"], + argspec="OOOO", + callfunction="wrap_PyObject_VectorcallMethod", + ) test_PyObject_Type = CPyExtFunction( type, lambda: ( diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 16e4264da2..237146b025 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -72,6 +72,7 @@ import java.io.PrintWriter; import java.lang.ref.Reference; +import java.util.logging.Level; import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; @@ -89,6 +90,7 @@ import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; import com.oracle.graal.python.builtins.objects.bytes.PBytes; +import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions; @@ -157,8 +159,10 @@ import com.oracle.graal.python.runtime.sequence.storage.EmptySequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; +import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; @@ -290,6 +294,51 @@ static Object doMethod(Object receiver, Object methodName, long argsArray, long } } + @CApiBuiltin(ret = PyObjectTransfer, args = {PyObjectAsTruffleString, PyObject, PyObjectConstPtr, Py_ssize_t, PyObject}, call = Ignored) + abstract static class GraalPyPrivate_Object_VectorcallMethod extends CApi5BuiltinNode { + + @Specialization + static Object doMethod(TruffleString methodName, Object receiver, long argsArray, long nargs, Object keywordNames, + @Bind Node inliningTarget, + @Cached CStructAccess.ReadObjectNode readNode, + @Cached CStructAccess.ReadObjectNode readKwNode, + @Cached GetTupleStorage getTupleStorage, + @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode, + @Cached CastToTruffleStringNode castToTruffleStringNode, + @Cached PyObjectGetMethod getMethodNode, + @Cached InlinedConditionProfile isBoundProfile, + @Cached CallNode callNode) { + try { + Object[] args = readNode.readPyObjectArray(argsArray, (int) nargs); + PKeyword[] keywords; + if (keywordNames instanceof PNone) { + keywords = PKeyword.EMPTY_KEYWORDS; + } else { + SequenceStorage storage = getTupleStorage.execute(inliningTarget, keywordNames); + int kwcount = storage.length(); + Object[] kwValues = readKwNode.readPyObjectArray(argsArray, kwcount, (int) nargs); + keywords = new PKeyword[kwcount]; + for (int i = 0; i < kwcount; i++) { + TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); + keywords[i] = new PKeyword(name, kwValues[i]); + } + } + + Object callable = getMethodNode.execute(null, inliningTarget, receiver, methodName); + if (isBoundProfile.profile(inliningTarget, callable instanceof BoundDescriptor)) { + return callNode.execute(null, ((BoundDescriptor) callable).descriptor, args, keywords); + } + Object[] unboundArgs = new Object[args.length + 1]; + unboundArgs[0] = receiver; + PythonUtils.arraycopy(args, 0, unboundArgs, 1, args.length); + return callNode.execute(null, callable, unboundArgs, keywords); + } catch (CannotCastException e) { + // PyVectorcall_NARGS cannot exceed Py_ssize_t, and GraalPy arrays are int-sized. + throw CompilerDirectives.shouldNotReachHere(e); + } + } + } + @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, ConstCharPtrAsTruffleString, PyObject, Int}, call = Ignored) abstract static class GraalPyPrivate_Object_CallMethod1 extends CApiQuaternaryBuiltinNode { @Specialization @@ -312,6 +361,8 @@ static Object doGeneric(Object receiver, TruffleString methodName, Object argsOb @CApiBuiltin(ret = PyObjectTransfer, args = {PyThreadState, PyObject, PyObjectConstPtr, Py_ssize_t, PyObject}, call = Direct) abstract static class _PyObject_MakeTpCall extends CApi5BuiltinNode { + private static final TruffleLogger LOGGER = CApiContext.getLogger(_PyObject_MakeTpCall.class); + @Specialization static Object doGeneric(@SuppressWarnings("unused") long threadState, Object callable, long argsArray, long nargs, Object kwargs, @Cached CStructAccess.ReadObjectNode readNode, @@ -324,6 +375,9 @@ static Object doGeneric(@SuppressWarnings("unused") long threadState, Object cal @Cached PyTupleCheckNode tupleCheckNode, @Cached CastToTruffleStringNode castToTruffleStringNode) { try { + if (LOGGER.isLoggable(Level.FINE)) { + logCallableType(callable); + } Object[] args = readNode.readPyObjectArray(argsArray, (int) nargs); PKeyword[] keywords; @@ -352,6 +406,12 @@ static Object doGeneric(@SuppressWarnings("unused") long threadState, Object cal throw CompilerDirectives.shouldNotReachHere(e); } } + + @TruffleBoundary + private static void logCallableType(Object callable) { + Object type = GetClassNode.executeUncached(callable); + LOGGER.fine(TypeNodes.GetNameNode.executeUncached(type).toJavaStringUncached()); + } } @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct) From 6cf7dfb444579a9b1c373d5de91b3a47551b746a Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 16 Sep 2026 16:40:17 +0200 Subject: [PATCH 009/129] Handle native method descriptors in vectorcall dispatch (cherry picked from commit c9d96fef07a581ecc0b7e6c36b7682865a13fbfd) --- .../src/tests/cpyext/test_object.py | 49 +++++++++++- .../cext/PythonCextObjectBuiltins.java | 77 ++++++++++++------- .../graal/python/lib/PyObjectGetMethod.java | 20 ++++- 3 files changed, 117 insertions(+), 29 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py index c7743751de..43240045a9 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py @@ -99,6 +99,30 @@ def test_get_method_keeps_method_descriptors_unbound(self): PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *, PyObject *, PyObject **); + static PyObject* native_descriptor_call(PyObject* self, PyObject* args, PyObject* kwargs) { + if (PyTuple_GET_SIZE(args) != 1 || (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0)) { + PyErr_SetString(PyExc_TypeError, "expected exactly one positional argument"); + return NULL; + } + return Py_NewRef(PyTuple_GET_ITEM(args, 0)); + } + + static PyObject* native_descriptor_get(PyObject* self, PyObject* obj, PyObject* type) { + if (obj == NULL || obj == Py_None) { + return Py_NewRef(self); + } + return PyMethod_New(self, obj); + } + + static PyTypeObject NativeMethodDescriptor_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "test_get_method.NativeMethodDescriptor", + .tp_basicsize = sizeof(PyObject), + .tp_call = native_descriptor_call, + .tp_descr_get = native_descriptor_get, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_METHOD_DESCRIPTOR, + }; + static PyObject* get_method(PyObject* self, PyObject* args) { PyObject* obj; PyObject* name; @@ -130,7 +154,20 @@ def test_get_method_keeps_method_descriptors_unbound(self): }; PyMODINIT_FUNC PyInit_test_get_method(void) { - return PyModule_Create(&module); + if (PyType_Ready(&NativeMethodDescriptor_Type) < 0) { + return NULL; + } + PyObject* m = PyModule_Create(&module); + if (m == NULL) { + return NULL; + } + PyObject* descriptor = NativeMethodDescriptor_Type.tp_alloc(&NativeMethodDescriptor_Type, 0); + if (descriptor == NULL || PyModule_AddObject(m, "native_method_descriptor", descriptor) < 0) { + Py_XDECREF(descriptor); + Py_DECREF(m); + return NULL; + } + return m; } """, "test_get_method", @@ -159,6 +196,16 @@ def method(self): assert is_method is True assert method(native_obj) is native_obj + class WithNativeMethodDescriptor: + native_method_descriptor = module.native_method_descriptor + + native_descriptor_obj = WithNativeMethodDescriptor() + is_method, method = module.get_method(native_descriptor_obj, "native_method_descriptor") + assert is_method is True + assert method is module.native_method_descriptor + assert method(native_descriptor_obj) is native_descriptor_obj + assert native_descriptor_obj.native_method_descriptor() is native_descriptor_obj + obj.method = lambda: "instance attribute" is_method, method = module.get_method(obj, "method") assert is_method is False diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 237146b025..d7b6608e40 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -66,6 +66,7 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___BYTES__; import static com.oracle.graal.python.nodes.StringLiterals.T_JAVA; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; +import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.POINTER_SIZE; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.readPtrArrayElement; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.writePtr; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; @@ -165,6 +166,7 @@ import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; @@ -298,45 +300,68 @@ static Object doMethod(Object receiver, Object methodName, long argsArray, long abstract static class GraalPyPrivate_Object_VectorcallMethod extends CApi5BuiltinNode { @Specialization - static Object doMethod(TruffleString methodName, Object receiver, long argsArray, long nargs, Object keywordNames, + static Object doMethodNoKeywords(TruffleString methodName, Object receiver, long argsArray, long nargs, + @SuppressWarnings("unused") PNone keywordNames, @Bind Node inliningTarget, - @Cached CStructAccess.ReadObjectNode readNode, - @Cached CStructAccess.ReadObjectNode readKwNode, + @Exclusive @Cached CStructAccess.ReadObjectNode readNode, + @Exclusive @Cached PyObjectGetMethod getMethodNode, + @Exclusive @Cached InlinedConditionProfile isBoundProfile, + @Exclusive @Cached CallNode callNode) { + Object callable = getMethodNode.execute(null, inliningTarget, receiver, methodName); + boolean isBound = isBoundProfile.profile(inliningTarget, callable instanceof BoundDescriptor); + Object[] args = readArguments(readNode, argsArray, (int) nargs, receiver, isBound); + if (isBound) { + callable = ((BoundDescriptor) callable).descriptor; + } + return callNode.execute(null, callable, args, PKeyword.EMPTY_KEYWORDS); + } + + @Specialization + static Object doMethodWithKeywords(TruffleString methodName, Object receiver, long argsArray, long nargs, Object keywordNames, + @Bind Node inliningTarget, + @Exclusive @Cached CStructAccess.ReadObjectNode readNode, + @Exclusive @Cached CStructAccess.ReadObjectNode readKwNode, @Cached GetTupleStorage getTupleStorage, @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode, @Cached CastToTruffleStringNode castToTruffleStringNode, - @Cached PyObjectGetMethod getMethodNode, - @Cached InlinedConditionProfile isBoundProfile, - @Cached CallNode callNode) { + @Exclusive @Cached PyObjectGetMethod getMethodNode, + @Exclusive @Cached InlinedConditionProfile isBoundProfile, + @Exclusive @Cached CallNode callNode) { try { - Object[] args = readNode.readPyObjectArray(argsArray, (int) nargs); - PKeyword[] keywords; - if (keywordNames instanceof PNone) { - keywords = PKeyword.EMPTY_KEYWORDS; - } else { - SequenceStorage storage = getTupleStorage.execute(inliningTarget, keywordNames); - int kwcount = storage.length(); - Object[] kwValues = readKwNode.readPyObjectArray(argsArray, kwcount, (int) nargs); - keywords = new PKeyword[kwcount]; - for (int i = 0; i < kwcount; i++) { - TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); - keywords[i] = new PKeyword(name, kwValues[i]); - } + Object callable = getMethodNode.execute(null, inliningTarget, receiver, methodName); + boolean isBound = isBoundProfile.profile(inliningTarget, callable instanceof BoundDescriptor); + Object[] args = readArguments(readNode, argsArray, (int) nargs, receiver, isBound); + if (isBound) { + callable = ((BoundDescriptor) callable).descriptor; } - Object callable = getMethodNode.execute(null, inliningTarget, receiver, methodName); - if (isBoundProfile.profile(inliningTarget, callable instanceof BoundDescriptor)) { - return callNode.execute(null, ((BoundDescriptor) callable).descriptor, args, keywords); + SequenceStorage storage = getTupleStorage.execute(inliningTarget, keywordNames); + int kwcount = storage.length(); + Object[] kwValues = readKwNode.readPyObjectArray(argsArray, kwcount, (int) nargs); + PKeyword[] keywords = new PKeyword[kwcount]; + for (int i = 0; i < kwcount; i++) { + TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); + keywords[i] = new PKeyword(name, kwValues[i]); } - Object[] unboundArgs = new Object[args.length + 1]; - unboundArgs[0] = receiver; - PythonUtils.arraycopy(args, 0, unboundArgs, 1, args.length); - return callNode.execute(null, callable, unboundArgs, keywords); + return callNode.execute(null, callable, args, keywords); } catch (CannotCastException e) { // PyVectorcall_NARGS cannot exceed Py_ssize_t, and GraalPy arrays are int-sized. throw CompilerDirectives.shouldNotReachHere(e); } } + + private static Object[] readArguments(CStructAccess.ReadObjectNode readNode, long argsArray, int nargs, + Object receiver, boolean isBound) { + if (isBound) { + return readNode.readPyObjectArray(argsArray, nargs); + } + Object[] args = new Object[nargs + 1]; + args[0] = receiver; + for (int i = 0; i < nargs; i++) { + args[i + 1] = readNode.read(argsArray, i * POINTER_SIZE); + } + return args; + } } @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, ConstCharPtrAsTruffleString, PyObject, Int}, call = Ignored) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.java index 3c38a181ec..0735ebd7fa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.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,10 +43,13 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PythonAbstractObject; +import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TpSlots.GetCachedTpSlotsNode; import com.oracle.graal.python.builtins.objects.type.TpSlots.GetObjectSlotsNode; +import com.oracle.graal.python.builtins.objects.type.TypeFlags; +import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetTypeFlagsNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrGet.CallSlotDescrGet; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrSet; @@ -110,6 +113,7 @@ static Object getAttr(VirtualFrame frame, Node inliningTarget, Object receiver, @Cached GetCachedTpSlotsNode getTypeSlotsNode, @Bind("getClass.execute(inliningTarget, receiver)") Object lazyClass, @Cached LookupAttributeInMRONode.Dynamic lookupNode, + @Cached(inline = false) GetTypeFlagsNode getTypeFlagsNode, @Cached GetObjectSlotsNode getSlotsNode, @Cached CallSlotDescrGet callGetNode, @Cached ReadAttributeFromObjectNode readAttr, @@ -124,7 +128,7 @@ static Object getAttr(VirtualFrame frame, Node inliningTarget, Object receiver, TpSlot getMethod = null; if (descr != PNone.NO_VALUE) { hasDescr.enter(inliningTarget); - if (MaybeBindDescriptorNode.isMethodDescriptor(descr)) { + if (isMethodDescriptor(inliningTarget, descr, getClass, getTypeFlagsNode)) { methodFound = true; } else { // lookupGet acts as branch profile for this branch @@ -159,6 +163,18 @@ static Object getAttr(VirtualFrame frame, Node inliningTarget, Object receiver, throw raiseNode.raiseAttributeError(inliningTarget, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, receiver, name); } + private static boolean isMethodDescriptor(Node inliningTarget, Object descriptor, GetClassNode getClassNode, + GetTypeFlagsNode getTypeFlagsNode) { + if (MaybeBindDescriptorNode.isMethodDescriptor(descriptor)) { + return true; + } + if (descriptor instanceof PythonAbstractNativeObject) { + Object descriptorType = getClassNode.execute(inliningTarget, descriptor); + return (getTypeFlagsNode.execute(descriptorType) & TypeFlags.METHOD_DESCRIPTOR) != 0; + } + return false; + } + @Specialization(guards = "isForeignObject(inliningTarget, isForeignObjectNode, receiver)", limit = "1") @InliningCutoff static Object getForeignMethod(VirtualFrame frame, Node inliningTarget, Object receiver, TruffleString name, From e04e981dc0122ded992f3c49a221d996d9ae0202 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 17 Sep 2026 10:41:11 +0200 Subject: [PATCH 010/129] Optimize vectorcall transitions (cherry picked from commit b529092951c158477b3c27ff68248ae970d2ed8f) --- .../com.oracle.graal.python.cext/src/call.c | 24 +++++-- .../src/tests/cpyext/test_functions.py | 54 ++++++++++++++ .../cext/PythonCextObjectBuiltins.java | 70 +++++++++---------- 3 files changed, 107 insertions(+), 41 deletions(-) diff --git a/graalpython/com.oracle.graal.python.cext/src/call.c b/graalpython/com.oracle.graal.python.cext/src/call.c index a1bf261e69..b6693f5af5 100644 --- a/graalpython/com.oracle.graal.python.cext/src/call.c +++ b/graalpython/com.oracle.graal.python.cext/src/call.c @@ -931,15 +931,27 @@ PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, /* GraalPy change: Perform the method lookup and call in a single upcall if the receiver is managed, or if a native extension type inherited GraalPy's managed object.__getattribute__ - slot. In the latter case, _PyObject_GetMethod would upcall for the lookup anyway, only to - return to native and potentially upcall again to invoke the resulting managed method. - Receivers with a genuinely native attribute lookup continue through CPython's native fast - path below. */ + slot. If the lookup finds an unbound native method descriptor, the upcall returns the + descriptor instead of invoking it. This keeps native extension method calls in native code + without duplicating managed MRO and instance-dict lookup semantics here. */ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (points_to_py_handle_space(args[0]) || (Py_TYPE(args[0])->tp_getattro == PyBaseObject_Type.tp_getattro && PyUnicode_CheckExact(name))) { - return GraalPyPrivate_Object_VectorcallMethod(name, args[0], args + 1, - nargs - 1, kwnames); + PyObject *result = NULL; + int native_method = GraalPyPrivate_Object_VectorcallMethod(name, args[0], args + 1, + nargs - 1, kwnames, &result); + if (native_method <= 0) { + return result; + } + + /* The receiver is still args[0], so the descriptor can use the original argument array. + Do not expose PY_VECTORCALL_ARGUMENTS_OFFSET: the native callee must not modify the + slot immediately preceding args. */ + nargsf &= ~PY_VECTORCALL_ARGUMENTS_OFFSET; + PyObject *call_result = _PyObject_VectorcallTstate(_PyThreadState_GET(), result, + args, nargsf, kwnames); + Py_DECREF(result); + return call_result; } PyThreadState *tstate = _PyThreadState_GET(); diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py index ae4d463fde..26829283a7 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py @@ -155,6 +155,57 @@ def combine(self, positional, *, keyword="default"): NativeTypeWithAttr.combine = VectorcallMethodReceiver.combine +NativeVectorcallMethodReceiver = CPyExtHeapType( + "NativeVectorcallMethodReceiver", + code=''' + static PyObject* native_combine(PyObject* self, PyObject* const* args, + Py_ssize_t nargs, PyObject* kwnames) { + PyObject* positional = PyTuple_New(nargs); + if (positional == NULL) { + return NULL; + } + for (Py_ssize_t i = 0; i < nargs; i++) { + PyTuple_SET_ITEM(positional, i, Py_NewRef(args[i])); + } + PyObject* keywords = PyDict_New(); + if (keywords == NULL) { + Py_DECREF(positional); + return NULL; + } + if (kwnames != NULL) { + Py_ssize_t nkw = PyTuple_GET_SIZE(kwnames); + for (Py_ssize_t i = 0; i < nkw; i++) { + if (PyDict_SetItem(keywords, PyTuple_GET_ITEM(kwnames, i), args[nargs + i]) < 0) { + Py_DECREF(positional); + Py_DECREF(keywords); + return NULL; + } + } + } + PyObject* result = PyTuple_Pack(2, positional, keywords); + Py_DECREF(positional); + Py_DECREF(keywords); + return result; + } + + static PyMethodDef native_methods[] = { + {"combine", (PyCFunction)(void(*)(void))native_combine, METH_FASTCALL | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} + }; + ''', + slots=['{Py_tp_methods, native_methods}'], +) + + +class NativeVectorcallMethodSubclass(NativeVectorcallMethodReceiver): + pass + + +native_vectorcall_method_shadowed = NativeVectorcallMethodSubclass() +native_vectorcall_method_shadowed.combine = lambda positional, *, keyword="default": ( + "shadowed", positional, keyword) + + class DelAttrObject: def __init__(self): self.a = 1 @@ -417,6 +468,9 @@ def __hash__(self): (VectorcallMethodReceiver(), "combine", "managed-positional", None), (NativeTypeWithAttr(), "combine", "native-positional", "native-keyword"), (NativeTypeWithAttr(), "combine", "native-positional", None), + (NativeVectorcallMethodReceiver(), "combine", "native-method-positional", "native-method-keyword"), + (NativeVectorcallMethodReceiver(), "combine", "native-method-positional", None), + (native_vectorcall_method_shadowed, "combine", "shadowed-positional", "shadowed-keyword"), ), code=''' static PyObject* wrap_PyObject_VectorcallMethod(PyObject* receiver, PyObject* name, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index d7b6608e40..97420f5566 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -78,6 +78,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi5BuiltinNode; +import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi6BuiltinNode; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBinaryBuiltinNode; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiNullaryBuiltinNode; @@ -91,6 +92,7 @@ import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; import com.oracle.graal.python.builtins.objects.bytes.PBytes; +import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming; @@ -160,13 +162,11 @@ import com.oracle.graal.python.runtime.sequence.storage.EmptySequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; -import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; @@ -296,57 +296,57 @@ static Object doMethod(Object receiver, Object methodName, long argsArray, long } } - @CApiBuiltin(ret = PyObjectTransfer, args = {PyObjectAsTruffleString, PyObject, PyObjectConstPtr, Py_ssize_t, PyObject}, call = Ignored) - abstract static class GraalPyPrivate_Object_VectorcallMethod extends CApi5BuiltinNode { + @CApiBuiltin(ret = Int, args = {PyObjectAsTruffleString, PyObject, PyObjectConstPtr, Py_ssize_t, PyObject, PyObjectPtr}, call = Ignored) + abstract static class GraalPyPrivate_Object_VectorcallMethod extends CApi6BuiltinNode { @Specialization - static Object doMethodNoKeywords(TruffleString methodName, Object receiver, long argsArray, long nargs, - @SuppressWarnings("unused") PNone keywordNames, + static int doMethod(TruffleString methodName, Object receiver, long argsArray, long nargs, Object keywordNames, long resultPointer, @Bind Node inliningTarget, - @Exclusive @Cached CStructAccess.ReadObjectNode readNode, - @Exclusive @Cached PyObjectGetMethod getMethodNode, - @Exclusive @Cached InlinedConditionProfile isBoundProfile, - @Exclusive @Cached CallNode callNode) { - Object callable = getMethodNode.execute(null, inliningTarget, receiver, methodName); - boolean isBound = isBoundProfile.profile(inliningTarget, callable instanceof BoundDescriptor); - Object[] args = readArguments(readNode, argsArray, (int) nargs, receiver, isBound); - if (isBound) { - callable = ((BoundDescriptor) callable).descriptor; - } - return callNode.execute(null, callable, args, PKeyword.EMPTY_KEYWORDS); - } - - @Specialization - static Object doMethodWithKeywords(TruffleString methodName, Object receiver, long argsArray, long nargs, Object keywordNames, - @Bind Node inliningTarget, - @Exclusive @Cached CStructAccess.ReadObjectNode readNode, - @Exclusive @Cached CStructAccess.ReadObjectNode readKwNode, + @Bind PythonContext context, + @Cached CStructAccess.ReadObjectNode readNode, + @Cached CStructAccess.ReadObjectNode readKwNode, @Cached GetTupleStorage getTupleStorage, @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode, @Cached CastToTruffleStringNode castToTruffleStringNode, - @Exclusive @Cached PyObjectGetMethod getMethodNode, - @Exclusive @Cached InlinedConditionProfile isBoundProfile, - @Exclusive @Cached CallNode callNode) { + @Cached PyObjectGetMethod getMethodNode, + @Cached InlinedConditionProfile isBoundProfile, + @Cached CallNode callNode, + @Cached EnsurePythonObjectNode ensureNode, + @Cached PythonToNativeInternalNode toNativeNode) { + long resultPointerValue = NULLPTR; try { Object callable = getMethodNode.execute(null, inliningTarget, receiver, methodName); boolean isBound = isBoundProfile.profile(inliningTarget, callable instanceof BoundDescriptor); + if (!isBound && callable instanceof PythonAbstractNativeObject) { + resultPointerValue = toNativeNode.executeNewRef(inliningTarget, callable); + return 1; + } Object[] args = readArguments(readNode, argsArray, (int) nargs, receiver, isBound); if (isBound) { callable = ((BoundDescriptor) callable).descriptor; } - SequenceStorage storage = getTupleStorage.execute(inliningTarget, keywordNames); - int kwcount = storage.length(); - Object[] kwValues = readKwNode.readPyObjectArray(argsArray, kwcount, (int) nargs); - PKeyword[] keywords = new PKeyword[kwcount]; - for (int i = 0; i < kwcount; i++) { - TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); - keywords[i] = new PKeyword(name, kwValues[i]); + PKeyword[] keywords; + if (keywordNames instanceof PNone) { + keywords = PKeyword.EMPTY_KEYWORDS; + } else { + SequenceStorage storage = getTupleStorage.execute(inliningTarget, keywordNames); + int kwcount = storage.length(); + Object[] kwValues = readKwNode.readPyObjectArray(argsArray, kwcount, (int) nargs); + keywords = new PKeyword[kwcount]; + for (int i = 0; i < kwcount; i++) { + TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); + keywords[i] = new PKeyword(name, kwValues[i]); + } } - return callNode.execute(null, callable, args, keywords); + Object result = callNode.execute(null, callable, args, keywords); + resultPointerValue = toNativeNode.executeNewRef(inliningTarget, ensureNode.execute(context, result, false)); + return 0; } catch (CannotCastException e) { // PyVectorcall_NARGS cannot exceed Py_ssize_t, and GraalPy arrays are int-sized. throw CompilerDirectives.shouldNotReachHere(e); + } finally { + writePtr(resultPointer, resultPointerValue); } } From b62331ca62c549cc245872658c88ae70f059700b Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 17 Sep 2026 10:11:37 +0200 Subject: [PATCH 011/129] Convert GraalPyPrivate_Object_VectorcallMethod to static upcall (cherry picked from commit 3eed965d7d2d1526e749050e621b1636869b9e13) --- .../cext/PythonCextObjectBuiltins.java | 108 ++++++++---------- 1 file changed, 48 insertions(+), 60 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 97420f5566..a847405177 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -78,7 +78,6 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi5BuiltinNode; -import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi6BuiltinNode; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBinaryBuiltinNode; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiNullaryBuiltinNode; @@ -126,6 +125,7 @@ import com.oracle.graal.python.lib.PyObjectGetAttrO; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectGetMethod; +import com.oracle.graal.python.lib.PyObjectGetMethodNodeGen; import com.oracle.graal.python.lib.PyObjectHashNode; import com.oracle.graal.python.lib.PyObjectIsInstanceNode; import com.oracle.graal.python.lib.PyObjectIsSubclassNode; @@ -143,6 +143,7 @@ import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; import com.oracle.graal.python.nodes.builtins.TupleNodes.GetTupleStorage; +import com.oracle.graal.python.nodes.builtins.TupleNodesFactory.GetTupleStorageNodeGen; import com.oracle.graal.python.nodes.call.BoundDescriptor; import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode; @@ -297,71 +298,58 @@ static Object doMethod(Object receiver, Object methodName, long argsArray, long } @CApiBuiltin(ret = Int, args = {PyObjectAsTruffleString, PyObject, PyObjectConstPtr, Py_ssize_t, PyObject, PyObjectPtr}, call = Ignored) - abstract static class GraalPyPrivate_Object_VectorcallMethod extends CApi6BuiltinNode { - - @Specialization - static int doMethod(TruffleString methodName, Object receiver, long argsArray, long nargs, Object keywordNames, long resultPointer, - @Bind Node inliningTarget, - @Bind PythonContext context, - @Cached CStructAccess.ReadObjectNode readNode, - @Cached CStructAccess.ReadObjectNode readKwNode, - @Cached GetTupleStorage getTupleStorage, - @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode, - @Cached CastToTruffleStringNode castToTruffleStringNode, - @Cached PyObjectGetMethod getMethodNode, - @Cached InlinedConditionProfile isBoundProfile, - @Cached CallNode callNode, - @Cached EnsurePythonObjectNode ensureNode, - @Cached PythonToNativeInternalNode toNativeNode) { - long resultPointerValue = NULLPTR; - try { - Object callable = getMethodNode.execute(null, inliningTarget, receiver, methodName); - boolean isBound = isBoundProfile.profile(inliningTarget, callable instanceof BoundDescriptor); - if (!isBound && callable instanceof PythonAbstractNativeObject) { - resultPointerValue = toNativeNode.executeNewRef(inliningTarget, callable); - return 1; - } - Object[] args = readArguments(readNode, argsArray, (int) nargs, receiver, isBound); - if (isBound) { - callable = ((BoundDescriptor) callable).descriptor; - } + static int GraalPyPrivate_Object_VectorcallMethod(long methodNamePtr, long receiverPtr, long argsArray, long nargs, long kwnamesPtr, long resultPointer) { + TruffleString methodName = CastToTruffleStringNode.castKnownStringUncached(NativeToPythonInternalNode.executeUncached(methodNamePtr, false)); + Object receiver = NativeToPythonInternalNode.executeUncached(receiverPtr, false); + long resultPointerValue = NULLPTR; + try { + Object callable = PyObjectGetMethodNodeGen.getUncached().execute(null, null, receiver, methodName); + boolean isBound = callable instanceof BoundDescriptor; + if (!isBound && callable instanceof PythonAbstractNativeObject) { + resultPointerValue = PythonToNativeInternalNode.executeNewRefUncached(callable); + return 1; + } + Object[] args = readArguments(argsArray, (int) nargs, receiver, isBound); + if (isBound) { + callable = ((BoundDescriptor) callable).descriptor; + } - PKeyword[] keywords; - if (keywordNames instanceof PNone) { - keywords = PKeyword.EMPTY_KEYWORDS; - } else { - SequenceStorage storage = getTupleStorage.execute(inliningTarget, keywordNames); - int kwcount = storage.length(); - Object[] kwValues = readKwNode.readPyObjectArray(argsArray, kwcount, (int) nargs); - keywords = new PKeyword[kwcount]; - for (int i = 0; i < kwcount; i++) { - TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); - keywords[i] = new PKeyword(name, kwValues[i]); - } + PKeyword[] keywords; + if (kwnamesPtr == NULLPTR) { + keywords = PKeyword.EMPTY_KEYWORDS; + } else { + Object keywordNames = NativeToPythonInternalNode.executeUncached(kwnamesPtr, false); + SequenceStorage storage = GetTupleStorageNodeGen.getUncached().execute(null, keywordNames); + int kwcount = storage.length(); + Object[] kwValues = CStructAccess.ReadObjectNode.getUncached().readPyObjectArray(argsArray, kwcount, (int) nargs); + keywords = new PKeyword[kwcount]; + for (int i = 0; i < kwcount; i++) { + TruffleString name = CastToTruffleStringNode.executeUncached(SequenceStorageNodes.GetItemScalarNode.executeUncached(storage, i)); + keywords[i] = new PKeyword(name, kwValues[i]); } - Object result = callNode.execute(null, callable, args, keywords); - resultPointerValue = toNativeNode.executeNewRef(inliningTarget, ensureNode.execute(context, result, false)); - return 0; - } catch (CannotCastException e) { - // PyVectorcall_NARGS cannot exceed Py_ssize_t, and GraalPy arrays are int-sized. - throw CompilerDirectives.shouldNotReachHere(e); - } finally { - writePtr(resultPointer, resultPointerValue); } + Object result = CallNode.executeUncached(callable, args, keywords); + resultPointerValue = PythonToNativeInternalNode.executeNewRefUncached(result); + return 0; + } catch (CannotCastException e) { + // PyVectorcall_NARGS cannot exceed Py_ssize_t, and GraalPy arrays are int-sized. + throw CompilerDirectives.shouldNotReachHere(e); + } finally { + writePtr(resultPointer, resultPointerValue); } + } - private static Object[] readArguments(CStructAccess.ReadObjectNode readNode, long argsArray, int nargs, - Object receiver, boolean isBound) { - if (isBound) { - return readNode.readPyObjectArray(argsArray, nargs); - } - Object[] args = new Object[nargs + 1]; - args[0] = receiver; - for (int i = 0; i < nargs; i++) { - args[i + 1] = readNode.read(argsArray, i * POINTER_SIZE); - } - return args; + private static Object[] readArguments(long argsArray, int nargs, + Object receiver, boolean isBound) { + if (isBound) { + return CStructAccess.ReadObjectNode.getUncached().readPyObjectArray(argsArray, nargs); + } + Object[] args = new Object[nargs + 1]; + args[0] = receiver; + for (int i = 0; i < nargs; i++) { + args[i + 1] = CStructAccess.ReadObjectNode.getUncached().read(argsArray, i * POINTER_SIZE); } + return args; } @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, ConstCharPtrAsTruffleString, PyObject, Int}, call = Ignored) From 46aa854a052621314eb3db32814c6d1f8f8ee9f5 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 8 Oct 2026 10:50:49 +0200 Subject: [PATCH 012/129] Match CPython password lookup error handling (cherry picked from commit aa9fb342c026dd24b84a19d29fd5a579e305b247) --- .../src/tests/test_pwd.py | 180 ++++++++++++++++++ .../python/runtime/NativePosixSupport.java | 9 +- 2 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 graalpython/com.oracle.graal.python.test/src/tests/test_pwd.py diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_pwd.py b/graalpython/com.oracle.graal.python.test/src/tests/test_pwd.py new file mode 100644 index 0000000000..54cddc373e --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_pwd.py @@ -0,0 +1,180 @@ +# Copyright (c) 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 +# +# 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. + +import os +import shlex +import shutil +import subprocess +import sys +import tempfile +import textwrap +import unittest + +from tests.util import run_subprocess_with_graalpy_startup_retry + + +POSIX_BACKEND_IS_JAVA = sys.implementation.name == "graalpy" and __graalpython__.posix_module_backend() == "java" + + +@unittest.skipUnless(sys.platform == "linux", "requires Linux LD_PRELOAD") +@unittest.skipIf(POSIX_BACKEND_IS_JAVA, "requires native password database lookups") +class PwdLookupErrorTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + compiler = shlex.split(os.environ.get("CC", "cc")) + if not compiler or shutil.which(compiler[0]) is None: + raise unittest.SkipTest("requires a C compiler") + temporary_directory = tempfile.TemporaryDirectory() + cls.addClassCleanup(temporary_directory.cleanup) + source = os.path.join(temporary_directory.name, "pwd_lookup_error.c") + cls.library = os.path.join(temporary_directory.name, "pwd_lookup_error.so") + # Inject the libc error itself, so the test exercises the real pwd builtin + # and native POSIX backend without touching the host password database. + with open(source, "w") as f: + f.write(textwrap.dedent("""\ + #include + #include + #include + #include + + static int retry_count; + + int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, + size_t buffer_size, struct passwd **result) { + *result = NULL; + if (uid == 2147483646) { + if (retry_count++ == 0) { + return ERANGE; + } + const char data[] = "graalpy_test_user\\0/home/graalpy_test_user\\0/bin/sh"; + if (buffer_size < sizeof(data)) { + return ERANGE; + } + memcpy(buffer, data, sizeof(data)); + pwd->pw_name = buffer; + pwd->pw_dir = buffer + strlen(buffer) + 1; + pwd->pw_shell = pwd->pw_dir + strlen(pwd->pw_dir) + 1; + pwd->pw_uid = uid; + pwd->pw_gid = uid; + pwd->pw_passwd = "x"; + pwd->pw_gecos = ""; + *result = pwd; + return 0; + } + errno = ENOENT; + return ENOENT; + } + + int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, + size_t buffer_size, struct passwd **result) { + *result = NULL; + errno = ENOENT; + return ENOENT; + } + """)) + result = subprocess.run( + [*compiler, "-shared", "-fPIC", source, "-o", cls.library], + capture_output=True, text=True, timeout=60, + ) + if result.returncode: + raise AssertionError(f"Could not compile password lookup shim:\n{result.stdout}\n{result.stderr}") + + def run_child(self, code, *, no_site=True): + env = os.environ.copy() + env.pop("HOME", None) + env.pop("PYTHONUSERBASE", None) + env.pop("PYTHONNOUSERSITE", None) + env["LD_PRELOAD"] = self.library + (" " + env["LD_PRELOAD"] if env.get("LD_PRELOAD") else "") + args = [sys.executable] + if no_site: + args.append("-S") + args.extend(["-c", textwrap.dedent(code)]) + result = run_subprocess_with_graalpy_startup_retry(args, env=env, text=True, timeout=60) + self.assertEqual(result.returncode, 0, f"{result.stdout}\n{result.stderr}") + + def test_getpwuid_lookup_error_is_keyerror(self): + self.run_child("""\ + import os + import pwd + + try: + pwd.getpwuid(os.getuid()) + except KeyError: + pass + else: + raise AssertionError("Expected KeyError for a failed password database lookup") + """) + + def test_getpwuid_retries_erange(self): + self.run_child("""\ + import pwd + + entry = pwd.getpwuid(2147483646) + assert entry.pw_name == "graalpy_test_user", entry + assert entry.pw_dir == "/home/graalpy_test_user", entry + assert entry.pw_shell == "/bin/sh", entry + assert entry.pw_uid == 2147483646, entry + """) + + def test_getpwnam_lookup_error_is_keyerror(self): + self.run_child("""\ + import pwd + + try: + pwd.getpwnam("graalpy_test_user") + except KeyError: + pass + else: + raise AssertionError("Expected KeyError for a failed password database lookup") + """) + + def test_expanduser_with_lookup_error(self): + self.run_child("""\ + import os + + assert os.path.expanduser("~/.local") == "~/.local" + """) + + def test_site_startup_with_lookup_error(self): + # No -S: exercise automatic site initialization before the script runs. + self.run_child("""\ + import site + + assert site.getuserbase() == "~/.local", site.getuserbase() + """, no_site=False) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 8710d7c53c..ba10dce091 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -3310,11 +3310,10 @@ private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode NativeMemory.readLongArrayElements(nativeOutput, 0, output, 0, output.length); return createPwdResult(data, output, fromByteArrayNode, switchEncodingFromUtf8Node); } - if (result != OSErrorEnum.ERANGE.getNumber() || sysConfMax != -1) { - // no point in trying larger buffer if we got different error or the OS already - // told - // us that sysConfMax should be enough... - throw newPosixException(result); + if (result != OSErrorEnum.ERANGE.getNumber()) { + // CPython treats failed lookups as missing entries, except for ERANGE, + // which requires retrying with a larger buffer even if sysconf gave a size. + return null; } } finally { NativeMemory.free(nativeOutput); From 662de3ddd6f0305bf80010f36cd26eea1af84e47 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 8 Oct 2026 11:36:27 +0200 Subject: [PATCH 013/129] Add patches for Cython up to 3.3.0 (cherry picked from commit f2e2546a77e8e042c2d2786a4f744bd6d0e87c35) --- .../patches/cython-3.2.5.patch | 315 ++++++++++++++++++ .../patches/cython-3.3.0.patch | 290 ++++++++++++++++ .../lib-graalpython/patches/metadata.toml | 12 + 3 files changed, 617 insertions(+) create mode 100644 graalpython/lib-graalpython/patches/cython-3.2.5.patch create mode 100644 graalpython/lib-graalpython/patches/cython-3.3.0.patch diff --git a/graalpython/lib-graalpython/patches/cython-3.2.5.patch b/graalpython/lib-graalpython/patches/cython-3.2.5.patch new file mode 100644 index 0000000000..068ea43c42 --- /dev/null +++ b/graalpython/lib-graalpython/patches/cython-3.2.5.patch @@ -0,0 +1,315 @@ +diff --git a/Cython/Build/Dependencies.py b/Cython/Build/Dependencies.py +index 3726a72..ed46b9b 100644 +--- a/Cython/Build/Dependencies.py ++++ b/Cython/Build/Dependencies.py +@@ -1077,6 +1077,11 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + else: + dep_timestamp, dep = deps.newest_dependency(source) + priority = 2 - (dep in deps.immediate_dependencies(source)) ++ # GraalPy change: force recythonize if not cythonized by our patched version ++ if os.path.exists(c_file): ++ with open(c_file, 'rb') as f: ++ if not b'graalpy' in f.read(100): ++ c_timestamp = -1 + if force or c_timestamp < dep_timestamp: + if not quiet and not force: + if source == dep: +@@ -1130,6 +1135,8 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + for i, task in enumerate(to_compile, 1) + ] + ++ nthreads = 0 # GraalVM: we don't want to spawn ++ + if N <= 1: + nthreads = 0 + try: +diff --git a/Cython/Compiler/Version.py b/Cython/Compiler/Version.py +index 5ae2a4e..951aacc 100644 +--- a/Cython/Compiler/Version.py ++++ b/Cython/Compiler/Version.py +@@ -5,4 +5,4 @@ from .. import __version__ as version + + # For 'generated by' header line in C files. + +-watermark = str(version) ++watermark = f'{version}-graalpy' +diff --git a/Cython/Includes/cpython/array.pxd b/Cython/Includes/cpython/array.pxd +index 2221ade..f46d197 100644 +--- a/Cython/Includes/cpython/array.pxd ++++ b/Cython/Includes/cpython/array.pxd +@@ -100,15 +100,18 @@ cdef extern from *: # Hard-coded utility code hack. + + cdef: + Py_ssize_t ob_size +- arraydescr* ob_descr # struct arraydescr *ob_descr; ++ ++ @property ++ cdef inline arraydescr* ob_descr(self) noexcept nogil: ++ return __Pyx_PyArray_Descr(self) + + @property + cdef inline __data_union data(self) noexcept nogil: + return __Pyx_PyArray_Data(self) + + array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr) +- + __data_union __Pyx_PyArray_Data(array self) noexcept nogil ++ arraydescr* __Pyx_PyArray_Descr(array self) noexcept nogil + # fast resize/realloc + # not suitable for small increments; reallocation 'to the point' + int resize(array self, Py_ssize_t n) except -1 +@@ -120,15 +123,18 @@ cdef inline array clone(array template, Py_ssize_t length, bint zero): + """ fast creation of a new array, given a template array. + type will be same as template. + if zero is true, new array will be initialized with zeroes.""" +- cdef array op = newarrayobject(Py_TYPE(template), length, template.ob_descr) ++ cdef arraydescr* descr = template.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(template), length, descr) + if zero and op is not None: +- memset(op.data.as_chars, 0, length * op.ob_descr.itemsize) ++ memset(op.data.as_chars, 0, length * descr.itemsize) + return op + + cdef inline array copy(array self): + """ make a copy of an array. """ +- cdef array op = newarrayobject(Py_TYPE(self), Py_SIZE(self), self.ob_descr) +- memcpy(op.data.as_chars, self.data.as_chars, Py_SIZE(op) * op.ob_descr.itemsize) ++ cdef Py_ssize_t length = Py_SIZE(self) ++ cdef arraydescr* descr = self.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(self), length, descr) ++ memcpy(op.data.as_chars, self.data.as_chars, length * descr.itemsize) + return op + + cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n) except -1: +@@ -149,4 +155,4 @@ cdef inline int extend(array self, array other) except -1: + + cdef inline void zero(array self) noexcept: + """ set all elements of array to zero. """ +- memset(self.data.as_chars, 0, Py_SIZE(self) * self.ob_descr.itemsize) ++ memset(self.data.as_chars, 0, Py_SIZE(self) * self.ob_descr.itemsize) +diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c +index 38e2f1c..7a4e223 100644 +--- a/Cython/Utility/CythonFunction.c ++++ b/Cython/Utility/CythonFunction.c +@@ -87,6 +87,22 @@ typedef struct { + PyObject *func_is_coroutine; + } __pyx_CyFunctionObject; + ++#if !CYTHON_COMPILING_IN_LIMITED_API ++#if CYTHON_COMPILING_IN_GRAAL ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) GraalPyCFunction_GetMethodDef((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) GraalPyCFunction_SetMethodDef((PyObject*)(cyfunc), ml) ++#define __Pyx_CyFunction_GetModule(cyfunc) GraalPyCFunction_GetModule((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) GraalPyCFunction_SetModule((PyObject*)(cyfunc), module) ++#define __Pyx_CyFunction_GetDoc(cyfunc) GraalPyCFunction_GetDoc((PyObject*)(cyfunc)) ++#else ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_ml) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) (((PyCFunctionObject*)(cyfunc))->m_ml = (ml)) ++#define __Pyx_CyFunction_GetModule(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_module) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) (((PyCFunctionObject*)(cyfunc))->m_module = (module)) ++#define __Pyx_CyFunction_GetDoc(cyfunc) (__Pyx_CyFunction_GetMethodDef(cyfunc)->ml_doc) ++#endif ++#endif ++ + #undef __Pyx_CyOrPyCFunction_Check + #define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, CGLOBAL(__pyx_CyFunctionType)) + #define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, CGLOBAL(__pyx_CyFunctionType), &PyCFunction_Type) +@@ -192,8 +208,8 @@ __Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; + #else +- if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +- op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); ++ if (__Pyx_CyFunction_GetDoc(op)) { ++ op->func_doc = PyUnicode_FromString(__Pyx_CyFunction_GetDoc(op)); + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { +@@ -238,7 +254,7 @@ __Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); + #else +- op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); ++ op->func_name = PyUnicode_InternFromString(__Pyx_CyFunction_GetMethodDef(op)->ml_name); + #endif /* CYTHON_COMPILING_IN_LIMITED_API */ + if (unlikely(op->func_name == NULL)) + return NULL; +@@ -588,7 +604,7 @@ static void __Pyx_CyFunction_raise_argument_count_error(__pyx_CyFunctionObject * + py_name, message, size); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", + name, message, size); +@@ -604,7 +620,7 @@ static void __Pyx_CyFunction_raise_type_error(__pyx_CyFunctionObject *func, cons + py_name, message); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s", + name, message); +@@ -719,14 +735,14 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef * + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + #if !CYTHON_COMPILING_IN_LIMITED_API +- cf->m_ml = ml; ++ __Pyx_CyFunction_SetMethodDef(cf, ml); + cf->m_self = (PyObject *) op; + #endif + Py_XINCREF(closure); + op->func_closure = closure; + #if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); +- cf->m_module = module; ++ __Pyx_CyFunction_SetModule(cf, module); + #endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + op->func_dict = NULL; +@@ -786,8 +802,10 @@ __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_CLEAR(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func_dict); + #elif PY_VERSION_HEX < 0x030d0000 +@@ -843,8 +861,10 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, + #if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_VISIT(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func_dict); + #else +@@ -898,8 +918,8 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + if (unlikely(flags < 0)) return NULL; + #else + PyCFunctionObject* f = (PyCFunctionObject*)func; +- PyCFunction meth = f->m_ml->ml_meth; +- int flags = f->m_ml->ml_flags; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(f)->ml_meth; ++ int flags = __Pyx_CyFunction_GetMethodDef(f)->ml_flags; + #endif + Py_ssize_t size; + +@@ -1062,7 +1082,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1101,7 +1121,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { +@@ -1140,7 +1160,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { +@@ -1175,7 +1195,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: +@@ -1435,14 +1455,14 @@ __pyx_FusedFunction_descr_get_locked(__pyx_FusedFunctionObject *func, PyObject * + module = __Pyx_CyFunction_get_module((__pyx_CyFunctionObject *) func, NULL); + if ((unlikely(!module))) return NULL; + #else +- module = ((PyCFunctionObject *) func)->m_module; ++ module = __Pyx_CyFunction_GetModule(func); + #endif + + meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New( + #if CYTHON_COMPILING_IN_LIMITED_API + func->ml, + #else +- ((PyCFunctionObject *) func)->m_ml, ++ __Pyx_CyFunction_GetMethodDef(func), + #endif + ((__pyx_CyFunctionObject *) func)->flags, + ((__pyx_CyFunctionObject *) func)->func_qualname, +diff --git a/Cython/Utility/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c +index ddaffbd..c8e7962 100644 +--- a/Cython/Utility/ModuleSetupCode.c ++++ b/Cython/Utility/ModuleSetupCode.c +@@ -96,9 +96,11 @@ + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL +- #define CYTHON_METH_FASTCALL 0 ++ #define CYTHON_METH_FASTCALL 1 + #undef CYTHON_FAST_PYCALL +- #define CYTHON_FAST_PYCALL 0 ++ #define CYTHON_FAST_PYCALL 1 ++ #undef CYTHON_FAST_PYCCALL ++ #define CYTHON_FAST_PYCCALL 1 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif +diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h +index bc6da7b..6bf0559 100644 +--- a/Cython/Utility/arrayarray.h ++++ b/Cython/Utility/arrayarray.h +@@ -69,10 +69,27 @@ struct arrayobject { + int ob_exports; /* Number of exported buffers */ + }; + ++#if CYTHON_COMPILING_IN_GRAAL && defined(GRAALPY_VERSION_NUM) && GRAALPY_VERSION_NUM >= 0x190304a0 ++#define __PYX_USE_GRAALPY_ARRAY_API 1 ++#else ++#define __PYX_USE_GRAALPY_ARRAY_API 0 ++#endif ++ ++static CYTHON_INLINE struct arraydescr *__Pyx_PyArray_Descr(arrayobject *self) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return (struct arraydescr *)GraalPyArray_GetDescriptor((PyObject*)self); ++#else ++ return self->ob_descr; ++#endif ++} ++ + #ifndef NO_NEWARRAY_INLINE + // fast creation of a new array + static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t size, + struct arraydescr *descr) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return GraalPyArray_New((PyObject*)type, size, (GraalPyArray_Descriptor*)descr); ++#else + arrayobject *op; + size_t nbytes; + +@@ -105,6 +122,7 @@ static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t si + } + } + return (PyObject *) op; ++#endif + } + #else + PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, diff --git a/graalpython/lib-graalpython/patches/cython-3.3.0.patch b/graalpython/lib-graalpython/patches/cython-3.3.0.patch new file mode 100644 index 0000000000..e9f7d1e465 --- /dev/null +++ b/graalpython/lib-graalpython/patches/cython-3.3.0.patch @@ -0,0 +1,290 @@ +diff --git a/Cython/Build/Dependencies.py b/Cython/Build/Dependencies.py +index a38cb31..367e0b2 100644 +--- a/Cython/Build/Dependencies.py ++++ b/Cython/Build/Dependencies.py +@@ -1077,6 +1077,11 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + else: + dep_timestamp, dep = deps.newest_dependency(source) + priority = 2 - (dep in deps.immediate_dependencies(source)) ++ # GraalPy change: force recythonize if not cythonized by our patched version ++ if os.path.exists(c_file): ++ with open(c_file, 'rb') as f: ++ if not b'graalpy' in f.read(100): ++ c_timestamp = -1 + if force or c_timestamp < dep_timestamp: + if not quiet and not force: + if source == dep: +@@ -1130,6 +1135,8 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + for i, task in enumerate(to_compile, 1) + ] + ++ nthreads = 0 # GraalVM: we don't want to spawn ++ + if N <= 1: + nthreads = 0 + try: +diff --git a/Cython/Compiler/Version.py b/Cython/Compiler/Version.py +index 5ae2a4e..951aacc 100644 +--- a/Cython/Compiler/Version.py ++++ b/Cython/Compiler/Version.py +@@ -5,4 +5,4 @@ from .. import __version__ as version + + # For 'generated by' header line in C files. + +-watermark = str(version) ++watermark = f'{version}-graalpy' +diff --git a/Cython/Includes/cpython/array.pxd b/Cython/Includes/cpython/array.pxd +index d5352a0..9640254 100644 +--- a/Cython/Includes/cpython/array.pxd ++++ b/Cython/Includes/cpython/array.pxd +@@ -100,15 +100,18 @@ cdef extern from *: # Hard-coded utility code hack. + + cdef: + Py_ssize_t ob_size +- arraydescr* ob_descr # struct arraydescr *ob_descr; ++ ++ @property ++ cdef inline arraydescr* ob_descr(self) noexcept nogil: ++ return __Pyx_PyArray_Descr(self) + + @property + cdef inline __data_union data(self) noexcept nogil: + return __Pyx_PyArray_Data(self) + + array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr) +- + __data_union __Pyx_PyArray_Data(array self) noexcept nogil ++ arraydescr* __Pyx_PyArray_Descr(array self) noexcept nogil + # fast resize/realloc + # not suitable for small increments; reallocation 'to the point' + int resize(array self, Py_ssize_t n) except -1 +@@ -120,15 +123,18 @@ cdef inline array clone(array template, Py_ssize_t length, bint zero): + """ fast creation of a new array, given a template array. + type will be same as template. + if zero is true, new array will be initialized with zeroes.""" +- cdef array op = newarrayobject(Py_TYPE(template), length, template.ob_descr) ++ cdef arraydescr* descr = template.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(template), length, descr) + if zero and op is not None: +- memset(op.data.as_chars, 0, length * op.ob_descr.itemsize) ++ memset(op.data.as_chars, 0, length * descr.itemsize) + return op + + cdef inline array copy(array self): + """ make a copy of an array. """ +- cdef array op = newarrayobject(Py_TYPE(self), Py_SIZE(self), self.ob_descr) +- memcpy(op.data.as_chars, self.data.as_chars, Py_SIZE(op) * op.ob_descr.itemsize) ++ cdef Py_ssize_t length = Py_SIZE(self) ++ cdef arraydescr* descr = self.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(self), length, descr) ++ memcpy(op.data.as_chars, self.data.as_chars, length * descr.itemsize) + return op + + cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n) except -1: +diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c +index d4c5107..2b3c7b8 100644 +--- a/Cython/Utility/CythonFunction.c ++++ b/Cython/Utility/CythonFunction.c +@@ -100,6 +100,22 @@ typedef struct { + #endif + } __pyx_CyFunctionObject; + ++#if !CYTHON_COMPILING_IN_LIMITED_API ++#if CYTHON_COMPILING_IN_GRAAL ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) GraalPyCFunction_GetMethodDef((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) GraalPyCFunction_SetMethodDef((PyObject*)(cyfunc), ml) ++#define __Pyx_CyFunction_GetModule(cyfunc) GraalPyCFunction_GetModule((PyObject*)(cyfunc)) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) GraalPyCFunction_SetModule((PyObject*)(cyfunc), module) ++#define __Pyx_CyFunction_GetDoc(cyfunc) GraalPyCFunction_GetDoc((PyObject*)(cyfunc)) ++#else ++#define __Pyx_CyFunction_GetMethodDef(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_ml) ++#define __Pyx_CyFunction_SetMethodDef(cyfunc, ml) (((PyCFunctionObject*)(cyfunc))->m_ml = (ml)) ++#define __Pyx_CyFunction_GetModule(cyfunc) (((PyCFunctionObject*)(cyfunc))->m_module) ++#define __Pyx_CyFunction_SetModule(cyfunc, module) (((PyCFunctionObject*)(cyfunc))->m_module = (module)) ++#define __Pyx_CyFunction_GetDoc(cyfunc) (__Pyx_CyFunction_GetMethodDef(cyfunc)->ml_doc) ++#endif ++#endif ++ + #undef __Pyx_CyOrPyCFunction_Check + #define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, CGLOBAL(__pyx_CyFunctionType)) + #define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, CGLOBAL(__pyx_CyFunctionType), &PyCFunction_Type) +@@ -268,7 +284,7 @@ __Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + const char *doc = op->func_methoddef->ml_doc; + #else +- const char *doc = ((PyCFunctionObject*)op)->m_ml->ml_doc; ++ const char *doc = __Pyx_CyFunction_GetDoc(op); + #endif + if (doc) { + op->func_doc = PyUnicode_FromString(doc); +@@ -317,7 +333,7 @@ __Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + const char *name = op->func_methoddef->ml_name; + #else +- const char *name = ((PyCFunctionObject*)op)->m_ml->ml_name; ++ const char *name = __Pyx_CyFunction_GetMethodDef(op)->ml_name; + #endif + op->func_name = PyUnicode_InternFromString(name); + if (unlikely(op->func_name == NULL)) +@@ -840,7 +856,7 @@ static void __Pyx_CyFunction_raise_argument_count_error(PyObject *func, const ch + py_name, message, size); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", + name, message, size); +@@ -856,7 +872,7 @@ static void __Pyx_CyFunction_raise_type_error(PyObject *func, const char* messag + py_name, message); + Py_DECREF(py_name); + #else +- const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; ++ const char* name = __Pyx_CyFunction_GetMethodDef(func)->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s", + name, message); +@@ -1013,7 +1029,7 @@ static PyObject *__Pyx_CyFunction_Init(PyObject *op_in, + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + #if !CYTHON_COMPILING_IN_LIMITED_API +- cf->m_ml = ml; ++ __Pyx_CyFunction_SetMethodDef(cf, ml); + // This is set for the benefit of __Pyx_CyOrPyCFunction_GET_SELF. It is never reassigned, so + // when we know an object is a CyFunction we don't even need to look it up.__Pyx_CyFunction_set_module + cf->m_self = (PyObject *) op; +@@ -1022,7 +1038,7 @@ static PyObject *__Pyx_CyFunction_Init(PyObject *op_in, + op->func_closure = closure; + #if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); +- cf->m_module = module; ++ __Pyx_CyFunction_SetModule(cf, module); + #endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + op->func_dict = NULL; +@@ -1083,8 +1099,10 @@ static int __Pyx__CyFunction_clear(__pyx_CyFunctionObject *m) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func_module); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_CLEAR(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func_dict); + #elif PY_VERSION_HEX < 0x030d0000 +@@ -1150,8 +1168,10 @@ static int __Pyx_CyFunction_traverse(PyObject *m_in, visitproc visit, void *arg) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func_module); + #else ++#if !CYTHON_COMPILING_IN_GRAAL + Py_VISIT(((PyCFunctionObject*)m)->m_module); + #endif ++#endif + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func_dict); + #else +@@ -1204,8 +1224,8 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + int flags = cyfunc->func_methoddef->ml_flags; + #else + PyCFunctionObject* f = (PyCFunctionObject*)func; +- PyCFunction meth = f->m_ml->ml_meth; +- int flags = f->m_ml->ml_flags; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(f)->ml_meth; ++ int flags = __Pyx_CyFunction_GetMethodDef(f)->ml_flags; + #endif + Py_ssize_t size; + +@@ -1361,7 +1381,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(func, cyfunc, nargs, kwnames)) { +@@ -1394,7 +1414,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(func, cyfunc, nargs, kwnames)) { +@@ -1427,7 +1447,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(func, cyfunc, nargs, NULL)) { +@@ -1456,7 +1476,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + if (unlikely(!meth)) return NULL; + #else +- PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; ++ PyCFunction meth = __Pyx_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(func, cyfunc, nargs, NULL)) { + case 1: +@@ -1752,14 +1772,14 @@ __pyx_FusedFunction_descr_get_locked(PyObject *self, PyObject *obj) + module = __Pyx_CyFunction_get_module(self, NULL); + if ((unlikely(!module))) return NULL; + #else +- module = ((PyCFunctionObject *) func)->m_module; ++ module = __Pyx_CyFunction_GetModule(func); + #endif + + meth = __pyx_FusedFunction_New( + #if CYTHON_COMPILING_IN_LIMITED_API + func->ml, + #else +- ((PyCFunctionObject *) func)->m_ml, ++ __Pyx_CyFunction_GetMethodDef(func), + #endif + cyfunc->flags, + cyfunc->func_qualname, +diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h +index 629b28f..ff2618c 100644 +--- a/Cython/Utility/arrayarray.h ++++ b/Cython/Utility/arrayarray.h +@@ -69,10 +69,27 @@ struct arrayobject { + int ob_exports; /* Number of exported buffers */ + }; + ++#if CYTHON_COMPILING_IN_GRAAL && defined(GRAALPY_VERSION_NUM) && GRAALPY_VERSION_NUM >= 0x190304a0 ++#define __PYX_USE_GRAALPY_ARRAY_API 1 ++#else ++#define __PYX_USE_GRAALPY_ARRAY_API 0 ++#endif ++ ++static CYTHON_INLINE struct arraydescr *__Pyx_PyArray_Descr(arrayobject *self) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return (struct arraydescr *)GraalPyArray_GetDescriptor((PyObject*)self); ++#else ++ return self->ob_descr; ++#endif ++} ++ + #ifndef NO_NEWARRAY_INLINE + // fast creation of a new array + static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t size, + struct arraydescr *descr) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return GraalPyArray_New((PyObject*)type, size, (GraalPyArray_Descriptor*)descr); ++#else + arrayobject *op; + size_t nbytes; + +@@ -105,6 +122,7 @@ static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t si + } + } + return (PyObject *) op; ++#endif + } + #else + PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, diff --git a/graalpython/lib-graalpython/patches/metadata.toml b/graalpython/lib-graalpython/patches/metadata.toml index 033fb7ce4f..8e1d29cfcb 100644 --- a/graalpython/lib-graalpython/patches/metadata.toml +++ b/graalpython/lib-graalpython/patches/metadata.toml @@ -93,6 +93,18 @@ license = 'Apache-2.0 OR BSD-3-Clause' version = '>= 43.0.0' note = "Versions newer than 43 do not need a patch." +[[cython.rules]] +version = '== 3.3.0' +autopatch = false +patch = 'cython-3.3.0.patch' +license = 'Apache-2.0' + +[[cython.rules]] +version = '>= 3.2.5, <= 3.2.9' +autopatch = false +patch = 'cython-3.2.5.patch' +license = 'Apache-2.0' + [[cython.rules]] version = '>= 3.2.0, < 3.2.4' autopatch = false From b634e6d5d611b8c19c9041fabe16f91b9e378642 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Tue, 29 Sep 2026 16:17:40 +0200 Subject: [PATCH 014/129] Remove useless TruffleNode.EqualNode param from OSErrorEnum.fromMessage and callers (cherry picked from commit b04f5a9ce6d1960b4b6964fd4ded88e26431d873) --- .../modules/GraalPythonModuleBuiltins.java | 8 +- .../builtins/modules/ImpModuleBuiltins.java | 2 +- .../builtins/modules/SSLModuleBuiltins.java | 7 +- .../objects/exception/OSErrorEnum.java | 17 +- .../objects/ssl/SSLContextBuiltins.java | 18 +- .../python/nodes/PConstructAndRaiseNode.java | 8 +- .../python/runtime/EmulatedPosixSupport.java | 227 ++++++++---------- 7 files changed, 128 insertions(+), 159 deletions(-) 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 9c163df123..94c1c4d94e 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 @@ -407,7 +407,7 @@ private void runFile(PythonContext context, TruffleString inputFilePath) { source = builder.build(); // TODO we should handle non-IO errors better } catch (IOException e) { - ErrorAndMessagePair error = OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached()); + ErrorAndMessagePair error = OSErrorEnum.fromException(e); String msg = String.format("%s: can't open file '%s': [Errno %d] %s\n", context.getOption(PythonOptions.Executable), inputFilePath, error.oserror.getNumber(), error.message); // CPython uses fprintf(stderr, ...) try { @@ -634,7 +634,6 @@ PBytes doString(VirtualFrame frame, Object filenameObj, @Bind Node inliningTarget, @Bind PythonContext context, @Cached CastToTruffleStringNode castToTruffleStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { TruffleString filename = castToTruffleStringNode.execute(inliningTarget, filenameObj); @@ -642,7 +641,7 @@ PBytes doString(VirtualFrame frame, Object filenameObj, byte[] bytes = file.readAllBytes(); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); } catch (Exception ex) { - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(ex, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(ex); throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, errAndMsg.oserror.getNumber(), errAndMsg.message); } } @@ -1251,7 +1250,6 @@ abstract static class DumpHeapNode extends PythonBuiltinNode { TruffleString doit(VirtualFrame frame, @Bind Node inliningTarget, @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { TruffleFile tempFile; try { @@ -1259,7 +1257,7 @@ TruffleString doit(VirtualFrame frame, tempFile = context.getEnv().createTempFile(context.getEnv().getCurrentWorkingDirectory(), J_GRAALPYTHON_ID, ".hprof"); tempFile.delete(); } catch (IOException e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } PythonUtils.dumpHeap(tempFile.getPath()); return fromJavaStringNode.execute(tempFile.getPath(), TS_ENCODING); 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 25c615978c..d691dc79f4 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 @@ -888,7 +888,7 @@ private static Object doCreate(PythonObject moduleSpec, Node inliningTarget, Pyt } catch (ImportException ie) { throw ie.reraise(); } catch (IOException e) { - throw PConstructAndRaiseNode.getUncached().raiseOSError(null, e, TruffleString.EqualNode.getUncached()); + throw PConstructAndRaiseNode.getUncached().raiseOSError(null, e); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java index 96b5e9ea1a..183fc6640a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java @@ -433,9 +433,8 @@ Object decode(VirtualFrame frame, Object path, @Bind Node inliningTarget, @Cached PyUnicodeFSDecoderNode asPath, @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return decode(inliningTarget, constructAndRaiseNode, toTruffleFile(frame, inliningTarget, asPath, path, toJavaStringNode, eqNode, constructAndRaiseNode)); + return decode(inliningTarget, constructAndRaiseNode, toTruffleFile(frame, inliningTarget, asPath, path, toJavaStringNode, constructAndRaiseNode)); } // No BoundaryCallContext: constructs and raises only builtin errors @@ -459,7 +458,7 @@ private Object decode(Node inliningTarget, PConstructAndRaiseNode.Lazy construct } private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, PyUnicodeFSDecoderNode asPath, Object fileObject, TruffleString.ToJavaStringNode toJavaStringNode, - TruffleString.EqualNode eqNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { + PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { TruffleFile file; try { file = getContext().getEnv().getPublicTruffleFile(toJavaStringNode.execute(asPath.execute(frame, fileObject))); @@ -468,7 +467,7 @@ private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, PyUni } return file; } catch (Exception e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java index a401c07a98..24d9b48165 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java @@ -247,7 +247,7 @@ public int getNumber() { } @TruffleBoundary - private static OSErrorEnum fromMessage(TruffleString message, TruffleString.EqualNode eqNode) { + private static OSErrorEnum fromMessage(TruffleString message) { if (message == null) { return null; } @@ -255,14 +255,15 @@ private static OSErrorEnum fromMessage(TruffleString message, TruffleString.Equa if (oserror.getMessage() == null) { continue; } - if (eqNode.execute(message, oserror.getMessage(), TS_ENCODING)) { + + if (message.equalsUncached(oserror.getMessage(), TS_ENCODING)) { return oserror; } for (TruffleString altMessage : oserror.alternativeMessages) { if (altMessage == null) { continue; } - if (eqNode.execute(message, altMessage, TS_ENCODING)) { + if (message.equalsUncached(altMessage, TS_ENCODING)) { return oserror; } } @@ -281,7 +282,7 @@ public static OSErrorEnum fromNumber(int number) { return null; } - public static ErrorAndMessagePair fromException(Exception e, TruffleString.EqualNode eqNode) { + public static ErrorAndMessagePair fromException(Exception e) { if (e instanceof IOException) { if (e instanceof NoSuchFileException || e instanceof FileNotFoundException) { return new ErrorAndMessagePair(OSErrorEnum.ENOENT, OSErrorEnum.ENOENT.getMessage()); @@ -305,14 +306,14 @@ public static ErrorAndMessagePair fromException(Exception e, TruffleString.Equal // specific error numbers like in the glob module: failing to match the correct // error number of 40 (link loop) breaks that module's code TruffleString reason = getReason((FileSystemException) e); - OSErrorEnum oserror = OSErrorEnum.fromMessage(reason, eqNode); + OSErrorEnum oserror = OSErrorEnum.fromMessage(reason); if (oserror == null) { return new ErrorAndMessagePair(OSErrorEnum.EIO, reason); } else { return new ErrorAndMessagePair(oserror, oserror.getMessage()); } } else { // Generic IOException - OSErrorEnum oserror = tryFindErrnoFromMessage(e, eqNode); + OSErrorEnum oserror = tryFindErrnoFromMessage(e); if (oserror == null) { return new ErrorAndMessagePair(OSErrorEnum.EIO, getMessage(e)); } else { @@ -360,13 +361,13 @@ private static TruffleString getReason(FileSystemException e) { } @TruffleBoundary - private static OSErrorEnum tryFindErrnoFromMessage(Exception e, TruffleString.EqualNode eqNode) { + private static OSErrorEnum tryFindErrnoFromMessage(Exception e) { String message = e.getMessage(); Matcher m = ERRNO_PATTERN.matcher(message); if (m.find()) { return fromNumber(Integer.parseInt(m.group(1))); } - return OSErrorEnum.fromMessage(toTruffleStringUncached(message), eqNode); + return OSErrorEnum.fromMessage(toTruffleStringUncached(message)); } @ValueType diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java index aae749a196..a865e532db 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java @@ -741,7 +741,6 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, @Cached ToByteArrayNode toBytes, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PRaiseNode raiseNode) { if (cafile instanceof PNone && capath instanceof PNone && cadata instanceof PNone) { throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.CA_FILE_PATH_DATA_CANNOT_BE_ALL_OMMITED); @@ -754,7 +753,7 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, } final TruffleFile file; if (!(cafile instanceof PNone)) { - file = toTruffleFile(frame, inliningTarget, asPath, cafile, toJavaStringNode, eqNode, constructAndRaiseNode); + file = toTruffleFile(frame, inliningTarget, asPath, cafile, toJavaStringNode, constructAndRaiseNode); if (!file.exists()) { throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, OSErrorEnum.ENOENT); } @@ -763,7 +762,7 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, } final TruffleFile path; if (!(capath instanceof PNone)) { - path = toTruffleFile(frame, inliningTarget, asPath, capath, toJavaStringNode, eqNode, constructAndRaiseNode); + path = toTruffleFile(frame, inliningTarget, asPath, capath, toJavaStringNode, constructAndRaiseNode); } else { path = null; } @@ -801,11 +800,11 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, } private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, PyUnicodeFSDecoderNode asPath, Object fileObject, TruffleString.ToJavaStringNode toJavaStringNode, - TruffleString.EqualNode eqNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { + PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { try { return getContext().getEnv().getPublicTruffleFile(toJavaStringNode.execute(asPath.execute(frame, fileObject))); } catch (Exception e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } } @@ -862,7 +861,6 @@ Object load(VirtualFrame frame, PSSLContext self, Object certfile, Object keyfil @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached GetPasswordNode getPasswordNode, @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PRaiseNode raiseNode) { if (!PGuards.isString(certfile) && !PGuards.isBytes(certfile)) { throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.S_SHOULD_BE_A_VALID_FILESYSTEMPATH, "certfile"); @@ -871,8 +869,8 @@ Object load(VirtualFrame frame, PSSLContext self, Object certfile, Object keyfil throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.S_SHOULD_BE_A_VALID_FILESYSTEMPATH, "keyfile"); } Object kf = keyfile instanceof PNone ? certfile : keyfile; - TruffleFile certTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, certfile), toJavaStringNode, eqNode, constructAndRaiseNode); - TruffleFile keyTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, kf), toJavaStringNode, eqNode, constructAndRaiseNode); + TruffleFile certTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, certfile), toJavaStringNode, constructAndRaiseNode); + TruffleFile keyTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, kf), toJavaStringNode, constructAndRaiseNode); try { try { return load(getContext(), inliningTarget, constructAndRaiseNode, certTruffleFile, keyTruffleFile, null, self); @@ -935,7 +933,7 @@ private static Object load(PythonContext context, Node inliningTarget, PConstruc } } - private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, TruffleString path, TruffleString.ToJavaStringNode toJavaStringNode, TruffleString.EqualNode eqNode, + private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, TruffleString path, TruffleString.ToJavaStringNode toJavaStringNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { try { TruffleFile file = getContext().getEnv().getPublicTruffleFile(toJavaStringNode.execute(path)); @@ -944,7 +942,7 @@ private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, Truff } return file; } catch (Exception e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java index 1eebdddb6c..1be0aad2b2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java @@ -213,8 +213,8 @@ private static Object[] createOsErrorArgs(OSErrorEnum osErrorEnum) { return new Object[]{osErrorEnum.getNumber(), osErrorEnum.getMessage()}; } - private static Object[] createOsErrorArgs(Exception exception, TruffleString.EqualNode eqNode) { - OSErrorEnum.ErrorAndMessagePair errorAndMessage = OSErrorEnum.fromException(exception, eqNode); + private static Object[] createOsErrorArgs(Exception exception) { + OSErrorEnum.ErrorAndMessagePair errorAndMessage = OSErrorEnum.fromException(exception); return new Object[]{errorAndMessage.oserror.getNumber(), errorAndMessage.message}; } @@ -230,8 +230,8 @@ public final PException raiseOSError(Frame frame, OSErrorEnum osErrorEnum, Truff return raiseOSErrorInternal(frame, createOsErrorArgs(osErrorEnum, filename)); } - public final PException raiseOSError(Frame frame, Exception exception, TruffleString.EqualNode eqNode) { - return raiseOSErrorInternal(frame, createOsErrorArgs(exception, eqNode)); + public final PException raiseOSError(Frame frame, Exception exception) { + return raiseOSErrorInternal(frame, createOsErrorArgs(exception)); } public final PException raiseOSError(Frame frame, OSErrorEnum osErrorEnum, Exception exception) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 43c6d963b6..f8adc19d73 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -217,6 +217,7 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; +import com.oracle.truffle.api.strings.TruffleString.ToJavaStringNode; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.ProcessProperties; import org.graalvm.polyglot.io.ProcessHandler.Redirect; @@ -463,14 +464,14 @@ public int openat(int dirFd, Object path, int flags, int mode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile file = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, toJavaStringNode); Set options = flagsToOptions(flags); FileAttribute> attributes = modeToAttributes(mode & ~currentUmask); try { return openTruffleFile(file, options, attributes); } catch (Exception e) { errorBranch.enter(inliningTarget); - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } @@ -499,8 +500,7 @@ private int openTruffleFile(TruffleFile truffleFile, Set opt @ExportMessage public long write(int fd, Buffer data, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { Channel channel = getFileChannel(fd); if (!(channel instanceof WritableByteChannel)) { errorBranch.enter(inliningTarget); @@ -510,7 +510,7 @@ public long write(int fd, Buffer data, return doWriteOp(data.getByteBuffer(), (WritableByteChannel) channel); } catch (Exception e) { errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -537,8 +537,7 @@ private static int doWriteOp(ByteBuffer data, WritableByteChannel channel) throw @SuppressWarnings({"unused", "static-method"}) public Buffer read(int fd, long length, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { Channel channel = getFileChannel(fd); if (!(channel instanceof ReadableByteChannel)) { errorBranch.enter(inliningTarget); @@ -548,7 +547,7 @@ public Buffer read(int fd, long length, return readBytesFromChannel((ReadableByteChannel) channel, length); } catch (Exception e) { errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -581,13 +580,12 @@ public int dup(int fd) { } @ExportMessage - public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable) throws PosixException { // TODO: will merge with super.dup2 once the super class is merged with this class try { return super.dup2(fd, fd2); } catch (IOException ex) { - throw posixException(OSErrorEnum.fromException(ex, eqNode)); + throw posixException(OSErrorEnum.fromException(ex)); } } @@ -650,12 +648,12 @@ public void msvcrtLocking(int fd, int mode, long nbytes, } @ExportMessage(name = "pipe") - public int[] pipeMessage(@Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public int[] pipeMessage() throws PosixException { // TODO: will merge with super.pipe once the super class is merged with this class try { return super.pipe(); } catch (IOException ex) { - throw posixException(OSErrorEnum.fromException(ex, eqNode)); + throw posixException(OSErrorEnum.fromException(ex)); } } @@ -747,7 +745,7 @@ public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeva } catch (IllegalBlockingModeException e) { throw posixException(OSErrorEnum.EINVAL); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached())); + throw posixException(OSErrorEnum.fromException(e)); } finally { i = 0; try { @@ -893,8 +891,7 @@ public long lseek(int fd, long offset, int how, @Bind Node inliningTarget, @Exclusive @Cached InlinedBranchProfile errorBranch, @Exclusive @Cached InlinedConditionProfile noFile, - @Exclusive @Cached InlinedConditionProfile notSeekable, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Exclusive @Cached InlinedConditionProfile notSeekable) throws PosixException { Channel channel = getFileChannel(fd); if (noFile.profile(inliningTarget, channel == null)) { throw posixException(OSErrorEnum.EBADF); @@ -914,7 +911,7 @@ public long lseek(int fd, long offset, int how, newPos = setPosition(offset, how, fc); } catch (Exception e) { errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } return newPos; } @@ -944,14 +941,13 @@ private static long setPosition(long pos, int how, SeekableByteChannel fc) throw @ExportMessage(name = "ftruncate") public void ftruncateMessage(int fd, long length, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { // TODO: will merge with super.ftruncate once the super class is merged with this class Object ret; try { ret = ftruncate(fd, length); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } if (ret == null) { errorBranch.enter(inliningTarget); @@ -962,14 +958,13 @@ public void ftruncateMessage(int fd, long length, @ExportMessage public void truncate(Object path, long length, @Bind Node inliningTarget, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = getTruffleFile(pathname, eqNode); + TruffleFile file = getTruffleFile(pathname); try { doTruncate(file, length); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -1068,7 +1063,7 @@ private void doLockOperation(int fd, Channel channel, boolean unlock, boolean sh } } } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached())); + throw posixException(OSErrorEnum.fromException(e)); } setFileLock(fd, lock); } @@ -1109,8 +1104,7 @@ private static boolean getBlocking(EmulatedSocket socket) { @ExportMessage @SuppressWarnings({"static-method", "unused"}) - public void setBlocking(int fd, boolean blocking, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public void setBlocking(int fd, boolean blocking) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { throw new UnsupportedPosixFeatureException("setBlocking was excluded"); } @@ -1133,7 +1127,7 @@ public void setBlocking(int fd, boolean blocking, } catch (PosixException e) { throw e; } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } // if we reach this point, it's an invalid FD throw posixException(OSErrorEnum.EBADFD); @@ -1198,13 +1192,13 @@ public long[] fstatat(int dirFd, Object path, boolean followSymlinks, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile f = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile f = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, toJavaStringNode); LinkOption[] linkOptions = getLinkOptions(followSymlinks); try { return fstat(f, linkOptions); } catch (Exception e) { errorBranch.enter(inliningTarget); - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } @@ -1215,7 +1209,6 @@ public long[] fstat(int fd, @Exclusive @Cached InlinedBranchProfile nullPathProfile, @Exclusive @Cached InlinedBranchProfile errorBranch, @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString path = getFilePath(fd, fromJavaStringNode); if (path == null) { @@ -1227,12 +1220,12 @@ public long[] fstat(int fd, } return fstatWithoutPath(fileChannel); } - TruffleFile f = getTruffleFile(path, eqNode); + TruffleFile f = getTruffleFile(path); try { return fstat(f, new LinkOption[0]); } catch (Exception e) { errorBranch.enter(inliningTarget); - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } @@ -1590,7 +1583,7 @@ public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile f = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile f = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, toJavaStringNode); if (f.exists(LinkOption.NOFOLLOW_LINKS)) { // we cannot check this if the file does not exist boolean isDirectory = f.isDirectory(LinkOption.NOFOLLOW_LINKS); @@ -1603,7 +1596,7 @@ public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean f.delete(); } catch (Exception e) { errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -1616,9 +1609,9 @@ public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, i @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { TruffleString srcPath = pathToTruffleString(oldPath, fromJavaStringNode); - TruffleFile srcFile = resolvePath(inliningTarget, oldFdDir, srcPath, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile srcFile = resolvePath(inliningTarget, oldFdDir, srcPath, defaultDirFdPofile, toJavaStringNode); TruffleString dstPath = pathToTruffleString(newPath, fromJavaStringNode); - TruffleFile dstFile = resolvePath(inliningTarget, newFdDir, srcPath, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile dstFile = resolvePath(inliningTarget, newFdDir, srcPath, defaultDirFdPofile, toJavaStringNode); try { if ((flags & PosixConstants.AT_SYMLINK_FOLLOW.value) != 0) { dstFile = dstFile.getCanonicalFile(); @@ -1626,7 +1619,7 @@ public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, i srcFile.createLink(dstFile); } catch (Exception e) { errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -1639,14 +1632,14 @@ public void symlinkat(Object target, int linkDirFd, Object link, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { TruffleString linkPath = pathToTruffleString(link, fromJavaStringNode); - TruffleFile linkFile = resolvePath(inliningTarget, linkDirFd, linkPath, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile linkFile = resolvePath(inliningTarget, linkDirFd, linkPath, defaultDirFdPofile, toJavaStringNode); TruffleString targetPath = pathToTruffleString(target, fromJavaStringNode); - TruffleFile targetFile = getTruffleFile(targetPath, eqNode); + TruffleFile targetFile = getTruffleFile(targetPath); try { linkFile.createSymbolicLink(targetFile); } catch (Exception e) { errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -1659,12 +1652,12 @@ public void mkdirat(int dirFd, Object path, int mode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { TruffleString pathStr = pathToTruffleString(path, fromJavaStringNode); - TruffleFile linkFile = resolvePath(inliningTarget, dirFd, pathStr, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile linkFile = resolvePath(inliningTarget, dirFd, pathStr, defaultDirFdPofile, toJavaStringNode); try { linkFile.createDirectory(); } catch (Exception e) { errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -1679,7 +1672,7 @@ public void chdir(Object path, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - chdirStr(inliningTarget, pathToTruffleString(path, fromJavaStringNode), errorBranch, eqNode); + chdirStr(inliningTarget, pathToTruffleString(path, fromJavaStringNode), errorBranch); } @ExportMessage @@ -1693,13 +1686,13 @@ public void fchdir(int fd, errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } - chdirStr(inliningTarget, path, errorBranch, eqNode); + chdirStr(inliningTarget, path, errorBranch); } private static final TruffleString T_FILESYSTEM_DOES_NOT_SUPPORT_CHANGING_CUR_DIR = tsLiteral("The filesystem does not support changing of the current working directory"); - private void chdirStr(Node inliningTarget, TruffleString pathStr, InlinedBranchProfile errorBranch, TruffleString.EqualNode eqNode) throws PosixException { - TruffleFile truffleFile = getTruffleFile(pathStr, eqNode).getAbsoluteFile(); + private void chdirStr(Node inliningTarget, TruffleString pathStr, InlinedBranchProfile errorBranch) throws PosixException { + TruffleFile truffleFile = getTruffleFile(pathStr).getAbsoluteFile(); if (!truffleFile.exists()) { errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.ENOENT); @@ -1764,47 +1757,44 @@ void reopen() throws PosixException { dirStream = file.newDirectoryStream(); iterator = dirStream.iterator(); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached())); + throw posixException(OSErrorEnum.fromException(e)); } } } @ExportMessage public Object opendir(Object path, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - return opendirImpl(pathToTruffleString(path, fromJavaStringNode), -1, eqNode); + return opendirImpl(pathToTruffleString(path, fromJavaStringNode), -1); } @ExportMessage public Object fdopendir(int fd, @Bind Node inliningTarget, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString path = getFilePath(fd, fromJavaStringNode); if (path == null) { errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.ENOENT); } - return opendirImpl(path, fd, eqNode); + return opendirImpl(path, fd); } - private EmulatedDirStream opendirImpl(TruffleString path, int fd, TruffleString.EqualNode eqNode) throws PosixException { - TruffleFile file = getTruffleFile(path, eqNode); + private EmulatedDirStream opendirImpl(TruffleString path, int fd) throws PosixException { + TruffleFile file = getTruffleFile(path); return new EmulatedDirStream(file, fd); } @ExportMessage @TruffleBoundary @SuppressWarnings("static-method") - public void closedir(Object dirStreamObj, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public void closedir(Object dirStreamObj) throws PosixException { EmulatedDirStream dirStream = (EmulatedDirStream) dirStreamObj; try { dirStream.closeStream(); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } finally { if (dirStream.fd != -1) { close(dirStream.fd); @@ -1815,8 +1805,7 @@ public void closedir(Object dirStreamObj, @ExportMessage @TruffleBoundary @SuppressWarnings("static-method") - public Object readdir(Object dirStreamObj, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public Object readdir(Object dirStreamObj) throws PosixException { EmulatedDirStream dirStream = (EmulatedDirStream) dirStreamObj; if (dirStream.needsReopen) { dirStream.reopen(); @@ -1828,7 +1817,7 @@ public Object readdir(Object dirStreamObj, return null; } } catch (DirectoryIteratorException e) { - throw posixException(OSErrorEnum.fromException(e.getCause(), eqNode)); + throw posixException(OSErrorEnum.fromException(e.getCause())); } } @@ -1862,8 +1851,7 @@ public Object dirEntryGetPath(Object dirEntry, Object scandirPath, @ExportMessage @TruffleBoundary @SuppressWarnings("static-method") - public long dirEntryGetInode(Object dirEntry, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public long dirEntryGetInode(Object dirEntry) throws PosixException { TruffleFile file = (TruffleFile) dirEntry; try { Attributes attributes = file.getAttributes(Collections.singletonList(UNIX_INODE), LinkOption.NOFOLLOW_LINKS); @@ -1871,7 +1859,7 @@ public long dirEntryGetInode(Object dirEntry, } catch (UnsupportedOperationException e) { return getEmulatedInode(file); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -1902,11 +1890,10 @@ public void utimensat(int dirFd, Object path, long[] timespec, boolean followSym @Bind Node inliningTarget, @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { TruffleString pathStr = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = resolvePath(inliningTarget, dirFd, pathStr, defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile file = resolvePath(inliningTarget, dirFd, pathStr, defaultDirFdPofile, toJavaStringNode); setUTimeNode.execute(inliningTarget, file, timespec, followSymlinks); } @@ -1914,10 +1901,9 @@ public void utimensat(int dirFd, Object path, long[] timespec, boolean followSym public void futimens(int fd, long[] timespec, @Bind Node inliningTarget, @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path, eqNode); + TruffleFile file = getTruffleFile(path); setUTimeNode.execute(inliningTarget, file, timespec, true); } @@ -1925,10 +1911,9 @@ public void futimens(int fd, long[] timespec, public void futimes(int fd, Timeval[] timeval, @Bind Node inliningTarget, @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path, eqNode); + TruffleFile file = getTruffleFile(path); setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); } @@ -1936,10 +1921,9 @@ public void futimes(int fd, Timeval[] timeval, public void lutimes(Object filename, Timeval[] timeval, @Bind Node inliningTarget, @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString filenameStr = pathToTruffleString(filename, fromJavaStringNode); - TruffleFile file = getTruffleFile(filenameStr, eqNode); + TruffleFile file = getTruffleFile(filenameStr); setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), false); } @@ -1947,10 +1931,9 @@ public void lutimes(Object filename, Timeval[] timeval, public void utimes(Object filename, Timeval[] timeval, @Bind Node inliningTarget, @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString filenameStr = pathToTruffleString(filename, fromJavaStringNode); - TruffleFile file = getTruffleFile(filenameStr, eqNode); + TruffleFile file = getTruffleFile(filenameStr); setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); } @@ -1970,10 +1953,9 @@ public abstract static class SetUTimeNode extends Node { @Specialization(guards = "timespec == null") static void doCurrentTime(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws PosixException { FileTime time = currentFileTime(); - setFileTimes(inliningTarget, followSymlinks, file, time, time, errBranch, eqNode); + setFileTimes(inliningTarget, followSymlinks, file, time, time, errBranch); } @TruffleBoundary @@ -1985,21 +1967,20 @@ private static FileTime currentFileTime() { // UnsupportedSpecializationException.. @Specialization(guards = {"timespec != null", "file != null"}) static void doGivenTime(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws PosixException { FileTime atime = toFileTime(timespec[0], timespec[1]); FileTime mtime = toFileTime(timespec[2], timespec[3]); - setFileTimes(inliningTarget, followSymlinks, file, mtime, atime, errBranch, eqNode); + setFileTimes(inliningTarget, followSymlinks, file, mtime, atime, errBranch); } - private static void setFileTimes(Node inliningTarget, boolean followSymlinks, TruffleFile file, FileTime mtime, FileTime atime, InlinedBranchProfile errBranch, TruffleString.EqualNode eqNode) + private static void setFileTimes(Node inliningTarget, boolean followSymlinks, TruffleFile file, FileTime mtime, FileTime atime, InlinedBranchProfile errBranch) throws PosixException { try { file.setLastAccessTime(atime, getLinkOptions(followSymlinks)); file.setLastModifiedTime(mtime, getLinkOptions(followSymlinks)); } catch (Exception e) { errBranch.enter(inliningTarget); - final ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); + final ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); // setLastAccessTime/setLastModifiedTime and NOFOLLOW_LINKS does not work (at least) // on OpenJDK8 on Linux and gives ELOOP error. See some explanation in this thread: // https://stackoverflow.com/questions/17308363/symlink-lastmodifiedtime-in-java-1-7 @@ -2031,14 +2012,14 @@ public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -2050,14 +2031,14 @@ public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -2075,7 +2056,7 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, } TruffleFile file = null; try { - file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); } catch (PosixException e) { // When the dirFd is invalid descriptor, we just return false, like the real faccessat return false; @@ -2113,7 +2094,7 @@ public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); Set permissions = modeToPosixFilePermissions(mode); if (getPythonOS() == PLATFORM_WIN32) { // cmp cpython's simple chmod implementation @@ -2125,25 +2106,24 @@ public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, try { file.setPosixPermissions(permissions, getLinkOptions(followSymlinks)); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } } @ExportMessage public void fchmod(int fd, int mode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { TruffleString path = getFilePath(fd, fromJavaStringNode); if (path == null) { throw posixException(OSErrorEnum.EBADF); } - TruffleFile file = getTruffleFile(path, eqNode); + TruffleFile file = getTruffleFile(path); Set permissions = modeToPosixFilePermissions(mode); try { file.setPosixPermissions(permissions); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -2164,7 +2144,7 @@ public Object readlinkat(int dirFd, Object path, @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); try { TruffleFile canonicalFile = file.getCanonicalFile(); if (file.equals(canonicalFile)) { @@ -2174,7 +2154,7 @@ public Object readlinkat(int dirFd, Object path, } catch (PosixException e) { throw e; } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -2632,7 +2612,7 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en // compatibility warning // TODO do we need to do this check (and the isExecutable() check later)? - TruffleFile cwdFile = cwd == null ? context.getEnv().getCurrentWorkingDirectory() : getTruffleFile(pathToTruffleString(cwd, fromJavaStringNode), TruffleString.EqualNode.getUncached()); + TruffleFile cwdFile = cwd == null ? context.getEnv().getCurrentWorkingDirectory() : getTruffleFile(pathToTruffleString(cwd, fromJavaStringNode)); if (!cwdFile.exists()) { throw posixException(OSErrorEnum.ENOENT); } @@ -2773,7 +2753,7 @@ private void handleIOError(int errpipe_write, IOException e) { if (e == null) { pair = new ErrorAndMessagePair(OSErrorEnum.ENOENT, OSErrorEnum.ENOENT.getMessage()); } else { - pair = OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached()); + pair = OSErrorEnum.fromException(e); } try { errChannel.write(ByteBuffer.wrap(("OSError:" + Long.toHexString(pair.oserror.getNumber()) + ":" + pair.message).getBytes())); @@ -2784,8 +2764,7 @@ private void handleIOError(int errpipe_write, IOException e) { } @ExportMessage - public void execv(Object pathname, Object[] args, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public void execv(Object pathname, Object[] args) throws PosixException { assert args.length > 0; String[] cmd = new String[args.length]; // ProcessBuilder does not accept separate executable name, we must overwrite the 0-th @@ -2797,7 +2776,7 @@ public void execv(Object pathname, Object[] args, try { execvInternal(cmd); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } throw shouldNotReachHere("Execv must not return normally"); } @@ -3005,7 +2984,6 @@ public SeekableByteChannel truncate(long size) throws IOException { final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @SuppressWarnings("unused") Object tagname, @Bind Node inliningTarget, @Shared("defaultDirProfile") @Cached InlinedConditionProfile isAnonymousProfile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { if (prot == PROT_NONE.value) { return MMapHandle.NONE; @@ -3021,7 +2999,7 @@ final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @Su } TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path, eqNode); + TruffleFile file = getTruffleFile(path); Set options = mmapProtToOptions(prot); // we create a new channel, the file may be closed but the mmap object should still work @@ -3031,7 +3009,7 @@ final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @Su position(fileChannel, offset); return new MMapHandle(fileChannel, offset); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -3059,15 +3037,14 @@ private static SeekableByteChannel newByteChannel(TruffleFile file, Set 0) { getByteBufferArray(readingBuffer, bytes, readSize); } return readSize; } - private static int readBytes(Node inliningTarget, MMapHandle handle, long index, ByteBuffer readingBuffer, InlinedBranchProfile errBranch, TruffleString.EqualNode eqNode) throws PosixException { + private static int readBytes(Node inliningTarget, MMapHandle handle, long index, ByteBuffer readingBuffer, InlinedBranchProfile errBranch) throws PosixException { try { position(handle.channel, index + handle.offset); return readChannel(handle.channel, readingBuffer); } catch (IOException e) { errBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -3123,8 +3098,7 @@ private static int readBytes(Node inliningTarget, MMapHandle handle, long index, @SuppressWarnings("static-method") public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws PosixException { if (mmap == MMapHandle.NONE) { errBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EACCES); @@ -3140,7 +3114,7 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, } catch (Exception e) { // Catching generic Exception to also cover NonWritableChannelException errBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -3161,8 +3135,7 @@ public void mmapFlush(Object mmap, long offset, long length) { @ExportMessage @SuppressWarnings("static-method") - public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length) throws PosixException { if (mmap == MMapHandle.NONE) { return; } @@ -3171,7 +3144,7 @@ public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length, try { closeChannel(handle.channel); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } handle.channel = null; } @@ -4835,7 +4808,7 @@ private static PosixException posixException(Exception e, TruffleString.EqualNod if (e instanceof PosixException) { throw (PosixException) e; } - ErrorAndMessagePair pair = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair pair = OSErrorEnum.fromException(e); throw new PosixErrnoException(pair.oserror.getNumber(), pair.message); } @@ -4853,13 +4826,13 @@ static long fileTimeNanoSecondsPart(FileTime t) { return t.toInstant().getNano(); } - private TruffleFile getTruffleFile(TruffleString path, TruffleString.EqualNode eqNode) throws PosixException { + private TruffleFile getTruffleFile(TruffleString path) throws PosixException { try { return context.getPublicTruffleFileRelaxed(path, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); } catch (Exception ex) { // So far it seem that this can only be InvalidPath exception from Java NIO, but we stay // on the safe side and catch generic exception - throw posixException(OSErrorEnum.fromException(ex, eqNode)); + throw posixException(OSErrorEnum.fromException(ex)); } } @@ -4867,13 +4840,13 @@ private TruffleFile getTruffleFile(TruffleString path, TruffleString.EqualNode e * Resolves the path relative to the directory given as file descriptor. Honors the * {@link PosixConstants#AT_FDCWD}. */ - private TruffleFile resolvePath(Node inliningTarget, int dirFd, TruffleString pathname, InlinedConditionProfile defaultDirFdPofile, TruffleString.EqualNode eqNode, - TruffleString.ToJavaStringNode toJavaStringNode) + private TruffleFile resolvePath(Node inliningTarget, int dirFd, TruffleString pathname, InlinedConditionProfile defaultDirFdPofile, + ToJavaStringNode toJavaStringNode) throws PosixException { if (defaultDirFdPofile.profile(inliningTarget, dirFd == AT_FDCWD.value)) { - return getTruffleFile(pathname, eqNode); + return getTruffleFile(pathname); } else { - TruffleFile file = getTruffleFile(pathname, eqNode); + TruffleFile file = getTruffleFile(pathname); if (file.isAbsolute()) { // Even if the dirFd is non-existing or otherwise wrong, we should not trigger // any error if the file path is already absolute @@ -4883,7 +4856,7 @@ private TruffleFile resolvePath(Node inliningTarget, int dirFd, TruffleString pa if (dirPath == null) { throw posixException(OSErrorEnum.EBADF); } - TruffleFile dir = getTruffleFile(dirPath, eqNode); + TruffleFile dir = getTruffleFile(dirPath); return dir.resolve(toJavaStringNode.execute(pathname)); } } From dc18eb7d408125929b50b6f5a8c054b27c5e1964 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Tue, 29 Sep 2026 16:20:46 +0200 Subject: [PATCH 015/129] Convert PosixSupportLibrary.read to a bare Java method (cherry picked from commit 145916fd447c006d0e7734023e5acdc76400153b) --- .../com/oracle/graal/python/test/SocketTests.java | 9 +++++---- .../builtins/modules/PosixModuleBuiltins.java | 5 ++--- .../python/builtins/modules/io/FileIOBuiltins.java | 9 ++++----- .../graal/python/runtime/EmulatedPosixSupport.java | 13 ++++--------- .../graal/python/runtime/LoggingPosixSupport.java | 7 +++---- .../graal/python/runtime/NativePosixSupport.java | 2 +- .../oracle/graal/python/runtime/PosixSupport.java | 4 ++++ .../graal/python/runtime/PosixSupportLibrary.java | 2 -- .../graal/python/runtime/PreInitPosixSupport.java | 9 ++++----- 9 files changed, 27 insertions(+), 33 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index f71fb33cf2..b476ef31cf 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -99,6 +99,7 @@ import java.util.stream.Stream; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.runtime.PosixSupport; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -158,7 +159,7 @@ public static String[] params() { private static final byte[] DATA2 = new byte[]{4, 5, 6, 7}; private static final UnixSockAddr UNIX_SOCK_ADDR_UNNAMED = new UnixSockAddr(new byte[0]); - private Object posixSupport; + private PosixSupport posixSupport; private PosixSupportLibrary lib; private UniversalSockAddrLibrary usaLib; private AddrInfoCursorLibrary aicLib; @@ -528,7 +529,7 @@ public void streamUnconnectedGetpeername() { @Test public void streamUnconnectedRead() { expectErrno(() -> { - lib.read(posixSupport, new TcpClient(AF_INET.value).fd, 10); + posixSupport.read(new TcpClient(AF_INET.value).fd, 10); }, OSErrorEnum.ENOTCONN); } @@ -565,7 +566,7 @@ public void streamListeningSend() { @Test public void streamListeningRead() { expectErrno(() -> { - lib.read(posixSupport, new TcpServer(AF_INET.value).fd, 10); + posixSupport.read(new TcpServer(AF_INET.value).fd, 10); }, OSErrorEnum.ENOTCONN); } @@ -1238,7 +1239,7 @@ void write(byte[] data) throws PosixException { } void read(byte[] expectedData) throws PosixException { - Buffer buf = lib.read(posixSupport, fd, expectedData.length * 2); + Buffer buf = posixSupport.read(fd, expectedData.length * 2); assertEquals(expectedData.length, buf.length); assertArrayEquals(expectedData, Arrays.copyOf(buf.data, expectedData.length)); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 10557b83a5..af36ccd76c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -987,7 +987,7 @@ static PBytes doRead(VirtualFrame frame, int fd, int length, throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, posixLib.strerror(context.getPosixSupport(), error)); } try { - return read(fd, length, inliningTarget, posixLib, context.getPosixSupport(), errorProfile1, gil); + return read(fd, length, inliningTarget, context.getPosixSupport(), errorProfile1, gil); } catch (PosixException e) { errorProfile2.enter(inliningTarget); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -996,14 +996,13 @@ static PBytes doRead(VirtualFrame frame, int fd, int length, public static PBytes read(int fd, int length, Node inliningTarget, - PosixSupportLibrary posixLib, PosixSupport posixSupport, InlinedBranchProfile errorProfile, GilNode gil) throws PosixException { gil.release(true); try { while (true) { try { - Buffer result = posixLib.read(posixSupport, fd, length); + Buffer result = posixSupport.read(fd, length); if (result.length > Integer.MAX_VALUE) { // sanity check that it is safe to cast result.length to int, to be // removed once we support large arrays diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index c462d056a4..b09f1d2ec0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -526,11 +526,10 @@ static Object read(VirtualFrame frame, PFileIO self, int size, @Cached InlinedBranchProfile readErrorProfile, @Cached InlinedBranchProfile readErrorProfile2, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + return PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); } catch (PosixException e) { if (e.hasErrno(EAGAIN)) { readErrorProfile2.enter(inliningTarget); @@ -592,7 +591,7 @@ static Object readall(VirtualFrame frame, PFileIO self, int bytesRead = 0; PBytes b; try { - b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); bytesRead = b.getSequenceStorage().length(); if (bytesRead == 0 || (mayBeQuick && bytesRead == bufsize - 1)) { return b; @@ -620,7 +619,7 @@ static Object readall(VirtualFrame frame, PFileIO self, int n; try { - b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize - bytesRead, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize - bytesRead, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); /* * PosixModuleBuiltins#ReadNode creates PBytes with exact size; */ @@ -674,7 +673,7 @@ static Object readinto(VirtualFrame frame, PFileIO self, Object buffer, return 0; } try { - PBytes data = PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + PBytes data = PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); int n = bufferLib.getBufferLength(data); bufferLib.readIntoBuffer(data, 0, buffer, 0, n, bufferLib); return n; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index f8adc19d73..e08b6c3d97 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -217,7 +217,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import com.oracle.truffle.api.strings.TruffleString.ToJavaStringNode; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.ProcessProperties; import org.graalvm.polyglot.io.ProcessHandler.Redirect; @@ -283,6 +282,7 @@ import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.api.strings.TruffleString.ToJavaStringNode; import com.sun.security.auth.UnixNumericGroupPrincipal; import com.sun.security.auth.module.UnixSystem; @@ -533,20 +533,15 @@ private static int doWriteOp(ByteBuffer data, WritableByteChannel channel) throw return channel.write(data); } - @ExportMessage - @SuppressWarnings({"unused", "static-method"}) - public Buffer read(int fd, long length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + public Buffer read(int fd, long length) throws PosixException { Channel channel = getFileChannel(fd); if (!(channel instanceof ReadableByteChannel)) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } try { return readBytesFromChannel((ReadableByteChannel) channel, length); } catch (Exception e) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } @@ -4841,7 +4836,7 @@ private TruffleFile getTruffleFile(TruffleString path) throws PosixException { * {@link PosixConstants#AT_FDCWD}. */ private TruffleFile resolvePath(Node inliningTarget, int dirFd, TruffleString pathname, InlinedConditionProfile defaultDirFdPofile, - ToJavaStringNode toJavaStringNode) + ToJavaStringNode toJavaStringNode) throws PosixException { if (defaultDirFdPofile.profile(inliningTarget, dirFd == AT_FDCWD.value)) { return getTruffleFile(pathname); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 7313ce5349..263b908779 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -174,12 +174,11 @@ final int close(int fd, } } - @ExportMessage - final Buffer read(int fd, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final Buffer read(int fd, long length) throws PosixException { logEnter("read", "%d, %d", fd, length); try { - Buffer retVal = lib.read(delegate, fd, length); + Buffer retVal = delegate.read(fd, length); logExit("read", "%d", retVal.length); return retVal; } catch (PosixException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index ba10dce091..7fc60426ed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -770,7 +770,7 @@ public int close(int fd) throws PosixException { return rv; } - @ExportMessage + @Override public Buffer read(int fd, long length) throws PosixException { long count = Math.min(length, MAX_READ); Buffer buffer = Buffer.allocate(count); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 2917505c04..0db3edd5c7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -40,6 +40,8 @@ */ package com.oracle.graal.python.runtime; +import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; +import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.nodes.Node; @@ -51,4 +53,6 @@ public void setEnv(@SuppressWarnings("unused") Env env) { public static PosixSupport get(Node node) { return PythonContext.get(node).getPosixSupport(); } + + public abstract Buffer read(int fd, long length) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 3a7b18cc1f..66f24eb41b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -92,8 +92,6 @@ public abstract class PosixSupportLibrary extends Library { public abstract int close(Object receiver, int fd) throws PosixException; - public abstract Buffer read(Object receiver, int fd, long length) throws PosixException; - public abstract long write(Object receiver, int fd, Buffer data) throws PosixException; /** Returns {@code 'r'}, {@code 'w'}, or zero when {@code fd} is not a Windows console. */ diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 81d70eafda..440d8661e0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -196,13 +196,12 @@ final int close(int fd, return nativeLib.close(nativePosixSupport, fd); } - @ExportMessage - final Buffer read(int fd, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final Buffer read(int fd, long length) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().read(emulatedPosixSupport, fd, length); + return emulatedPosixSupport.read(fd, length); } - return nativeLib.read(nativePosixSupport, fd, length); + return nativePosixSupport.read(fd, length); } @ExportMessage From 840fc97bd5797867aed3cc384fd6b568884ada10 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Tue, 29 Sep 2026 16:30:27 +0200 Subject: [PATCH 016/129] Convert PosixSupportLibrary.write to a bare Java method (cherry picked from commit 2d49eda89319707bb9c8b75094dec911819b603b) --- .../com/oracle/graal/python/test/SocketTests.java | 10 +++++----- .../modules/FaulthandlerModuleBuiltins.java | 2 +- .../builtins/modules/PosixModuleBuiltins.java | 7 +++---- .../builtins/modules/io/BufferedWriterNodes.java | 4 +--- .../python/builtins/modules/io/FileIOBuiltins.java | 3 +-- .../graal/python/runtime/EmulatedPosixSupport.java | 8 ++------ .../graal/python/runtime/LoggingPosixSupport.java | 7 +++---- .../graal/python/runtime/NativePosixSupport.java | 4 ++-- .../oracle/graal/python/runtime/PosixSupport.java | 4 +++- .../graal/python/runtime/PosixSupportLibrary.java | 2 -- .../graal/python/runtime/PreInitPosixSupport.java | 13 ++++++------- 11 files changed, 27 insertions(+), 37 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index b476ef31cf..3050124abf 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -98,8 +98,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.oracle.graal.python.PythonLanguage; -import com.oracle.graal.python.runtime.PosixSupport; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -111,9 +109,11 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; +import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.runtime.PosixConstants.MandatoryIntConstant; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; @@ -537,7 +537,7 @@ public void streamUnconnectedRead() { public void streamUnconnectedWrite() { // From send(2): Linux may return EPIPE instead of ENOTCONN. expectErrno(() -> { - lib.write(posixSupport, new TcpClient(AF_INET.value).fd, Buffer.wrap(DATA)); + posixSupport.write(new TcpClient(AF_INET.value).fd, Buffer.wrap(DATA)); }, OSErrorEnum.ENOTCONN, OSErrorEnum.EPIPE); } @@ -574,7 +574,7 @@ public void streamListeningRead() { public void streamListeningWrite() { // From send(2): Linux may return EPIPE instead of ENOTCONN. expectErrno(() -> { - lib.write(posixSupport, new TcpServer(AF_INET.value).fd, Buffer.wrap(DATA)); + posixSupport.write(new TcpServer(AF_INET.value).fd, Buffer.wrap(DATA)); }, OSErrorEnum.ENOTCONN, OSErrorEnum.EPIPE); } @@ -1235,7 +1235,7 @@ void sendto(byte[] data, int flags, UniversalSockAddr destAddr) throws PosixExce } void write(byte[] data) throws PosixException { - assertEquals(data.length, lib.write(posixSupport, fd, Buffer.wrap(data))); + assertEquals(data.length, posixSupport.write(fd, Buffer.wrap(data))); } void read(byte[] expectedData) throws PosixException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java index bccac49aa9..9264f75e7f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java @@ -408,7 +408,7 @@ public void write(int b) { public void flush() throws IOException { super.flush(); try { - PosixSupportLibrary.getUncached().write(PythonContext.get(null).getPosixSupport(), fd, PosixSupportLibrary.Buffer.wrap(bb.toArray())); + PythonContext.get(null).getPosixSupport().write(fd, PosixSupportLibrary.Buffer.wrap(bb.toArray())); } catch (PosixSupportLibrary.PosixException e) { // Ignore } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index af36ccd76c..e555fd5181 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1041,12 +1041,11 @@ static long doWrite(VirtualFrame frame, int fd, Object dataBuffer, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("dataBuffer") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return write(fd, bufferLib.getInternalOrCopiedByteArray(dataBuffer), bufferLib.getBufferLength(dataBuffer), inliningTarget, posixLib, context.getPosixSupport(), errorProfile, gil); + return write(fd, bufferLib.getInternalOrCopiedByteArray(dataBuffer), bufferLib.getBufferLength(dataBuffer), inliningTarget, context.getPosixSupport(), errorProfile, gil); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } finally { @@ -1055,13 +1054,13 @@ static long doWrite(VirtualFrame frame, int fd, Object dataBuffer, } public static long write(int fd, byte[] dataBytes, - int dataLen, Node inliningTarget, PosixSupportLibrary posixLib, PosixSupport posixSupport, + int dataLen, Node inliningTarget, PosixSupport posixSupport, InlinedBranchProfile errorProfile, GilNode gil) throws PosixException { gil.release(true); try { while (true) { try { - return posixLib.write(posixSupport, fd, new Buffer(dataBytes, dataLen)); + return posixSupport.write(fd, new Buffer(dataBytes, dataLen)); } catch (PosixErrnoException e) { errorProfile.enter(inliningTarget); if (e.hasErrno(OSErrorEnum.EINTR)) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java index a182c5e772..76dd9cdd65 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java @@ -70,7 +70,6 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; @@ -237,7 +236,6 @@ abstract static class RawWriteNode extends PNodeWithContext { @Specialization(guards = "self.hasFileIORaw()") static int bufferedwriterRawWriteFileIO(VirtualFrame frame, Node inliningTarget, PBuffered self, byte[] buf, int len, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -252,7 +250,7 @@ static int bufferedwriterRawWriteFileIO(VirtualFrame frame, Node inliningTarget, final int n; try { n = Math.toIntExact(PosixModuleBuiltins.WriteNode.write(fileIO.getFD(), buf, len, - inliningTarget, posixLib, context.getPosixSupport(), errorProfile, gil)); + inliningTarget, context.getPosixSupport(), errorProfile, gil)); } catch (PosixException e) { if (e.hasErrno(OSErrorEnum.EAGAIN)) { return -2; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index b09f1d2ec0..bebb280d66 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -718,7 +718,6 @@ static Object write(VirtualFrame frame, PFileIO self, Object buffer, @Bind Node inliningTarget, @Bind PythonContext context, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -732,7 +731,7 @@ static Object write(VirtualFrame frame, PFileIO self, Object buffer, } try { return PosixModuleBuiltins.WriteNode.write(self.getFD(), bufferLib.getInternalOrCopiedByteArray(buffer), bufferLib.getBufferLength(buffer), - inliningTarget, posixLib, context.getPosixSupport(), errorProfile, gil); + inliningTarget, context.getPosixSupport(), errorProfile, gil); } catch (PosixException e) { if (e.hasErrno(EAGAIN)) { return PNone.NONE; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index e08b6c3d97..77cd012eb7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -497,19 +497,15 @@ private int openTruffleFile(TruffleFile truffleFile, Set opt return open(file, fc); } - @ExportMessage - public long write(int fd, Buffer data, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + public long write(int fd, Buffer data) throws PosixException { Channel channel = getFileChannel(fd); if (!(channel instanceof WritableByteChannel)) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } try { return doWriteOp(data.getByteBuffer(), (WritableByteChannel) channel); } catch (Exception e) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 263b908779..884c0c7bf5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -186,12 +186,11 @@ public final Buffer read(int fd, long length) throws PosixException { } } - @ExportMessage - final long write(int fd, Buffer data, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final long write(int fd, Buffer data) throws PosixException { logEnter("write", "%d, %d", fd, data.length); try { - return logExit("write", "%d", lib.write(delegate, fd, data)); + return logExit("write", "%d", delegate.write(fd, data)); } catch (PosixException e) { throw logException("write", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 7fc60426ed..6297f6a005 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -59,8 +59,8 @@ import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN_SIN_PORT; import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_SA_FAMILY; import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_UN_SUN_PATH; -import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_POLLFD; +import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN6; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_SA_FAMILY; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_STORAGE; @@ -787,7 +787,7 @@ public Buffer read(int fd, long length) throws PosixException { } } - @ExportMessage + @Override public long write(int fd, Buffer data) throws PosixException { long nativeBuffer = NativeMemory.mallocByteArrayOrNull(data.length); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 0db3edd5c7..855075113e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -55,4 +55,6 @@ public static PosixSupport get(Node node) { } public abstract Buffer read(int fd, long length) throws PosixException; + + public abstract long write(int fd, Buffer data) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 66f24eb41b..6af29892a4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -92,8 +92,6 @@ public abstract class PosixSupportLibrary extends Library { public abstract int close(Object receiver, int fd) throws PosixException; - public abstract long write(Object receiver, int fd, Buffer data) throws PosixException; - /** Returns {@code 'r'}, {@code 'w'}, or zero when {@code fd} is not a Windows console. */ public abstract int getWindowsConsoleType(Object receiver, int fd); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 440d8661e0..a6568c3230 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -74,13 +74,13 @@ @ExportLibrary(PosixSupportLibrary.class) public class PreInitPosixSupport extends PosixSupport { - protected final PosixSupport nativePosixSupport; - private PosixSupport emulatedPosixSupport; + protected final NativePosixSupport nativePosixSupport; + private EmulatedPosixSupport emulatedPosixSupport; private HashSet emulatedFds; private IdentityHashMap emulatedDirStreams; private boolean inPreInitialization; - public PreInitPosixSupport(Env env, PosixSupport nativePosixSupport, PosixSupport emulatedPosixSupport) { + public PreInitPosixSupport(Env env, NativePosixSupport nativePosixSupport, EmulatedPosixSupport emulatedPosixSupport) { this.inPreInitialization = env.isPreInitialization(); this.nativePosixSupport = nativePosixSupport; this.emulatedPosixSupport = emulatedPosixSupport; @@ -204,11 +204,10 @@ public final Buffer read(int fd, long length) throws PosixException { return nativePosixSupport.read(fd, length); } - @ExportMessage - final long write(int fd, Buffer data, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final long write(int fd, Buffer data) throws PosixException { checkNotInPreInitialization(); - return nativeLib.write(nativePosixSupport, fd, data); + return nativePosixSupport.write(fd, data); } @ExportMessage From 1851a4673793866e2083554a90bd8e9a0f62f4cc Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 7 Oct 2026 17:29:34 +0200 Subject: [PATCH 017/129] Convert PosixSupportLibrary.(getWindowsConsoleType|writeWindowsConsole) (cherry picked from commit 68b4fa22de07011aeefeb40207b146a4a01a731d) --- .../builtins/modules/SysModuleBuiltins.java | 8 ++++---- .../modules/io/WindowsConsoleIOBuiltins.java | 9 +++------ .../python/runtime/EmulatedPosixSupport.java | 14 ++++++-------- .../python/runtime/LoggingPosixSupport.java | 16 ++++++++-------- .../graal/python/runtime/NativePosixSupport.java | 6 ++++-- .../graal/python/runtime/PosixSupport.java | 5 +++++ .../python/runtime/PosixSupportLibrary.java | 5 ----- .../python/runtime/PreInitPosixSupport.java | 16 ++++++++-------- 8 files changed, 38 insertions(+), 41 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index 08d77d6b44..0e16aa772a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -813,20 +813,20 @@ static void initStd(Python3Core core) { BufferedReaderBuiltins.BufferedReaderInit.internalInit(stdinBuffer, stdinFileIO, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); setWrapper(T_STDIN, T___STDIN__, T_R, stdioEncoding, stdioError, PNone.NONE, stdinBuffer, sysModule, language, true); - PFileIO stdoutFileIO = createStdoutRaw(context, language, posixSupport, posixLib, toTruffleStringUncached(""), 1); + PFileIO stdoutFileIO = createStdoutRaw(context, language, toTruffleStringUncached(""), 1); Object stdoutBuffer = createBufferedIO(buffering, language, stdoutFileIO, posixSupport, posixLib); TruffleString stdoutEncoding = isWindowsConsoleIO(stdoutFileIO) ? StringLiterals.T_UTF8 : stdioEncoding; setWrapper(T_STDOUT, T___STDOUT__, T_W, stdoutEncoding, stdioError, PNone.NONE, stdoutBuffer, sysModule, language, buffering); - PFileIO stderr = createStdoutRaw(context, language, posixSupport, posixLib, toTruffleStringUncached(""), 2); + PFileIO stderr = createStdoutRaw(context, language, toTruffleStringUncached(""), 2); Object stderrBuffer = createBufferedIO(buffering, language, stderr, posixSupport, posixLib); TruffleString stderrEncoding = isWindowsConsoleIO(stderr) ? StringLiterals.T_UTF8 : stdioEncoding; setWrapper(T_STDERR, T___STDERR__, T_W, stderrEncoding, T_BACKSLASHREPLACE, PNone.NONE, stderrBuffer, sysModule, language, buffering); } - private static PFileIO createStdoutRaw(PythonContext context, PythonLanguage language, Object posixSupport, PosixSupportLibrary posixLib, TruffleString name, int fd) { + private static PFileIO createStdoutRaw(PythonContext context, PythonLanguage language, TruffleString name, int fd) { if (getPythonOS() == PLATFORM_WIN32 && !context.getOption(PythonOptions.LegacyWindowsStdio)) { - int consoleType = posixLib.getWindowsConsoleType(posixSupport, fd); + int consoleType = context.getPosixSupport().getWindowsConsoleType(fd); if (consoleType != 0) { PFileIO consoleIO = WindowsConsoleIOBuiltins.create(language); WindowsConsoleIOBuiltins.internalInit(consoleIO, name, fd, IOMode.WB, consoleType); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java index be004a262d..d507e6c635 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java @@ -79,7 +79,6 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; @@ -150,13 +149,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone init(PFileIO self, int file, IONodes.IOMode mode, @SuppressWarnings("unused") boolean closefd, @SuppressWarnings("unused") Object opener, @Bind Node inliningTarget, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { + @Bind PythonContext context) { if (file < 0) { throw PRaiseNode.raiseStatic(inliningTarget, ValueError, NEG_FILE_DESC); } // We don't release the GIL because CPython doesn't do it - int consoleType = posixLib.getWindowsConsoleType(context.getPosixSupport(), file); + int consoleType = context.getPosixSupport().getWindowsConsoleType(file); if (consoleType == 0) { throw PRaiseNode.raiseStatic(inliningTarget, ValueError, CANNOT_OPEN_NON_CONSOLE_FILE); } @@ -179,7 +177,6 @@ static Object write(VirtualFrame frame, PFileIO self, Object buffer, @Bind Node inliningTarget, @Bind PythonContext context, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { @@ -194,7 +191,7 @@ static Object write(VirtualFrame frame, PFileIO self, Object buffer, try { gil.release(true); try { - return posixLib.writeWindowsConsole(context.getPosixSupport(), self.getFD(), new Buffer(bytes, length)); + return context.getPosixSupport().writeWindowsConsole(self.getFD(), new Buffer(bytes, length)); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 77cd012eb7..ca6a164fdb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -510,18 +510,16 @@ public long write(int fd, Buffer data) throws PosixException { } } - @ExportMessage - @SuppressWarnings("unused") + @Override + @TruffleBoundary public int getWindowsConsoleType(int fd) { return 0; } - @ExportMessage - public long writeWindowsConsole(int fd, Buffer data, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { - return write(fd, data, inliningTarget, errorBranch, eqNode); + @Override + @TruffleBoundary + public long writeWindowsConsole(int fd, Buffer data) throws PosixException { + return write(fd, data); } @TruffleBoundary(allowInlining = true) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 884c0c7bf5..a517e7aeb5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -196,19 +196,19 @@ public final long write(int fd, Buffer data) throws PosixException { } } - @ExportMessage - final int getWindowsConsoleType(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int getWindowsConsoleType(int fd) { logEnter("getWindowsConsoleType", "%d", fd); - return logExit("getWindowsConsoleType", "%d", lib.getWindowsConsoleType(delegate, fd)); + return logExit("getWindowsConsoleType", "%d", delegate.getWindowsConsoleType(fd)); } - @ExportMessage - final long writeWindowsConsole(int fd, Buffer data, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long writeWindowsConsole(int fd, Buffer data) throws PosixException { logEnter("writeWindowsConsole", "%d, %d", fd, data.length); try { - return logExit("writeWindowsConsole", "%d", lib.writeWindowsConsole(delegate, fd, data)); + return logExit("writeWindowsConsole", "%d", delegate.writeWindowsConsole(fd, data)); } catch (PosixException e) { throw logException("writeWindowsConsole", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 6297f6a005..d2c64b3f36 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -802,12 +802,14 @@ public long write(int fd, Buffer data) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int getWindowsConsoleType(int fd) { return posixNativeFunctionInvoker.call_get_windows_console_type(fd); } - @ExportMessage + @Override + @TruffleBoundary public long writeWindowsConsole(int fd, Buffer data) throws PosixException { long nativeBuffer = NativeMemory.mallocByteArrayOrNull(data.length); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 855075113e..30af32f830 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -57,4 +57,9 @@ public static PosixSupport get(Node node) { public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; + + /** Returns {@code 'r'}, {@code 'w'}, or zero when {@code fd} is not a Windows console. */ + public abstract int getWindowsConsoleType(int fd); + + public abstract long writeWindowsConsole(int fd, Buffer data) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 6af29892a4..fd740e338d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -92,11 +92,6 @@ public abstract class PosixSupportLibrary extends Library { public abstract int close(Object receiver, int fd) throws PosixException; - /** Returns {@code 'r'}, {@code 'w'}, or zero when {@code fd} is not a Windows console. */ - public abstract int getWindowsConsoleType(Object receiver, int fd); - - public abstract long writeWindowsConsole(Object receiver, int fd, Buffer data) throws PosixException; - public abstract int dup(Object receiver, int fd) throws PosixException; public abstract int dup2(Object receiver, int fd, int fd2, boolean inheritable) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index a6568c3230..43970a1ad5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -210,20 +210,20 @@ public final long write(int fd, Buffer data) throws PosixException { return nativePosixSupport.write(fd, data); } - @ExportMessage - final int getWindowsConsoleType(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int getWindowsConsoleType(int fd) { if (inPreInitialization) { return 0; } - return nativeLib.getWindowsConsoleType(nativePosixSupport, fd); + return nativePosixSupport.getWindowsConsoleType(fd); } - @ExportMessage - final long writeWindowsConsole(int fd, Buffer data, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long writeWindowsConsole(int fd, Buffer data) throws PosixException { checkNotInPreInitialization(); - return nativeLib.writeWindowsConsole(nativePosixSupport, fd, data); + return nativePosixSupport.writeWindowsConsole(fd, data); } @ExportMessage From 2cd95f13bef527f966aa9f9700899ab8b74dae6a Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Tue, 29 Sep 2026 17:01:32 +0200 Subject: [PATCH 018/129] Introduce Path abstraction to PosixSupport (cherry picked from commit 827aad9836e704b6333594236da2c1760d206b49) --- .../src/com/oracle/graal/python/runtime/PosixSupport.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 30af32f830..b8b22278ac 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -46,6 +46,10 @@ import com.oracle.truffle.api.nodes.Node; public abstract class PosixSupport { + + public static abstract class Path { + } + public void setEnv(@SuppressWarnings("unused") Env env) { // nop } From dd82c104ae9e0094ae9c9761e50f5166a73d8520 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 09:42:01 +0200 Subject: [PATCH 019/129] Accept Java String in PythonContext.getPublicTruffleFileRelaxed (cherry picked from commit 58bfbc60547df23492794a8e3fae1286d374e953) --- .../oracle/graal/python/PythonLanguage.java | 6 ++--- .../modules/GraalPythonModuleBuiltins.java | 7 +++--- .../builtins/modules/JavaModuleBuiltins.java | 11 +++++---- .../objects/cext/capi/CApiContext.java | 2 +- .../graal/python/lib/PyTraceBackPrint.java | 4 ++-- .../python/runtime/EmulatedPosixSupport.java | 2 +- .../graal/python/runtime/PythonContext.java | 23 +++++++++++-------- 7 files changed, 31 insertions(+), 24 deletions(-) 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 25f73178cd..aa23d8192e 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 @@ -27,7 +27,7 @@ import static com.oracle.graal.python.annotations.PythonOS.PLATFORM_WIN32; import static com.oracle.graal.python.nodes.BuiltinNames.T__SIGNAL; -import static com.oracle.graal.python.nodes.StringLiterals.T_PY_EXTENSION; +import static com.oracle.graal.python.nodes.StringLiterals.J_PY_EXTENSION; import static com.oracle.graal.python.nodes.truffle.TruffleStringMigrationHelpers.isJavaString; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; @@ -304,7 +304,7 @@ public static PlatformInfo getPlatformInfo() { public static final String MIME_TYPE = "text/x-python"; - public static final TruffleString[] T_DEFAULT_PYTHON_EXTENSIONS = new TruffleString[]{T_PY_EXTENSION, tsLiteral(".pyc")}; + public static final String[] T_DEFAULT_PYTHON_EXTENSIONS = new String[]{J_PY_EXTENSION, ".pyc"}; public static final TruffleLogger LOGGER = TruffleLogger.getLogger(ID, PythonLanguage.class); @@ -910,7 +910,7 @@ public static Source newSource(PythonContext ctxt, TruffleString tsrc, TruffleSt String src = tsrc.toJavaStringUncached(); if (mayBeFile) { try { - TruffleFile truffleFile = ctxt.getPublicTruffleFileRelaxed(name, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); + TruffleFile truffleFile = ctxt.getPublicTruffleFileRelaxed(name.toJavaStringUncached(), PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); if (truffleFile.exists()) { // XXX: (tfel): We don't know if the expression has anything to do with the // filename that's given. We would really have to compare the entire 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 94c1c4d94e..5b3e0b0016 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 @@ -165,7 +165,6 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaLongLossyNode; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; -import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.nodes.util.ToNativePrimitiveStorageNode; import com.oracle.graal.python.pegparser.InputType; import com.oracle.graal.python.runtime.ExecutionContext; @@ -630,13 +629,13 @@ private static Object doLoadBytecodeFile(Object bytecodePath, Object sourcePath, @GenerateNodeFactory public abstract static class ReadFileNode extends PythonUnaryBuiltinNode { @Specialization - PBytes doString(VirtualFrame frame, Object filenameObj, + static PBytes doString(VirtualFrame frame, Object filenameObj, @Bind Node inliningTarget, @Bind PythonContext context, - @Cached CastToTruffleStringNode castToTruffleStringNode, + @Cached CastToJavaStringNode castToStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - TruffleString filename = castToTruffleStringNode.execute(inliningTarget, filenameObj); + String filename = castToStringNode.execute(filenameObj); TruffleFile file = context.getPublicTruffleFileRelaxed(filename, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); byte[] bytes = file.readAllBytes(); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java index 619cb9dc1d..ae410da54a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -99,7 +99,7 @@ @CoreFunctions(defineModule = J_JAVA) public final class JavaModuleBuiltins extends PythonBuiltins { - private static final TruffleString T_JAR = tsLiteral(".jar"); + private static final String J_JAR = ".jar"; @Override protected List> getNodeFactories() { @@ -159,9 +159,11 @@ abstract static class AddToClassPathNode extends PythonBuiltinNode { @Specialization static PNone add(Object[] args, @Bind Node inliningTarget, + @Bind PythonContext context, @Cached CastToTruffleStringNode castToString, + @Cached TruffleString.ToJavaStringNode toJavaStringNode, @Cached PRaiseNode raiseNode) { - Env env = PythonContext.get(inliningTarget).getEnv(); + Env env = context.getEnv(); if (!env.isHostLookupAllowed()) { throw raiseNode.raise(inliningTarget, PythonErrorType.NotImplementedError, ErrorMessages.HOST_ACCESS_NOT_ALLOWED); } @@ -172,7 +174,8 @@ static PNone add(Object[] args, entry = castToString.execute(inliningTarget, arg); // Always allow accessing JAR files in the language home; folders are allowed // implicitly - env.addToHostClassPath(PythonContext.get(inliningTarget).getPublicTruffleFileRelaxed(entry, T_JAR)); + String jEntry = toJavaStringNode.execute(entry); + env.addToHostClassPath(context.getPublicTruffleFileRelaxed(jEntry, J_JAR)); } catch (CannotCastException e) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.CLASSPATH_ARG_MUST_BE_STRING, i + 1, arg); } catch (SecurityException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java index ed6689f364..ef7f80fa81 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java @@ -1226,7 +1226,7 @@ public static Object loadCExtModule(Node location, PythonContext context, Module CApiContext cApiContext = CApiContext.ensureCapiWasLoaded(location, context, spec.name, spec.path); NativeLibrary library; - TruffleFile realPath = context.getPublicTruffleFileRelaxed(spec.path, context.getExtensionSuffix()).getCanonicalFile(); + TruffleFile realPath = context.getPublicTruffleFileRelaxed(spec.path.toJavaStringUncached(), context.getExtensionSuffix().toJavaStringUncached()).getCanonicalFile(); String loadPath = cApiContext.nativeLibraryLocator.resolve(context, realPath); getLogger(CApiContext.class).config(String.format("loading module %s (real path: %s) as native", spec.path, loadPath)); int dlopenFlags = context.getDlopenFlags(); 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 6088c97134..d5c53cab02 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 @@ -254,9 +254,9 @@ protected static TruffleString getIndent(int indent) { protected static CharSequence getSourceLine(TruffleString fileName, int lineNo) { final PythonContext context = PythonContext.get(null); - TruffleFile file = null; + TruffleFile file; try { - file = context.getPublicTruffleFileRelaxed(fileName, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); + file = context.getPublicTruffleFileRelaxed(fileName.toJavaStringUncached(), PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); } catch (IllegalArgumentException | SecurityException | UnsupportedOperationException e) { return null; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index ca6a164fdb..0659fb3e6e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -4817,7 +4817,7 @@ static long fileTimeNanoSecondsPart(FileTime t) { private TruffleFile getTruffleFile(TruffleString path) throws PosixException { try { - return context.getPublicTruffleFileRelaxed(path, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); + return context.getPublicTruffleFileRelaxed(path.toJavaStringUncached(), PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); } catch (Exception ex) { // So far it seem that this can only be InvalidPath exception from Java NIO, but we stay // on the safe side and catch generic exception 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 92738a9cfd..faa508e02e 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 @@ -2362,33 +2362,38 @@ public boolean setGilLockedDuringForeignCalls(boolean lock) { return old; } + @TruffleBoundary(allowInlining = true) + public TruffleFile getPublicTruffleFileRelaxed(TruffleString path) { + return getPublicTruffleFileRelaxed(path.toJavaStringUncached()); + } + /** * This is like {@code Env#getPublicTruffleFile(String)} but also allows access to files in the * language home directory matching one of the given file extensions. This is mostly useful to * access files of the {@code stdlib}, {@code core} or similar. */ @TruffleBoundary - public TruffleFile getPublicTruffleFileRelaxed(TruffleString path, TruffleString... allowedSuffixes) { - TruffleFile f = env.getInternalTruffleFile(path.toJavaStringUncached()); + public TruffleFile getPublicTruffleFileRelaxed(String path, String... allowedSuffixes) { + TruffleFile f = env.getInternalTruffleFile(path); // 'isDirectory' does deliberately not follow symlinks because otherwise this could allow to // escape the language home directory. // Also, during pre-initialization, we allow full internal access. if (env.isPreInitialization() || isPyFileInLanguageHome(f) && (f.isDirectory(LinkOption.NOFOLLOW_LINKS) || hasAllowedSuffix(path, allowedSuffixes))) { return f; } else { - return env.getPublicTruffleFile(path.toJavaStringUncached()); + return env.getPublicTruffleFile(path); } } - @TruffleBoundary(allowInlining = true) - private static boolean hasAllowedSuffix(TruffleString path, TruffleString[] allowedSuffixes) { - int pathLen = path.codePointLengthUncached(TS_ENCODING); - for (TruffleString suffix : allowedSuffixes) { - int suffixLen = suffix.codePointLengthUncached(TS_ENCODING); + private static boolean hasAllowedSuffix(String path, String[] allowedSuffixes) { + CompilerAsserts.neverPartOfCompilation(); + int pathLen = path.length(); + for (String suffix : allowedSuffixes) { + int suffixLen = suffix.length(); if (suffixLen > pathLen) { continue; } - if (path.regionEqualsUncached(pathLen - suffixLen, suffix, 0, suffixLen, TS_ENCODING)) { + if (path.endsWith(suffix)) { return true; } } From 0af9ee3544bf9b2ecd5afc5d30f7eb63aff73d4a Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 10:26:05 +0200 Subject: [PATCH 020/129] Use j.l.String as backend path type in EmulatedPosixSupport (cherry picked from commit 5f8b5f6c05a24186a3bc91e4cca43c76a8df9240) --- .../python/runtime/EmulatedPosixSupport.java | 279 ++++++------------ 1 file changed, 97 insertions(+), 182 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 0659fb3e6e..1d9ce9ea7b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -282,7 +282,6 @@ import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; -import com.oracle.truffle.api.strings.TruffleString.ToJavaStringNode; import com.sun.security.auth.UnixNumericGroupPrincipal; import com.sun.security.auth.module.UnixSystem; @@ -392,7 +391,7 @@ public TruffleString getBackend() { @ExportMessage public static class Getpid { - private static final TruffleString T_PROC_SELF_STAT = tsLiteral("/proc/self/stat"); + private static final String T_PROC_SELF_STAT = "/proc/self/stat"; @Specialization(rewriteOn = Exception.class) @TruffleBoundary @@ -459,12 +458,8 @@ public int closeMessage(int fd) throws PosixException { public int openat(int dirFd, Object path, int flags, int mode, @Bind Node inliningTarget, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, toJavaStringNode); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); Set options = flagsToOptions(flags); FileAttribute> attributes = modeToAttributes(mode & ~currentUmask); try { @@ -945,11 +940,8 @@ public void ftruncateMessage(int fd, long length, } @ExportMessage - public void truncate(Object path, long length, - @Bind Node inliningTarget, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = getTruffleFile(pathname); + public void truncate(Object path, long length) throws PosixException { + TruffleFile file = getTruffleFile(pathToJavaString(path)); try { doTruncate(file, length); } catch (Exception e) { @@ -1176,12 +1168,8 @@ public long sysconf(int name) throws PosixException { public long[] fstatat(int dirFd, Object path, boolean followSymlinks, @Bind Node inliningTarget, @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile f = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, toJavaStringNode); + @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile f = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); LinkOption[] linkOptions = getLinkOptions(followSymlinks); try { return fstat(f, linkOptions); @@ -1197,9 +1185,8 @@ public long[] fstat(int fd, @Bind Node inliningTarget, @Exclusive @Cached InlinedBranchProfile nullPathProfile, @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); + @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + String path = getFilePath(fd); if (path == null) { nullPathProfile.enter(inliningTarget); Channel fileChannel = getFileChannel(fd); @@ -1225,7 +1212,7 @@ public long[] fstat(int fd, public long[] statvfs(Object path) throws PosixException { try { Env env = PythonContext.get(null).getEnv(); - TruffleFile truffleFile = env.getPublicTruffleFile((String) path); + TruffleFile truffleFile = env.getPublicTruffleFile(pathToJavaString(path)); TruffleFile.FileStoreInfo fileStoreInfo = truffleFile.getFileStoreInfo(); long totalSpace, usableSpace, unallocatedSpace, blockSize; @@ -1567,12 +1554,8 @@ private static String getHostName(boolean withoutSocket) { public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean rmdir, @Bind Node inliningTarget, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile f = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, toJavaStringNode); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile f = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); if (f.exists(LinkOption.NOFOLLOW_LINKS)) { // we cannot check this if the file does not exist boolean isDirectory = f.isDirectory(LinkOption.NOFOLLOW_LINKS); @@ -1593,14 +1576,9 @@ public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, @Bind Node inliningTarget, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString srcPath = pathToTruffleString(oldPath, fromJavaStringNode); - TruffleFile srcFile = resolvePath(inliningTarget, oldFdDir, srcPath, defaultDirFdPofile, toJavaStringNode); - TruffleString dstPath = pathToTruffleString(newPath, fromJavaStringNode); - TruffleFile dstFile = resolvePath(inliningTarget, newFdDir, srcPath, defaultDirFdPofile, toJavaStringNode); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile srcFile = resolvePath(inliningTarget, oldFdDir, pathToJavaString(oldPath), defaultDirFdPofile); + TruffleFile dstFile = resolvePath(inliningTarget, newFdDir, pathToJavaString(newPath), defaultDirFdPofile); try { if ((flags & PosixConstants.AT_SYMLINK_FOLLOW.value) != 0) { dstFile = dstFile.getCanonicalFile(); @@ -1616,14 +1594,9 @@ public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, i public void symlinkat(Object target, int linkDirFd, Object link, @Bind Node inliningTarget, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString linkPath = pathToTruffleString(link, fromJavaStringNode); - TruffleFile linkFile = resolvePath(inliningTarget, linkDirFd, linkPath, defaultDirFdPofile, toJavaStringNode); - TruffleString targetPath = pathToTruffleString(target, fromJavaStringNode); - TruffleFile targetFile = getTruffleFile(targetPath); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile linkFile = resolvePath(inliningTarget, linkDirFd, pathToJavaString(link), defaultDirFdPofile); + TruffleFile targetFile = getTruffleFile(pathToJavaString(target)); try { linkFile.createSymbolicLink(targetFile); } catch (Exception e) { @@ -1636,12 +1609,8 @@ public void symlinkat(Object target, int linkDirFd, Object link, public void mkdirat(int dirFd, Object path, int mode, @Bind Node inliningTarget, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathStr = pathToTruffleString(path, fromJavaStringNode); - TruffleFile linkFile = resolvePath(inliningTarget, dirFd, pathStr, defaultDirFdPofile, toJavaStringNode); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile linkFile = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); try { linkFile.createDirectory(); } catch (Exception e) { @@ -1658,19 +1627,15 @@ public Object getcwd() { @ExportMessage public void chdir(Object path, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - chdirStr(inliningTarget, pathToTruffleString(path, fromJavaStringNode), errorBranch); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + chdirStr(inliningTarget, pathToJavaString(path), errorBranch); } @ExportMessage public void fchdir(int fd, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + String path = getFilePath(fd); if (path == null) { errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); @@ -1680,7 +1645,7 @@ public void fchdir(int fd, private static final TruffleString T_FILESYSTEM_DOES_NOT_SUPPORT_CHANGING_CUR_DIR = tsLiteral("The filesystem does not support changing of the current working directory"); - private void chdirStr(Node inliningTarget, TruffleString pathStr, InlinedBranchProfile errorBranch) throws PosixException { + private void chdirStr(Node inliningTarget, String pathStr, InlinedBranchProfile errorBranch) throws PosixException { TruffleFile truffleFile = getTruffleFile(pathStr).getAbsoluteFile(); if (!truffleFile.exists()) { errorBranch.enter(inliningTarget); @@ -1752,17 +1717,15 @@ void reopen() throws PosixException { } @ExportMessage - public Object opendir(Object path, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - return opendirImpl(pathToTruffleString(path, fromJavaStringNode), -1); + public Object opendir(Object path) throws PosixException { + return opendirImpl(pathToJavaString(path), -1); } @ExportMessage public Object fdopendir(int fd, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + String path = getFilePath(fd); if (path == null) { errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.ENOENT); @@ -1770,7 +1733,7 @@ public Object fdopendir(int fd, return opendirImpl(path, fd); } - private EmulatedDirStream opendirImpl(TruffleString path, int fd) throws PosixException { + private EmulatedDirStream opendirImpl(String path, int fd) throws PosixException { TruffleFile file = getTruffleFile(path); return new EmulatedDirStream(file, fd); } @@ -1827,12 +1790,11 @@ public Object dirEntryGetName(Object dirEntry) { @ExportMessage @SuppressWarnings("static-method") - public Object dirEntryGetPath(Object dirEntry, Object scandirPath, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + public Object dirEntryGetPath(Object dirEntry, Object scandirPath) { TruffleFile file = (TruffleFile) dirEntry; // Given that scandirPath must have been successfully channeled via opendir, we can assume // that it is a valid path - TruffleFile dir = context.getPublicTruffleFileRelaxed(pathToTruffleString(scandirPath, fromJavaStringNode)); + TruffleFile dir = context.getPublicTruffleFileRelaxed(pathToJavaString(scandirPath)); // We let the filesystem handle the proper concatenation of the two paths return dir.resolve(file.getName()).getPath(); } @@ -1878,51 +1840,40 @@ public int dirEntryGetType(Object dirEntry) { public void utimensat(int dirFd, Object path, long[] timespec, boolean followSymlinks, @Bind Node inliningTarget, @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathStr = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = resolvePath(inliningTarget, dirFd, pathStr, defaultDirFdPofile, toJavaStringNode); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); setUTimeNode.execute(inliningTarget, file, timespec, followSymlinks); } @ExportMessage public void futimens(int fd, long[] timespec, @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path); + @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + TruffleFile file = getTruffleFile(getFilePath(fd)); setUTimeNode.execute(inliningTarget, file, timespec, true); } @ExportMessage public void futimes(int fd, Timeval[] timeval, @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path); + @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + TruffleFile file = getTruffleFile(getFilePath(fd)); setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); } @ExportMessage public void lutimes(Object filename, Timeval[] timeval, @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString filenameStr = pathToTruffleString(filename, fromJavaStringNode); - TruffleFile file = getTruffleFile(filenameStr); + @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + TruffleFile file = getTruffleFile(pathToJavaString(filename)); setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), false); } @ExportMessage public void utimes(Object filename, Timeval[] timeval, @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString filenameStr = pathToTruffleString(filename, fromJavaStringNode); - TruffleFile file = getTruffleFile(filenameStr); + @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + TruffleFile file = getTruffleFile(pathToJavaString(filename)); setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); } @@ -1996,16 +1947,13 @@ private static FileTime toFileTime(long seconds, long nanos) { @ExportMessage public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); + TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToJavaString(newPath), defaultDirFdPofile); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); + TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToJavaString(oldPath), defaultDirFdPofile); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { throw posixException(OSErrorEnum.fromException(e)); @@ -2015,16 +1963,13 @@ public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, @ExportMessage public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); + TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToJavaString(newPath), defaultDirFdPofile); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); + TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToJavaString(oldPath), defaultDirFdPofile); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { throw posixException(OSErrorEnum.fromException(e)); @@ -2035,17 +1980,14 @@ public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, @Bind Node inliningTarget, @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws UnsupportedPosixFeatureException { + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws UnsupportedPosixFeatureException { if (effectiveIds) { errBranch.enter(inliningTarget); throw createUnsupportedFeature("faccess with effective user IDs"); } - TruffleFile file = null; + TruffleFile file; try { - file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); + file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); } catch (PosixException e) { // When the dirFd is invalid descriptor, we just return false, like the real faccessat return false; @@ -2079,11 +2021,8 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, @ExportMessage public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); Set permissions = modeToPosixFilePermissions(mode); if (getPythonOS() == PLATFORM_WIN32) { // cmp cpython's simple chmod implementation @@ -2101,9 +2040,8 @@ public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, } @ExportMessage - public void fchmod(int fd, int mode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); + public void fchmod(int fd, int mode) throws PosixException { + String path = getFilePath(fd); if (path == null) { throw posixException(OSErrorEnum.EBADF); } @@ -2129,11 +2067,8 @@ public void fchown(int fd, long owner, long group) throws PosixException { @ExportMessage public Object readlinkat(int dirFd, Object path, @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, toJavaStringNode); + @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); try { TruffleFile canonicalFile = file.getCanonicalFile(); if (file.equals(canonicalFile)) { @@ -2509,8 +2444,7 @@ public RusageResult getrusage(int who) throws PosixException { ru_stime = Math.max(0, (threadMXBean.getThreadCpuTime(id) - threadMXBean.getThreadUserTime(id))) / 1000000000.0; } - if (threadMXBean instanceof com.sun.management.ThreadMXBean) { - com.sun.management.ThreadMXBean thMxBean = (com.sun.management.ThreadMXBean) threadMXBean; + if (threadMXBean instanceof com.sun.management.ThreadMXBean thMxBean) { ru_maxrss = thMxBean.getThreadAllocatedBytes(id); } else { ru_maxrss = runtime.maxMemory(); @@ -2588,8 +2522,7 @@ public void unsetenv(Object name) { @ExportMessage @TruffleBoundary public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { if (PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { throw new UnsupportedPosixFeatureException("forkExec was excluded"); } @@ -2601,7 +2534,7 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en // compatibility warning // TODO do we need to do this check (and the isExecutable() check later)? - TruffleFile cwdFile = cwd == null ? context.getEnv().getCurrentWorkingDirectory() : getTruffleFile(pathToTruffleString(cwd, fromJavaStringNode)); + TruffleFile cwdFile = cwd == null ? context.getEnv().getCurrentWorkingDirectory() : getTruffleFile(pathToJavaString(cwd)); if (!cwdFile.exists()) { throw posixException(OSErrorEnum.ENOENT); } @@ -2972,8 +2905,7 @@ public SeekableByteChannel truncate(long size) throws IOException { @SuppressWarnings("static-method") final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @SuppressWarnings("unused") Object tagname, @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile isAnonymousProfile, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { + @Shared("defaultDirProfile") @Cached InlinedConditionProfile isAnonymousProfile) throws PosixException { if (prot == PROT_NONE.value) { return MMapHandle.NONE; } @@ -2987,8 +2919,7 @@ final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @Su } } - TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path); + TruffleFile file = getTruffleFile(getFilePath(fd)); Set options = mmapProtToOptions(prot); // we create a new channel, the file may be closed but the mmap object should still work @@ -3161,13 +3092,13 @@ private static ByteBuffer allocateByteBuffer(int n) { } @TruffleBoundary(allowInlining = true) - protected static void getByteBufferArray(ByteBuffer src, byte[] dst, int readSize) { + private static void getByteBufferArray(ByteBuffer src, byte[] dst, int readSize) { src.flip(); src.get(dst, 0, readSize); } @TruffleBoundary(allowInlining = true) - protected static byte getByte(ByteBuffer src) { + private static byte getByte(ByteBuffer src) { src.flip(); return src.get(); } @@ -3309,8 +3240,7 @@ public int ioctlInt(int fd, long request, int arg) throws PosixException { } @ExportMessage - public int socket(int domain, int type, int protocol, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public int socket(int domain, int type, int protocol) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { throw new UnsupportedPosixFeatureException("socket was excluded"); } @@ -3329,7 +3259,7 @@ public int socket(int domain, int type, int protocol, } return assignFileDescriptor(socket); } catch (Exception e) { - throw posixException(e, eqNode); + throw posixException(e); } } @@ -3348,7 +3278,7 @@ public AcceptResult accept(int sockfd) throws PosixException { c = null; return new AcceptResult(fd, addr); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } finally { if (c != null) { try { @@ -3374,7 +3304,7 @@ public void bind(int sockfd, UniversalSockAddr addr) throws PosixException { try { socket.bind(usa.socketAddress); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3392,7 +3322,7 @@ public void connect(int sockfd, UniversalSockAddr addr) throws PosixException { try { socket.connect(usa.socketAddress); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3406,7 +3336,7 @@ public void listen(int sockfd, int backlog) throws PosixException { try { socket.listen(backlog); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3424,7 +3354,7 @@ public UniversalSockAddr getpeername(int sockfd) throws PosixException { } return EmulatedUniversalSockAddrImpl.fromSocketAddress(socket.family, sa); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3443,7 +3373,7 @@ public UniversalSockAddr getsockname(int sockfd) throws PosixException { } return EmulatedUniversalSockAddrImpl.fromSocketAddress(socket.family, sa); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3458,7 +3388,7 @@ public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws P try { return socket.send(bb, flags); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3477,7 +3407,7 @@ public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, Univer try { return socket.sendto(bb, flags, usa.socketAddress); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3492,7 +3422,7 @@ public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws P try { return socket.recv(bb, flags); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3508,7 +3438,7 @@ public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int SocketAddress sa = socket.recvfrom(bb, flags); return new RecvfromResult(bb.position(), EmulatedUniversalSockAddrImpl.fromSocketAddress(socket.family, sa)); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3519,7 +3449,7 @@ public void shutdown(int sockfd, int how) throws PosixException { try { socket.shutdown(how); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3566,7 +3496,7 @@ public int getsockopt(int sockfd, int level, int optname, byte[] optval, int opt } catch (UnsupportedOperationException e) { throw posixException(OSErrorEnum.ENOPROTOOPT); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3608,7 +3538,7 @@ public void setsockopt(int sockfd, int level, int optname, byte[] optval, int op } catch (UnsupportedOperationException e) { throw posixException(OSErrorEnum.ENOPROTOOPT); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3658,18 +3588,15 @@ public int inet_aton(Object src) throws InvalidAddressException { throw new InvalidAddressException(); } String[] parts = s.split("\\."); - switch (parts.length) { - case 1: - return parseUnsigned(parts[0], 0xFFFFFFFFL); - case 2: - return (parseUnsigned(parts[0], 0xFF) << 24) | parseUnsigned(parts[1], 0xFFFFFF); - case 3: - return (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | parseUnsigned(parts[2], 0xFFFF); - case 4: - return (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | (parseUnsigned(parts[2], 0xFF) << 8) | parseUnsigned(parts[3], 0xFF); - default: - throw new InvalidAddressException(); - } + return switch (parts.length) { + case 1 -> parseUnsigned(parts[0], 0xFFFFFFFFL); + case 2 -> (parseUnsigned(parts[0], 0xFF) << 24) | parseUnsigned(parts[1], 0xFFFFFF); + case 3 -> + (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | parseUnsigned(parts[2], 0xFFFF); + case 4 -> + (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | (parseUnsigned(parts[2], 0xFF) << 8) | parseUnsigned(parts[3], 0xFF); + default -> throw new InvalidAddressException(); + }; } @ExportMessage @@ -4023,8 +3950,7 @@ Inet6SockAddr asInet6SockAddr() { throw new IllegalArgumentException("Only AF_INET6 socket address can be converted to Inet6SockAddr"); } InetAddress sa = socketAddress.getAddress(); - if (sa instanceof Inet6Address) { - Inet6Address a = (Inet6Address) sa; + if (sa instanceof Inet6Address a) { return new Inet6SockAddr(socketAddress.getPort(), a.getAddress(), 0, a.getScopeId()); } // IPv4 mapped to IPv6 @@ -4793,7 +4719,7 @@ static PosixException posixException(OSErrorEnum osError) throws PosixException throw new PosixErrnoException(osError.getNumber(), osError.getMessage()); } - private static PosixException posixException(Exception e, TruffleString.EqualNode eqNode) throws PosixException { + private static PosixException posixException(Exception e) throws PosixException { if (e instanceof PosixException) { throw (PosixException) e; } @@ -4815,9 +4741,9 @@ static long fileTimeNanoSecondsPart(FileTime t) { return t.toInstant().getNano(); } - private TruffleFile getTruffleFile(TruffleString path) throws PosixException { + private TruffleFile getTruffleFile(String path) throws PosixException { try { - return context.getPublicTruffleFileRelaxed(path.toJavaStringUncached(), PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); + return context.getPublicTruffleFileRelaxed(path, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); } catch (Exception ex) { // So far it seem that this can only be InvalidPath exception from Java NIO, but we stay // on the safe side and catch generic exception @@ -4829,8 +4755,7 @@ private TruffleFile getTruffleFile(TruffleString path) throws PosixException { * Resolves the path relative to the directory given as file descriptor. Honors the * {@link PosixConstants#AT_FDCWD}. */ - private TruffleFile resolvePath(Node inliningTarget, int dirFd, TruffleString pathname, InlinedConditionProfile defaultDirFdPofile, - ToJavaStringNode toJavaStringNode) + private TruffleFile resolvePath(Node inliningTarget, int dirFd, String pathname, InlinedConditionProfile defaultDirFdPofile) throws PosixException { if (defaultDirFdPofile.profile(inliningTarget, dirFd == AT_FDCWD.value)) { return getTruffleFile(pathname); @@ -4841,27 +4766,22 @@ private TruffleFile resolvePath(Node inliningTarget, int dirFd, TruffleString pa // any error if the file path is already absolute return file; } - TruffleString dirPath = getFilePathOrDefault(dirFd, null); + String dirPath = getFilePathOrDefault(dirFd); if (dirPath == null) { throw posixException(OSErrorEnum.EBADF); } TruffleFile dir = getTruffleFile(dirPath); - return dir.resolve(toJavaStringNode.execute(pathname)); + return dir.resolve(pathname); } } - private static TruffleString pathToTruffleString(Object path, TruffleString.FromJavaStringNode fromJavaStringNode) { - return fromJavaStringNode.execute((String) path, TS_ENCODING); - } - private static String pathToJavaString(Object path) { return (String) path; } @TruffleBoundary(allowInlining = true) - private TruffleString getFilePathOrDefault(int fd, String defaultValue) { - String path = filePaths.getOrDefault(fd, defaultValue); - return path != null ? toTruffleStringUncached(path) : null; + private String getFilePathOrDefault(int fd) { + return filePaths.getOrDefault(fd, null); } @TruffleBoundary(allowInlining = true) @@ -4951,9 +4871,4 @@ public static void compatibilityIgnored(String fmt, Object... args) { private static String getIgnoredMessage(String fmt, Object[] args) { return "Ignored: " + String.format(fmt, args); } - - private TruffleString getFilePath(int fd, TruffleString.FromJavaStringNode fromJavaStringNode) { - String path = getFilePath(fd); - return path != null ? fromJavaStringNode.execute(path, TS_ENCODING) : null; - } } From b4708126ba81e9c160a3f62dfb5d4e25a88ee0fc Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 11:08:41 +0200 Subject: [PATCH 021/129] Remove InlinedConditionProfile from EmulatedPosixSupport.resolvePath (cherry picked from commit 94bcbbd9973935f6c9d68f057af376a16ad4004c) --- .../python/runtime/EmulatedPosixSupport.java | 101 ++++++++---------- 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 1d9ce9ea7b..1f8d2dd6f8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -457,9 +457,8 @@ public int closeMessage(int fd) throws PosixException { @SuppressWarnings({"unused", "static-method"}) public int openat(int dirFd, Object path, int flags, int mode, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); Set options = flagsToOptions(flags); FileAttribute> attributes = modeToAttributes(mode & ~currentUmask); try { @@ -1167,9 +1166,8 @@ public long sysconf(int name) throws PosixException { @ExportMessage public long[] fstatat(int dirFd, Object path, boolean followSymlinks, @Bind Node inliningTarget, - @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile f = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + @Exclusive @Cached InlinedBranchProfile errorBranch) throws PosixException { + TruffleFile f = resolvePath(dirFd, pathToJavaString(path)); LinkOption[] linkOptions = getLinkOptions(followSymlinks); try { return fstat(f, linkOptions); @@ -1553,9 +1551,8 @@ private static String getHostName(boolean withoutSocket) { @ExportMessage public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean rmdir, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile f = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + TruffleFile f = resolvePath(dirFd, pathToJavaString(path)); if (f.exists(LinkOption.NOFOLLOW_LINKS)) { // we cannot check this if the file does not exist boolean isDirectory = f.isDirectory(LinkOption.NOFOLLOW_LINKS); @@ -1575,10 +1572,9 @@ public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean @ExportMessage public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile srcFile = resolvePath(inliningTarget, oldFdDir, pathToJavaString(oldPath), defaultDirFdPofile); - TruffleFile dstFile = resolvePath(inliningTarget, newFdDir, pathToJavaString(newPath), defaultDirFdPofile); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + TruffleFile srcFile = resolvePath(oldFdDir, pathToJavaString(oldPath)); + TruffleFile dstFile = resolvePath(newFdDir, pathToJavaString(newPath)); try { if ((flags & PosixConstants.AT_SYMLINK_FOLLOW.value) != 0) { dstFile = dstFile.getCanonicalFile(); @@ -1593,9 +1589,8 @@ public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, i @ExportMessage public void symlinkat(Object target, int linkDirFd, Object link, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile linkFile = resolvePath(inliningTarget, linkDirFd, pathToJavaString(link), defaultDirFdPofile); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + TruffleFile linkFile = resolvePath(linkDirFd, pathToJavaString(link)); TruffleFile targetFile = getTruffleFile(pathToJavaString(target)); try { linkFile.createSymbolicLink(targetFile); @@ -1608,9 +1603,8 @@ public void symlinkat(Object target, int linkDirFd, Object link, @ExportMessage public void mkdirat(int dirFd, Object path, int mode, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile linkFile = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + TruffleFile linkFile = resolvePath(dirFd, pathToJavaString(path)); try { linkFile.createDirectory(); } catch (Exception e) { @@ -1839,9 +1833,8 @@ public int dirEntryGetType(Object dirEntry) { @ExportMessage public void utimensat(int dirFd, Object path, long[] timespec, boolean followSymlinks, @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); setUTimeNode.execute(inliningTarget, file, timespec, followSymlinks); } @@ -1945,15 +1938,13 @@ private static FileTime toFileTime(long seconds, long nanos) { } @ExportMessage - public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToJavaString(newPath), defaultDirFdPofile); + TruffleFile newFile = resolvePath(newDirFd, pathToJavaString(newPath)); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToJavaString(oldPath), defaultDirFdPofile); + TruffleFile oldFile = resolvePath(oldDirFd, pathToJavaString(oldPath)); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { throw posixException(OSErrorEnum.fromException(e)); @@ -1961,15 +1952,13 @@ public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, } @ExportMessage - public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToJavaString(newPath), defaultDirFdPofile); + TruffleFile newFile = resolvePath(newDirFd, pathToJavaString(newPath)); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToJavaString(oldPath), defaultDirFdPofile); + TruffleFile oldFile = resolvePath(oldDirFd, pathToJavaString(oldPath)); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { throw posixException(OSErrorEnum.fromException(e)); @@ -1979,15 +1968,14 @@ public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath @ExportMessage public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws UnsupportedPosixFeatureException { + @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws UnsupportedPosixFeatureException { if (effectiveIds) { errBranch.enter(inliningTarget); throw createUnsupportedFeature("faccess with effective user IDs"); } TruffleFile file; try { - file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + file = resolvePath(dirFd, pathToJavaString(path)); } catch (PosixException e) { // When the dirFd is invalid descriptor, we just return false, like the real faccessat return false; @@ -2019,10 +2007,8 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, } @ExportMessage - public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); Set permissions = modeToPosixFilePermissions(mode); if (getPythonOS() == PLATFORM_WIN32) { // cmp cpython's simple chmod implementation @@ -2065,10 +2051,8 @@ public void fchown(int fd, long owner, long group) throws PosixException { } @ExportMessage - public Object readlinkat(int dirFd, Object path, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToJavaString(path), defaultDirFdPofile); + public Object readlinkat(int dirFd, Object path) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); try { TruffleFile canonicalFile = file.getCanonicalFile(); if (file.equals(canonicalFile)) { @@ -4755,24 +4739,23 @@ private TruffleFile getTruffleFile(String path) throws PosixException { * Resolves the path relative to the directory given as file descriptor. Honors the * {@link PosixConstants#AT_FDCWD}. */ - private TruffleFile resolvePath(Node inliningTarget, int dirFd, String pathname, InlinedConditionProfile defaultDirFdPofile) - throws PosixException { - if (defaultDirFdPofile.profile(inliningTarget, dirFd == AT_FDCWD.value)) { + private TruffleFile resolvePath(int dirFd, String pathname) throws PosixException { + if (dirFd == AT_FDCWD.value) { return getTruffleFile(pathname); - } else { - TruffleFile file = getTruffleFile(pathname); - if (file.isAbsolute()) { - // Even if the dirFd is non-existing or otherwise wrong, we should not trigger - // any error if the file path is already absolute - return file; - } - String dirPath = getFilePathOrDefault(dirFd); - if (dirPath == null) { - throw posixException(OSErrorEnum.EBADF); - } - TruffleFile dir = getTruffleFile(dirPath); - return dir.resolve(pathname); } + + TruffleFile file = getTruffleFile(pathname); + if (file.isAbsolute()) { + // Even if the dirFd is non-existing or otherwise wrong, we should not trigger + // any error if the file path is already absolute + return file; + } + String dirPath = getFilePathOrDefault(dirFd); + if (dirPath == null) { + throw posixException(OSErrorEnum.EBADF); + } + TruffleFile dir = getTruffleFile(dirPath); + return dir.resolve(pathname); } private static String pathToJavaString(Object path) { From a72938c6ca5e476c21e4d747fe78b616fc91a636 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 11:01:37 +0200 Subject: [PATCH 022/129] Convert PosixSupportLibrary.(fstatat|fstat|statvfs|fstatvfs) to a bare Java methods (cherry picked from commit 4be2a16189b10f01e9adad1f827ea7f124826075) --- .../builtins/modules/PosixModuleBuiltins.java | 20 ++++------- .../builtins/modules/io/FileIOBuiltins.java | 4 +-- .../builtins/objects/mmap/MMapBuiltins.java | 17 +++++---- .../objects/posix/DirEntryBuiltins.java | 6 ++-- .../python/runtime/EmulatedPosixSupport.java | 27 +++++--------- .../python/runtime/LoggingPosixSupport.java | 32 ++++++++--------- .../python/runtime/NativePosixSupport.java | 12 ++++--- .../graal/python/runtime/PosixSupport.java | 19 ++++++++++ .../python/runtime/PosixSupportLibrary.java | 19 ---------- .../python/runtime/PreInitPosixSupport.java | 36 +++++++++---------- 10 files changed, 87 insertions(+), 105 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index e555fd5181..5669af2c66 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1462,11 +1462,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatPath(VirtualFrame frame, PosixPath path, int dirFd, boolean followSymlinks, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared("positive") @Cached InlinedConditionProfile positiveLongProfile, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - long[] out = posixLib.fstatat(context.getPosixSupport(), dirFd, path.value, followSymlinks); + long[] out = context.getPosixSupport().fstatat(dirFd, path.value, followSymlinks); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -1491,11 +1490,10 @@ static PTuple doStatFdWithFollowSymlinks(VirtualFrame frame, PosixFd fd, int dir static PTuple doStatFd(VirtualFrame frame, PosixFd fd, @SuppressWarnings("unused") int dirFd, @SuppressWarnings("unused") boolean followSymlinks, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared("positive") @Cached InlinedConditionProfile positiveLongProfile, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - long[] out = posixLib.fstat(context.getPosixSupport(), fd.fd); + long[] out = context.getPosixSupport().fstat(fd.fd); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd.originalObject); @@ -1522,12 +1520,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatPath(VirtualFrame frame, PosixPath path, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile positiveLongProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { // TODO we used to return all zeros when the filename was equal to sys.executable - long[] out = posixLib.fstatat(context.getPosixSupport(), dirFd, path.value, false); + long[] out = context.getPosixSupport().fstatat(dirFd, path.value, false); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -1549,13 +1546,12 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatFd(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile positiveLongProfile, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { while (true) { try { - long[] out = posixLib.fstat(context.getPosixSupport(), fd); + long[] out = context.getPosixSupport().fstat(fd); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { errorProfile.enter(inliningTarget); @@ -1591,16 +1587,15 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatvfs(VirtualFrame frame, PosixFileHandle posixFileHandle, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile posixPathProfile, @Cached InlinedConditionProfile positiveLongProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] out; try { if (posixPathProfile.profile(inliningTarget, posixFileHandle instanceof PosixPath)) { - out = posixLib.statvfs(context.getPosixSupport(), ((PosixPath) posixFileHandle).value); + out = context.getPosixSupport().statvfs(((PosixPath) posixFileHandle).value); } else { - out = posixLib.fstatvfs(context.getPosixSupport(), ((PosixFd) posixFileHandle).fd); + out = context.getPosixSupport().fstatvfs(((PosixFd) posixFileHandle).fd); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, posixFileHandle.originalObject); @@ -1618,12 +1613,11 @@ abstract static class FStatvfsNode extends PythonUnaryClinicBuiltinNode { static PTuple doStatvfs(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile positiveLongProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] out; try { - out = posixLib.fstatvfs(context.getPosixSupport(), fd); + out = context.getPosixSupport().fstatvfs(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index bebb280d66..4f4304c11d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -392,7 +392,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object long[] fstatResult; gil.release(true); try { - fstatResult = posixLib.fstat(context.getPosixSupport(), self.getFD()); + fstatResult = context.getPosixSupport().fstat(self.getFD()); } finally { gil.acquire(); } @@ -572,7 +572,7 @@ static Object readall(VirtualFrame frame, PFileIO self, try { PosixSupport posixSupport = PosixSupport.get(inliningTarget); long pos = posixLib.lseek(posixSupport, self.getFD(), 0L, mapPythonSeekWhenceToPosix(SEEK_CUR)); - long[] status = posixLib.fstat(posixSupport, self.getFD()); + long[] status = posixSupport.fstat(self.getFD()); long end = status[6]; // TODO: st_size if (end > 0 && end >= pos && pos >= 0 && end - pos < MAX_SIZE) { /* diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index f9f8367d5c..ddfc56fd93 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -75,8 +75,8 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.ArgumentClinic; import com.oracle.graal.python.annotations.ArgumentClinic.ClinicConversion; -import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.annotations.Slot; import com.oracle.graal.python.annotations.Slot.SlotKind; import com.oracle.graal.python.annotations.Slot.SlotSignature; @@ -215,7 +215,7 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj Object tagname, Object trackFdArg, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixSupport, + @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Exclusive @Cached CastToTruffleStringNode castTagnameNode, @@ -272,11 +272,11 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj // For file mappings we use fstat to validate the length or to initialize the length if // it is 0 meaning that we should find it out for the user long length = lengthIn; - PosixSupport posixSupport1 = PosixSupport.get(inliningTarget); + PosixSupport posixSupport = PosixSupport.get(inliningTarget); if (fd != ANONYMOUS_FD) { long[] fstatResult = null; try { - fstatResult = posixSupport.fstat(posixSupport1, fd); + fstatResult = posixSupport.fstat(fd); } catch (PosixException ignored) { } if (fstatResult != null && length == 0) { @@ -302,7 +302,7 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj // MAP_ANONYMOUS, maybe this can be detected and handled by the POSIX layer } else if (mmapArgs.trackFd()) { try { - trackedFd = posixSupport.dup(posixSupport1, fd); + trackedFd = posixSupportLib.dup(posixSupport, fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -312,11 +312,11 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj Object mmapHandle; try { - mmapHandle = posixSupport.mmap(posixSupport1, length, prot, flags, fd, offset, mmapTagname); + mmapHandle = posixSupportLib.mmap(posixSupport, length, prot, flags, fd, offset, mmapTagname); } catch (PosixException e) { if (trackedFd != ANONYMOUS_FD) { try { - posixSupport.close(posixSupport1, trackedFd); + posixSupportLib.close(posixSupport, trackedFd); } catch (PosixException ignored) { } } @@ -650,7 +650,6 @@ abstract static class SizeNode extends PythonBuiltinNode { static long size(VirtualFrame frame, PMMap self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupport, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { if (self.isClosed()) { @@ -660,7 +659,7 @@ static long size(VirtualFrame frame, PMMap self, return self.getLength(); } try { - return posixSupport.fstat(context.getPosixSupport(), self.getFd())[ST_SIZE]; + return context.getPosixSupport().fstat(self.getFd())[ST_SIZE]; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java index 1560852b83..d471c9bbf3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java @@ -257,7 +257,6 @@ static PTuple cachedLStat(PDirEntry self, boolean followSymlinks, boolean catchN static PTuple uncachedStatWithSymlink(VirtualFrame frame, PDirEntry self, boolean followSymlinks, boolean catchNoent, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @SuppressWarnings("unused") @Cached IsSymlinkNode isSymlinkNode, @SuppressWarnings("unused") @Bind("isSymlinkNode.executeBoolean(frame, self)") boolean isSymlink, @Shared("cachedPosixPathNode") @Cached CachedPosixPathNode cachedPosixPathNode, @@ -265,14 +264,13 @@ static PTuple uncachedStatWithSymlink(VirtualFrame frame, PDirEntry self, boolea @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // There are two caches - one for `follow_symlinks=True` and the other for // 'follow_symlinks=False`. They are different only when the dir entry is a symlink. - return uncachedLStatWithSymlink(frame, self, followSymlinks, catchNoent, inliningTarget, context, posixLib, cachedPosixPathNode, positiveLongProfile, constructAndRaiseNode); + return uncachedLStatWithSymlink(frame, self, followSymlinks, catchNoent, inliningTarget, context, cachedPosixPathNode, positiveLongProfile, constructAndRaiseNode); } @Specialization(guards = {"!followSymlinks", "self.lstatCache == null"}) static PTuple uncachedLStatWithSymlink(VirtualFrame frame, PDirEntry self, boolean followSymlinks, boolean catchNoent, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared("cachedPosixPathNode") @Cached CachedPosixPathNode cachedPosixPathNode, @Shared("positiveLongProfile") @Cached InlinedConditionProfile positiveLongProfile, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -280,7 +278,7 @@ static PTuple uncachedLStatWithSymlink(VirtualFrame frame, PDirEntry self, boole int dirFd = self.scandirPath instanceof PosixFd ? ((PosixFd) self.scandirPath).fd : AT_FDCWD.value; PosixPath posixPath = cachedPosixPathNode.execute(frame, inliningTarget, self); try { - long[] rawStat = posixLib.fstatat(context.getPosixSupport(), dirFd, posixPath.value, followSymlinks); + long[] rawStat = context.getPosixSupport().fstatat(dirFd, posixPath.value, followSymlinks); res = PosixModuleBuiltins.createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, rawStat); } catch (PosixException e) { if (catchNoent && e.hasErrno(OSErrorEnum.ENOENT)) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 1f8d2dd6f8..4a841d2bcb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -1163,33 +1163,26 @@ public long sysconf(int name) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage - public long[] fstatat(int dirFd, Object path, boolean followSymlinks, - @Bind Node inliningTarget, - @Exclusive @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public long[] fstatat(int dirFd, Object path, boolean followSymlinks) throws PosixException { TruffleFile f = resolvePath(dirFd, pathToJavaString(path)); LinkOption[] linkOptions = getLinkOptions(followSymlinks); try { return fstat(f, linkOptions); } catch (Exception e) { - errorBranch.enter(inliningTarget); ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } - @ExportMessage - public long[] fstat(int fd, - @Bind Node inliningTarget, - @Exclusive @Cached InlinedBranchProfile nullPathProfile, - @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile) throws PosixException { + @Override + @TruffleBoundary + public long[] fstat(int fd) throws PosixException { String path = getFilePath(fd); if (path == null) { - nullPathProfile.enter(inliningTarget); Channel fileChannel = getFileChannel(fd); if (fileChannel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } return fstatWithoutPath(fileChannel); @@ -1198,15 +1191,13 @@ public long[] fstat(int fd, try { return fstat(f, new LinkOption[0]); } catch (Exception e) { - errorBranch.enter(inliningTarget); ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") public long[] statvfs(Object path) throws PosixException { try { Env env = PythonContext.get(null).getEnv(); @@ -1243,8 +1234,8 @@ public long[] statvfs(Object path) throws PosixException { } } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public long[] fstatvfs(int fd) throws PosixException { String path = getFilePath(fd); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index a517e7aeb5..339a26efec 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -447,45 +447,45 @@ final long sysconf(int name, } } - @ExportMessage - final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { logEnter("fstatAt", "%d, %s, %b", dirFd, pathname, followSymlinks); try { - return logExit("fstatAt", "%s", lib.fstatat(delegate, dirFd, pathname, followSymlinks)); + return logExit("fstatAt", "%s", delegate.fstatat(dirFd, pathname, followSymlinks)); } catch (PosixException e) { throw logException("fstatAt", e); } } - @ExportMessage - final long[] fstat(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstat(int fd) throws PosixException { logEnter("fstat", "%d", fd); try { - return logExit("fstat", "%s", lib.fstat(delegate, fd)); + return logExit("fstat", "%s", delegate.fstat(fd)); } catch (PosixException e) { throw logException("fstat", e); } } - @ExportMessage - final long[] statvfs(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] statvfs(Object path) throws PosixException { logEnter("statvfs", "%s", path); try { - return logExit("statvfs", "%s", lib.statvfs(delegate, path)); + return logExit("statvfs", "%s", delegate.statvfs(path)); } catch (PosixException e) { throw logException("statvfs", e); } } - @ExportMessage - final long[] fstatvfs(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstatvfs(int fd) throws PosixException { logEnter("fstatvfs", "%d", fd); try { - return logExit("fstatvfs", "%s", lib.fstatvfs(delegate, fd)); + return logExit("fstatvfs", "%s", delegate.fstatvfs(fd)); } catch (PosixException e) { throw logException("fstatvfs", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index d2c64b3f36..d3d86d9acb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1104,7 +1104,8 @@ public long sysconf(int name) throws PosixException { return result; } - @ExportMessage + @Override + @TruffleBoundary public long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { long[] out = new long[13]; long nativeOut = NULLPTR; @@ -1124,7 +1125,8 @@ public long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws } } - @ExportMessage + @Override + @TruffleBoundary public long[] fstat(int fd) throws PosixException { long[] out = new long[13]; long nativeOut = NativeMemory.mallocLongArray(out.length); @@ -1140,7 +1142,8 @@ public long[] fstat(int fd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long[] statvfs(Object path) throws PosixException { long[] out = new long[11]; long nativeOut = NULLPTR; @@ -1160,7 +1163,8 @@ public long[] statvfs(Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long[] fstatvfs(int fd) throws PosixException { long[] out = new long[11]; long nativeOut = NativeMemory.mallocLongArray(out.length); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index b8b22278ac..fe58d21ba2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -47,6 +47,8 @@ public abstract class PosixSupport { + public static final int ST_MODE = 0; + public static abstract class Path { } @@ -66,4 +68,21 @@ public static PosixSupport get(Node node) { public abstract int getWindowsConsoleType(int fd); public abstract long writeWindowsConsole(int fd, Buffer data) throws PosixException; + + // see stat_struct_to_longs in posix.c for the layout of the array + public abstract long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException; + + /** + * Performs operation of fstat(fd). + * + * @param fd the file descriptor + * @return see {@code stat_struct_to_longs} in posix.c for the layout of the array. There are + * constants for some of the indices, e.g., {@link #ST_MODE}. + * @throws PosixException if an error occurs + */ + public abstract long[] fstat(int fd) throws PosixException; + + public abstract long[] statvfs(Object path) throws PosixException; + + public abstract long[] fstatvfs(int fd) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index fd740e338d..9295bf6686 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -77,7 +77,6 @@ public abstract class PosixSupportLibrary extends Library { // Constants for accessing the fields of the fstat result: // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants - public static final int ST_MODE = 0; public static final int ST_SIZE = 6; public abstract TruffleString getBackend(Object recevier); @@ -134,24 +133,6 @@ public abstract class PosixSupportLibrary extends Library { public abstract long sysconf(Object receiver, int name) throws PosixException; - // see stat_struct_to_longs in posix.c for the layout of the array - public abstract long[] fstatat(Object receiver, int dirFd, Object pathname, boolean followSymlinks) throws PosixException; - - /** - * Performs operation of fstat(fd). - * - * @param receiver the receiver of the message - * @param fd the file descriptor - * @return see {@code stat_struct_to_longs} in posix.c for the layout of the array. There are - * constants for some of the indices, e.g., {@link #ST_MODE}. - * @throws PosixException if an error occurs - */ - public abstract long[] fstat(Object receiver, int fd) throws PosixException; - - public abstract long[] statvfs(Object receiver, Object path) throws PosixException; - - public abstract long[] fstatvfs(Object receiver, int fd) throws PosixException; - public abstract Object[] uname(Object receiver) throws PosixException; public record WindowsVersion(int major, int minor, int build, int platform, TruffleString servicePack, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 43970a1ad5..ca4d946474 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -377,40 +377,36 @@ final long sysconf(int name, return nativeLib.sysconf(nativePosixSupport, name); } - @ExportMessage - final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().fstatat(emulatedPosixSupport, dirFd, pathname, followSymlinks); + return emulatedPosixSupport.fstatat(dirFd, pathname, followSymlinks); } - return nativeLib.fstatat(nativePosixSupport, dirFd, pathname, followSymlinks); + return nativePosixSupport.fstatat(dirFd, pathname, followSymlinks); } - @ExportMessage - final long[] fstat(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final long[] fstat(int fd) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().fstat(emulatedPosixSupport, fd); + return emulatedPosixSupport.fstat(fd); } - return nativeLib.fstat(nativePosixSupport, fd); + return nativePosixSupport.fstat(fd); } - @ExportMessage - final long[] statvfs(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final long[] statvfs(Object path) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().statvfs(emulatedPosixSupport, path); + return emulatedPosixSupport.statvfs(path); } - return nativeLib.statvfs(nativePosixSupport, path); + return nativePosixSupport.statvfs(path); } - @ExportMessage - final long[] fstatvfs(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final long[] fstatvfs(int fd) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().fstatvfs(emulatedPosixSupport, fd); + return emulatedPosixSupport.fstatvfs(fd); } - return nativeLib.fstatvfs(nativePosixSupport, fd); + return nativePosixSupport.fstatvfs(fd); } @ExportMessage From eea387f2188116ae459caf182825f8fc8d8e03f2 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 12:19:31 +0200 Subject: [PATCH 023/129] Convert PosixSupportLibrary descriptor inheritance methods (cherry picked from commit 4182cb848fa8129c1184bd32548f92d25113f6f7) --- .../builtins/modules/PosixModuleBuiltins.java | 19 +++++------- .../modules/SocketModuleBuiltins.java | 4 +-- .../builtins/modules/io/FileIOBuiltins.java | 2 +- .../builtins/objects/mmap/MMapBuiltins.java | 2 +- .../objects/socket/SocketBuiltins.java | 4 +-- .../python/runtime/EmulatedPosixSupport.java | 9 ++---- .../python/runtime/LoggingPosixSupport.java | 28 ++++++++--------- .../python/runtime/NativePosixSupport.java | 8 ++--- .../graal/python/runtime/PosixSupport.java | 8 +++++ .../python/runtime/PosixSupportLibrary.java | 8 ----- .../python/runtime/PreInitPosixSupport.java | 30 ++++++++----------- 11 files changed, 54 insertions(+), 68 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 5669af2c66..1603efb840 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -874,8 +874,8 @@ static Object openpty(VirtualFrame frame, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { OpenPtyResult result = posixLib.openpty(context.getPosixSupport()); - posixLib.setInheritable(context.getPosixSupport(), result.masterFd(), false); - posixLib.setInheritable(context.getPosixSupport(), result.slaveFd(), false); + context.getPosixSupport().setInheritable(result.masterFd(), false); + context.getPosixSupport().setInheritable(result.slaveFd(), false); return PFactory.createTuple(context.getLanguage(inliningTarget), new int[]{result.masterFd(), result.slaveFd()}); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -1090,10 +1090,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static int dup(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.dup(context.getPosixSupport(), fd); + return context.getPosixSupport().dup(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1126,7 +1125,7 @@ static int dup2(VirtualFrame frame, int fd, int fd2, boolean inheritable, } try { - return posixLib.dup2(context.getPosixSupport(), fd, fd2, inheritable); + return context.getPosixSupport().dup2(fd, fd2, inheritable); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1147,10 +1146,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static boolean getInheritable(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getInheritable(context.getPosixSupport(), fd); + return context.getPosixSupport().getInheritable(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1172,11 +1170,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone setInheritable(VirtualFrame frame, int fd, int inheritable, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { // not sure why inheritable is not a boolean, but that is how they do it in CPython - posixLib.setInheritable(context.getPosixSupport(), fd, inheritable != 0); + context.getPosixSupport().setInheritable(fd, inheritable != 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -2054,10 +2051,10 @@ private static Object[] listToArray(List list) { } } - static Object dupAndFdopendir(VirtualFrame frame, Node inliningTarget, PosixSupportLibrary posixLib, Object posixSupport, PosixFd fd, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { + static Object dupAndFdopendir(VirtualFrame frame, Node inliningTarget, PosixSupportLibrary posixLib, PosixSupport posixSupport, PosixFd fd, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int dupFd = -1; try { - dupFd = posixLib.dup(posixSupport, fd.fd); + dupFd = posixSupport.dup(fd.fd); // when fdopenddir succeeds, we are no longer responsible for closing dupFd return posixLib.fdopendir(posixSupport, dupFd); } catch (PosixException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index 2d5d882fdd..f9817b19a7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -790,9 +790,9 @@ static Object close(VirtualFrame frame, Object fdObj, try { gil.release(true); try { - int dup = posixLib.dup(context.getPosixSupport(), fd); + int dup = context.getPosixSupport().dup(fd); try { - posixLib.setInheritable(context.getPosixSupport(), dup, false); + context.getPosixSupport().setInheritable(dup, false); } catch (PosixException e1) { try { posixLib.close(context.getPosixSupport(), dup); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index 4f4304c11d..1d53de6444 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -380,7 +380,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object } } try { - posixLib.setInheritable(context.getPosixSupport(), self.getFD(), false); + context.getPosixSupport().setInheritable(self.getFD(), false); } catch (PosixException e) { exceptionProfile1.enter(inliningTarget); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index ddfc56fd93..f6f1b26305 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -302,7 +302,7 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj // MAP_ANONYMOUS, maybe this can be detected and handled by the POSIX layer } else if (mmapArgs.trackFd()) { try { - trackedFd = posixSupportLib.dup(posixSupport, fd); + trackedFd = posixSupport.dup(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index e80d199a7b..a8116e86cf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -201,7 +201,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i gil.acquire(); } try { - posixLib.setInheritable(context.getPosixSupport(), fd, false); + context.getPosixSupport().setInheritable(fd, false); sockInit(context, posixLib, self, fd, family, type, proto); } catch (Exception e) { // If we failed before giving the fd to python-land, close it @@ -326,7 +326,7 @@ static Object accept(VirtualFrame frame, PSocket self, false, false); try { Object pythonAddr = makeSockAddrNode.execute(frame, inliningTarget, acceptResult.sockAddr); - posixLib.setInheritable(posixSupport, acceptResult.socketFd, false); + posixSupport.setInheritable(acceptResult.socketFd, false); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{acceptResult.socketFd, pythonAddr}); } catch (Exception e) { // If we failed before giving the fd to python-land, close it diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 4a841d2bcb..6fafb3712a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -556,13 +556,12 @@ private static Buffer readBytesFromChannel(ReadableByteChannel channel, long siz } @Override - @ExportMessage public int dup(int fd) { // TODO: will disappear once the super class is merged with this class return super.dup(fd); } - @ExportMessage + @Override public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable) throws PosixException { // TODO: will merge with super.dup2 once the super class is merged with this class try { @@ -572,15 +571,13 @@ public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable } } - @ExportMessage - @SuppressWarnings("static-method") + @Override public boolean getInheritable(int fd) { compatibilityIgnored("getting inheritable for file descriptor %d in POSIX emulation layer (not supported, always returns false)", fd); return false; } - @ExportMessage - @SuppressWarnings("static-method") + @Override public void setInheritable(int fd, boolean inheritable) { compatibilityIgnored("setting inheritable '%b' for file descriptor %d in POSIX emulation layer (not supported)", inheritable, fd); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 339a26efec..2352e0d605 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -214,45 +214,41 @@ public final long writeWindowsConsole(int fd, Buffer data) throws PosixException } } - @ExportMessage - final int dup(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int dup(int fd) throws PosixException { logEnter("dup", "%d", fd); try { - return logExit("dup", "%d", lib.dup(delegate, fd)); + return logExit("dup", "%d", delegate.dup(fd)); } catch (PosixException e) { throw logException("dup", e); } } - @ExportMessage - final int dup2(int fd, int fd2, boolean inheritable, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int dup2(int fd, int fd2, boolean inheritable) throws PosixException { logEnter("dup2", "%d, %d, %b", fd, fd2, inheritable); try { - return logExit("dup2", "%d", lib.dup2(delegate, fd, fd2, inheritable)); + return logExit("dup2", "%d", delegate.dup2(fd, fd2, inheritable)); } catch (PosixException e) { throw logException("dup2", e); } } - @ExportMessage - final boolean getInheritable(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final boolean getInheritable(int fd) throws PosixException { logEnter("getInheritable", "%d", fd); try { - return logExit("getInheritable", "%b", lib.getInheritable(delegate, fd)); + return logExit("getInheritable", "%b", delegate.getInheritable(fd)); } catch (PosixException e) { throw logException("getInheritable", e); } } - @ExportMessage - final void setInheritable(int fd, boolean inheritable, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void setInheritable(int fd, boolean inheritable) throws PosixException { logEnter("setInheritable", "%d, %b", fd, inheritable); try { - lib.setInheritable(delegate, fd, inheritable); + delegate.setInheritable(fd, inheritable); } catch (PosixException e) { throw logException("setInheritable", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index d3d86d9acb..2219163cbd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -824,7 +824,7 @@ public long writeWindowsConsole(int fd, Buffer data) throws PosixException { } } - @ExportMessage + @Override public int dup(int fd) throws PosixException { int newFd = posixNativeFunctionInvoker.call_dup(fd); if (newFd < 0) { @@ -833,7 +833,7 @@ public int dup(int fd) throws PosixException { return newFd; } - @ExportMessage + @Override public int dup2(int fd, int fd2, boolean inheritable) throws PosixException { int newFd = posixNativeFunctionInvoker.call_dup2(fd, fd2, inheritable ? 1 : 0); if (newFd < 0) { @@ -842,7 +842,7 @@ public int dup2(int fd, int fd2, boolean inheritable) throws PosixException { return newFd; } - @ExportMessage + @Override public boolean getInheritable(int fd) throws PosixException { int result = posixNativeFunctionInvoker.get_inheritable(fd); if (result < 0) { @@ -851,7 +851,7 @@ public boolean getInheritable(int fd) throws PosixException { return result != 0; } - @ExportMessage + @Override public void setInheritable(int fd, boolean inheritable) throws PosixException { if (posixNativeFunctionInvoker.set_inheritable(fd, inheritable ? 1 : 0) < 0) { throw getErrnoAndThrowPosixException(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index fe58d21ba2..db97d8161e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -69,6 +69,14 @@ public static PosixSupport get(Node node) { public abstract long writeWindowsConsole(int fd, Buffer data) throws PosixException; + public abstract int dup(int fd) throws PosixException; + + public abstract int dup2(int fd, int fd2, boolean inheritable) throws PosixException; + + public abstract boolean getInheritable(int fd) throws PosixException; + + public abstract void setInheritable(int fd, boolean inheritable) throws PosixException; + // see stat_struct_to_longs in posix.c for the layout of the array public abstract long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 9295bf6686..f8a7e66b42 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -91,14 +91,6 @@ public abstract class PosixSupportLibrary extends Library { public abstract int close(Object receiver, int fd) throws PosixException; - public abstract int dup(Object receiver, int fd) throws PosixException; - - public abstract int dup2(Object receiver, int fd, int fd2, boolean inheritable) throws PosixException; - - public abstract boolean getInheritable(Object receiver, int fd) throws PosixException; - - public abstract void setInheritable(Object receiver, int fd, boolean inheritable) throws PosixException; - public abstract long getOsfHandle(Object receiver, int fd) throws PosixException; public abstract int openOsfHandle(Object receiver, long handle, int flags) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index ca4d946474..11c3728ed0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -226,35 +226,31 @@ public final long writeWindowsConsole(int fd, Buffer data) throws PosixException return nativePosixSupport.writeWindowsConsole(fd, data); } - @ExportMessage - final int dup(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int dup(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dup(nativePosixSupport, fd); + return nativePosixSupport.dup(fd); } - @ExportMessage - final int dup2(int fd, int fd2, boolean inheritable, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int dup2(int fd, int fd2, boolean inheritable) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dup2(nativePosixSupport, fd, fd2, inheritable); + return nativePosixSupport.dup2(fd, fd2, inheritable); } - @ExportMessage - final boolean getInheritable(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final boolean getInheritable(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getInheritable(nativePosixSupport, fd); + return nativePosixSupport.getInheritable(fd); } - @ExportMessage - final void setInheritable(int fd, boolean inheritable, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void setInheritable(int fd, boolean inheritable) throws PosixException { if (inPreInitialization) { - PosixSupportLibrary.getUncached().setInheritable(emulatedPosixSupport, fd, inheritable); + emulatedPosixSupport.setInheritable(fd, inheritable); return; } - nativeLib.setInheritable(nativePosixSupport, fd, inheritable); + nativePosixSupport.setInheritable(fd, inheritable); } @ExportMessage From b75b30c40d2aaa5b0d5e76d6b0b6b5e643851c03 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 12:44:26 +0200 Subject: [PATCH 024/129] Convert PosixSupportLibrary.(getBackend|strerror|getpid|umask) (cherry picked from commit bdac2d9d13614f4c415b683a5698b46224ddc760) --- .../modules/GraalPythonModuleBuiltins.java | 5 +- .../builtins/modules/PosixModuleBuiltins.java | 27 ++++----- .../modules/SignalModuleBuiltins.java | 2 +- .../modules/SocketModuleBuiltins.java | 2 +- .../cext/PythonCextObjectBuiltins.java | 5 +- .../objects/socket/SocketBuiltins.java | 2 +- .../python/runtime/EmulatedPosixSupport.java | 57 ++++++++++--------- .../python/runtime/LoggingPosixSupport.java | 28 ++++----- .../python/runtime/NativePosixSupport.java | 18 +++--- .../graal/python/runtime/PosixSupport.java | 9 +++ .../python/runtime/PosixSupportLibrary.java | 10 +--- .../python/runtime/PreInitPosixSupport.java | 26 ++++----- 12 files changed, 90 insertions(+), 101 deletions(-) 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 5b3e0b0016..1e852540f3 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 @@ -970,9 +970,8 @@ static boolean isAvailable(@Bind PythonContext context) { @GenerateNodeFactory public abstract static class PosixModuleBackendNode extends PythonBuiltinNode { @Specialization - TruffleString posixModuleBackend( - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getBackend(getPosixSupport()); + TruffleString posixModuleBackend() { + return getPosixSupport().getBackend(); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 1603efb840..693bc6b7ee 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -327,12 +327,11 @@ public void initialize(Python3Core core) { public void postInitialize(Python3Core core) { super.postInitialize(core); - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - Object posixSupport = core.getContext().getPosixSupport(); + PosixSupport posixSupport = core.getContext().getPosixSupport(); PythonModule posix = PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 ? core.lookupBuiltinModule(T_NT) : core.lookupBuiltinModule(T_POSIX); - if (posixLib.getBackend(posixSupport).toJavaStringUncached().equals("java")) { + if (posixSupport.getBackend().toJavaStringUncached().equals("java")) { posix.setAttribute(toTruffleStringUncached("geteuid"), PNone.NO_VALUE); posix.setAttribute(toTruffleStringUncached("getegid"), PNone.NO_VALUE); posix.setAttribute(toTruffleStringUncached("WNOHANG"), EMULATED_WNOHANG); @@ -355,7 +354,7 @@ public void patchPostInitialize(Python3Core core) { private void populateEnviron(Python3Core core) { PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - Object posixSupport = core.getContext().getPosixSupport(); + PosixSupport posixSupport = core.getContext().getPosixSupport(); PythonLanguage language = core.getLanguage(); Map getenv = core.getContext().getEnv().getEnvironment(); @@ -619,9 +618,8 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, @GenerateNodeFactory public abstract static class GetPidNode extends PythonBuiltinNode { @Specialization - static long getPid(@Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getpid(context.getPosixSupport()); + static long getPid(@Bind PythonContext context) { + return context.getPosixSupport().getpid(); } } @@ -977,14 +975,13 @@ protected ArgumentClinicProvider getArgumentClinic() { static PBytes doRead(VirtualFrame frame, int fd, int length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile1, @Cached InlinedBranchProfile errorProfile2, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (length < 0) { int error = OSErrorEnum.EINVAL.getNumber(); - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, posixLib.strerror(context.getPosixSupport(), error)); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, context.getPosixSupport().strerror(error)); } try { return read(fd, length, inliningTarget, context.getPosixSupport(), errorProfile1, gil); @@ -1115,13 +1112,12 @@ protected ArgumentClinicProvider getArgumentClinic() { static int dup2(VirtualFrame frame, int fd, int fd2, boolean inheritable, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (fd < 0 || fd2 < 0) { // CPython does not set errno here and raises a 'random' OSError // (possibly with errno=0 Success) int error = OSErrorEnum.EINVAL.getNumber(); - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, posixLib.strerror(context.getPosixSupport(), error)); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, context.getPosixSupport().strerror(error)); } try { @@ -2649,10 +2645,8 @@ protected ArgumentClinicProvider getArgumentClinic() { } @Specialization - static TruffleString getStrError(int code, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.strerror(context.getPosixSupport(), code); + static TruffleString getStrError(int code, @Bind PythonContext context) { + return context.getPosixSupport().strerror(code); } } @@ -3040,10 +3034,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static int umask(VirtualFrame frame, int mask, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.umask(context.getPosixSupport(), mask); + return context.getPosixSupport().umask(mask); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java index 16dad2ca2a..b832b16b2a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java @@ -173,7 +173,7 @@ public void postInitialize(Python3Core core) { } var context = core.getContext(); - if (PosixSupportLibrary.getUncached().getBackend(context.getPosixSupport()).equalsUncached(T_JAVA, TS_ENCODING)) { + if (context.getPosixSupport().getBackend().equalsUncached(T_JAVA, TS_ENCODING)) { for (EmulatedSignal signal : EmulatedSignal.values()) { if (signalModule.getAttribute(signal.name) == PNone.NO_VALUE) { moduleData.signals.put(signal.name(), signal.number); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index f9817b19a7..f2e395e59f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -201,7 +201,7 @@ public void postInitialize(Python3Core core) { PythonModule module = core.lookupBuiltinModule(T__SOCKET); module.setModuleState(-1L); if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 || - PosixSupportLibrary.getUncached().getBackend(core.getContext().getPosixSupport()).toJavaStringUncached().equals("java")) { + core.getContext().getPosixSupport().getBackend().toJavaStringUncached().equals("java")) { module.setAttribute(toTruffleStringUncached(PosixConstants.AF_UNIX.name), PNone.NO_VALUE); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index a847405177..9faf2f1306 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -155,6 +155,7 @@ import com.oracle.graal.python.nodes.util.CastToJavaStringNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -508,8 +509,8 @@ static Object asFileDescriptor(Object obj, @Cached PyObjectAsFileDescriptor asFileDescriptorNode, @Cached PRaiseNode raiseNode) { if (!longCheckNode.execute(inliningTarget, obj)) { - Object posixSupport = PythonContext.get(inliningTarget).getPosixSupport(); - if (eqNode.execute(T_JAVA, posixLib.getBackend(posixSupport), TS_ENCODING)) { + PosixSupport posixSupport = PythonContext.get(inliningTarget).getPosixSupport(); + if (eqNode.execute(T_JAVA, posixSupport.getBackend(), TS_ENCODING)) { /* * For non Python 'int' objects, we refuse to hand out the fileno field when * using the emulated Posix backend, because it is likely a fake. diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index a8116e86cf..cfc347f164 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -455,7 +455,7 @@ static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.L p.getsockopt(s, self.getFd(), SOL_SOCKET.value, SO_ERROR.value, tmp, tmp.length); int err = PythonUtils.ARRAY_ACCESSOR.getInt(tmp, 0); if (err != 0 && err != EISCONN.getNumber()) { - throw new PosixErrnoException(err, p.strerror(s, err)); + throw new PosixErrnoException(err, ((PosixSupport) s).strerror(err)); } return null; }, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 6fafb3712a..1b975d44da 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -352,6 +352,8 @@ public final class EmulatedPosixSupport extends PosixResources { private static final TruffleString T_DEV_TTY = tsLiteral("/dev/tty"); private final ConcurrentHashMap environ = new ConcurrentHashMap<>(); + private long pid; + private boolean pidInitialized; private int currentUmask = 0022; private boolean hasDefaultUmask = true; private final boolean withoutIOSocket; @@ -380,43 +382,46 @@ public void setEnv(Env env) { if (!env.isPreInitialization()) { environ.putAll(env.getEnvironment()); } + pidInitialized = false; } - @ExportMessage - @SuppressWarnings("static-method") + @Override public TruffleString getBackend() { return T_JAVA; } - @ExportMessage - public static class Getpid { - - private static final String T_PROC_SELF_STAT = "/proc/self/stat"; - - @Specialization(rewriteOn = Exception.class) - @TruffleBoundary - static long getPid(EmulatedPosixSupport receiver) throws Exception { + @TruffleBoundary + private long determinePid() { + long pid; + try { if (ImageInfo.inImageRuntimeCode()) { - return ProcessProperties.getProcessID(); + pid = ProcessProperties.getProcessID(); + } else { + pid = ProcessHandle.current().pid(); } - TruffleFile statFile = receiver.context.getPublicTruffleFileRelaxed(T_PROC_SELF_STAT); - return Long.parseLong(new String(statFile.readAllBytes()).trim().split(" ")[0]); - } - - @Specialization(replaces = "getPid") - @TruffleBoundary - static long getPidFallback(@SuppressWarnings("unused") EmulatedPosixSupport receiver) { + } catch (Exception e) { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { + // Java 8 compatibility String info = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); - return Long.parseLong(info.split("@")[0]); + pid = Long.parseLong(info.split("@")[0]); } else { - return Long.MAX_VALUE; + pid = Long.MAX_VALUE; } } + this.pid = pid; + this.pidInitialized = true; + return pid; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + public long getpid() { + if (pidInitialized) { + return pid; + } + return determinePid(); + } + + @Override public int umask(int umask) { int prev = currentUmask; currentUmask = umask & 00777; @@ -427,14 +432,10 @@ public int umask(int umask) { return umask; } - @ExportMessage - @SuppressWarnings({"unused", "static-method"}) - public TruffleString strerror(int errorCode, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) { + @Override + public TruffleString strerror(int errorCode) { OSErrorEnum err = OSErrorEnum.fromNumber(errorCode); if (err == null) { - errorBranch.enter(inliningTarget); err = OSErrorEnum.EINVAL; } return err.getMessage(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 2352e0d605..9d0c101915 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -120,33 +120,29 @@ public void setEnv(Env env) { delegate.setEnv(env); } - @ExportMessage - final TruffleString getBackend( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + public final TruffleString getBackend() { logEnter(Level.FINEST, "getBackend", ""); - return logExit(Level.FINEST, "getBackend", "%s", lib.getBackend(delegate)); + return logExit(Level.FINEST, "getBackend", "%s", delegate.getBackend()); } - @ExportMessage - final TruffleString strerror(int errorCode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + public final TruffleString strerror(int errorCode) { logEnter(Level.FINEST, "strerror", "%d", errorCode); - return logExit(Level.FINEST, "strerror", "%s", lib.strerror(delegate, errorCode)); + return logExit(Level.FINEST, "strerror", "%s", delegate.strerror(errorCode)); } - @ExportMessage - final long getpid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + public final long getpid() { logEnter("getpid", ""); - return logExit("getpid", "%d", lib.getpid(delegate)); + return logExit("getpid", "%d", delegate.getpid()); } - @ExportMessage - final int umask(int mask, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int umask(int mask) throws PosixException { logEnter("umask", "0%o", mask); try { - return logExit("umask", "0%o", lib.umask(delegate, mask)); + return logExit("umask", "0%o", delegate.umask(mask)); } catch (PosixException e) { throw logException("umask", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 2219163cbd..193232fe24 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -715,15 +715,13 @@ public void setEnv(Env env) { } } - @ExportMessage + @Override public TruffleString getBackend() { return nativeBackend; } - @ExportMessage - public TruffleString strerror(int errorCode, - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) { + @Override + public TruffleString strerror(int errorCode) { // From man pages: The GNU C Library uses a buffer of 1024 characters for strerror(). // This buffer size therefore should be sufficient to avoid an ERANGE error when calling // strerror_r(). @@ -731,18 +729,20 @@ public TruffleString strerror(int errorCode, try { posixNativeFunctionInvoker.call_strerror(errorCode, buf, STRERROR_BUF_LENGTH); // TODO PyUnicode_DecodeLocale - return zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, buf); + TruffleString message = NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(buf); + message.toJavaStringUncached(); + return message; } finally { NativeMemory.free(buf); } } - @ExportMessage + @Override public long getpid() { return posixNativeFunctionInvoker.call_getpid(); } - @ExportMessage + @Override public int umask(int mask) { return posixNativeFunctionInvoker.call_umask(mask); } @@ -3724,7 +3724,7 @@ private PosixException newPosixException(int errno) throws PosixException { @TruffleBoundary private PosixException newPosixException(int errno, Integer winerror) throws PosixException { - throw new PosixErrnoException(errno, strerror(errno, null, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.getUncached()), winerror); + throw new PosixErrnoException(errno, strerror(errno), winerror); } // CPython performs this mapping in PC/errmap.h:winerror_to_errno(). diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index db97d8161e..993daf3458 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -44,6 +44,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.TruffleString; public abstract class PosixSupport { @@ -60,6 +61,14 @@ public static PosixSupport get(Node node) { return PythonContext.get(node).getPosixSupport(); } + public abstract TruffleString getBackend(); + + public abstract TruffleString strerror(int errorCode); + + public abstract long getpid(); + + public abstract int umask(int mask) throws PosixException; + public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index f8a7e66b42..9b1c02f261 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,14 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract TruffleString getBackend(Object recevier); - - public abstract TruffleString strerror(Object receiver, int errorCode); - - public abstract long getpid(Object receiver); - - public abstract int umask(Object receiver, int mask) throws PosixException; - public abstract int openat(Object receiver, int dirFd, Object pathname, int flags, int mode) throws PosixException; public abstract int close(Object receiver, int fd) throws PosixException; @@ -1042,7 +1034,7 @@ public Throwable fillInStackTrace() { /** * Exception that indicates POSIX level error associated with numeric code. If the message is * known, it may be included in the exception, otherwise it can be queried using - * {@link #strerror(Object, int)}. + * {@link PosixSupport#strerror(int)}. */ public static final class PosixErrnoException extends PosixException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 11c3728ed0..b8b6d14623 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -152,30 +152,28 @@ private Object removeDirStream(Object dirStream) { return dirStream; } - @ExportMessage - final TruffleString getBackend(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + public final TruffleString getBackend() { checkNotInPreInitialization(); - return nativeLib.getBackend(nativePosixSupport); + return nativePosixSupport.getBackend(); } - @ExportMessage - final TruffleString strerror(int errorCode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + public final TruffleString strerror(int errorCode) { checkNotInPreInitialization(); - return nativeLib.strerror(nativePosixSupport, errorCode); + return nativePosixSupport.strerror(errorCode); } - @ExportMessage - final long getpid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + public final long getpid() { checkNotInPreInitialization(); - return nativeLib.getpid(nativePosixSupport); + return nativePosixSupport.getpid(); } - @ExportMessage - final int umask(int mask, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int umask(int mask) throws PosixException { checkNotInPreInitialization(); - return nativeLib.umask(nativePosixSupport, mask); + return nativePosixSupport.umask(mask); } @ExportMessage From 4ed212c53b4461fa6746c57d469f3f7f72275173 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 12:49:24 +0200 Subject: [PATCH 025/129] Convert PosixSupportLibrary file descriptor operations (cherry picked from commit 638dadd511e0fa4891bbd5cc3eba8c7c0d278234) --- .../oracle/graal/python/test/SocketTests.java | 4 ++-- .../builtins/modules/PosixModuleBuiltins.java | 8 +++----- .../builtins/modules/SocketModuleBuiltins.java | 8 +++----- .../builtins/modules/io/FileIOBuiltins.java | 2 +- .../python/builtins/modules/io/PFileIO.java | 2 +- .../MultiprocessingModuleBuiltins.java | 5 ++--- .../builtins/objects/mmap/MMapBuiltins.java | 2 +- .../python/builtins/objects/mmap/PMMap.java | 7 ++++--- .../objects/socket/SocketBuiltins.java | 7 +++---- .../python/runtime/EmulatedPosixSupport.java | 16 ++++++---------- .../python/runtime/LoggingPosixSupport.java | 14 ++++++-------- .../python/runtime/NativePosixSupport.java | 4 ++-- .../graal/python/runtime/PosixResources.java | 2 +- .../graal/python/runtime/PosixSupport.java | 4 ++++ .../python/runtime/PosixSupportLibrary.java | 4 ---- .../python/runtime/PreInitPosixSupport.java | 18 ++++++++---------- 16 files changed, 47 insertions(+), 60 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index 3050124abf..bf1fd0c65f 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -1105,7 +1105,7 @@ private static void expectGetAddrInfoException(ThrowingRunnable runnable, Mandat private int createSocket(int family, int type, int protocol) throws PosixException { int sockfd = lib.socket(posixSupport, family, type, protocol); - cleanup.add(() -> lib.close(posixSupport, sockfd)); + cleanup.add(() -> posixSupport.close(sockfd)); return sockfd; } @@ -1278,7 +1278,7 @@ private class Server extends Socket { int acceptFd(FamilySpecificSockAddr expectedAddress) throws PosixException { AcceptResult acceptResult = lib.accept(posixSupport, fd); - cleanup.add(() -> lib.close(posixSupport, acceptResult.socketFd)); + cleanup.add(() -> posixSupport.close(acceptResult.socketFd)); checkUsa(expectedAddress, acceptResult.sockAddr); return acceptResult.socketFd; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 693bc6b7ee..9be241f9f8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -898,7 +898,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static int open(VirtualFrame frame, PosixPath path, int flags, int mode, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @@ -912,7 +911,7 @@ static int open(VirtualFrame frame, PosixPath path, int flags, int mode, int dir try { while (true) { try { - return posixLib.openat(context.getPosixSupport(), dirFd, path.value, fixedFlags, mode); + return context.getPosixSupport().openat(dirFd, path.value, fixedFlags, mode); } catch (PosixException e) { errorProfile.enter(inliningTarget); if (e.hasErrno(OSErrorEnum.EINTR)) { @@ -943,13 +942,12 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone close(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { gil.release(true); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } finally { gil.acquire(); } @@ -2056,7 +2054,7 @@ static Object dupAndFdopendir(VirtualFrame frame, Node inliningTarget, PosixSupp } catch (PosixException e) { if (dupFd != -1) { try { - posixLib.close(posixSupport, dupFd); + posixSupport.close(dupFd); } catch (PosixException e1) { // ignored } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index f2e395e59f..08df641bd3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -247,8 +247,8 @@ public abstract static class GetHostnameNode extends PythonBuiltinNode { @Specialization static TruffleString doGeneric(VirtualFrame frame, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, + @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -752,7 +752,6 @@ abstract static class CloseNode extends PythonUnaryBuiltinNode { @Specialization static Object close(VirtualFrame frame, Object fdObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached GilNode gil, @Cached PyLongAsIntNode asIntNode, @@ -761,7 +760,7 @@ static Object close(VirtualFrame frame, Object fdObj, try { gil.release(true); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } finally { gil.acquire(); } @@ -781,7 +780,6 @@ abstract static class DupNode extends PythonUnaryBuiltinNode { @Specialization static Object close(VirtualFrame frame, Object fdObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached GilNode gil, @Cached PyLongAsIntNode asIntNode, @@ -795,7 +793,7 @@ static Object close(VirtualFrame frame, Object fdObj, context.getPosixSupport().setInheritable(dup, false); } catch (PosixException e1) { try { - posixLib.close(context.getPosixSupport(), dup); + context.getPosixSupport().close(dup); } catch (PosixException e2) { // ignore } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index 1d53de6444..e246e5bfb1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -249,7 +249,7 @@ private static int open(VirtualFrame frame, TruffleString name, int flags, int m try { gil.release(true); try { - return posixLib.openat(ctxt.getPosixSupport(), AT_FDCWD.value, path, flags, mode); + return ctxt.getPosixSupport().openat(AT_FDCWD.value, path, flags, mode); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java index ca9c15aa0d..df6bd57b7b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java @@ -212,7 +212,7 @@ void doRelease() { if (markReleased()) { assert isReleased(); try (GilNode.UncachedRelease gil = GilNode.uncachedRelease()) { - PosixSupportLibrary.getUncached().close(context.getPosixSupport(), (int) getReference()); + context.getPosixSupport().close((int) getReference()); } catch (PosixException e) { // ignore } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java index 193609ad2b..7a2c4fea2a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java @@ -120,8 +120,8 @@ abstract static class Send extends PythonBinaryClinicBuiltinNode { @Specialization(limit = "3") static int doit(VirtualFrame frame, int handle, Object buffer, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, + @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -148,11 +148,10 @@ abstract static class CloseSocket extends PythonUnaryClinicBuiltinNode { @Specialization PNone doit(VirtualFrame frame, int handle, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.close(context.getPosixSupport(), handle); + context.getPosixSupport().close(handle); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index f6f1b26305..1625269443 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -316,7 +316,7 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj } catch (PosixException e) { if (trackedFd != ANONYMOUS_FD) { try { - posixSupportLib.close(posixSupport, trackedFd); + posixSupport.close(trackedFd); } catch (PosixException ignored) { } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java index bac81eca36..d3956fa112 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java @@ -49,6 +49,7 @@ import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.NativePosixSupport; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; @@ -85,7 +86,7 @@ public Object getPosixSupportHandle() { return ref.getReference(); } - void close(PosixSupportLibrary lib, Object posix) { + void close(PosixSupportLibrary lib, PosixSupport posix) { ref.close(lib, posix); } @@ -196,7 +197,7 @@ public AsyncHandler.AsyncAction release() { return new MMapBuiltins.ReleaseCallback(this); } - void close(PosixSupportLibrary posixLib, Object posixSupport) { + void close(PosixSupportLibrary posixLib, PosixSupport posixSupport) { if (!markReleased()) { return; } @@ -204,7 +205,7 @@ void close(PosixSupportLibrary posixLib, Object posixSupport) { Object handle = getReference(); if (fd != -1) { try { - posixLib.close(posixSupport, fd); + posixSupport.close(fd); } catch (PosixException e) { // ignored (CPython does not check the return value) } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index cfc347f164..e531c7f23c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -207,7 +207,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i // If we failed before giving the fd to python-land, close it CompilerDirectives.transferToInterpreterAndInvalidate(); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } catch (PosixException posixException) { // ignore } @@ -332,7 +332,7 @@ static Object accept(VirtualFrame frame, PSocket self, // If we failed before giving the fd to python-land, close it CompilerDirectives.transferToInterpreterAndInvalidate(); try { - posixLib.close(posixSupport, acceptResult.socketFd); + posixSupport.close(acceptResult.socketFd); } catch (PosixException posixException) { // ignore } @@ -382,7 +382,6 @@ abstract static class CloseNode extends PythonUnaryBuiltinNode { static Object close(VirtualFrame frame, PSocket socket, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int fd = socket.getFd(); @@ -391,7 +390,7 @@ static Object close(VirtualFrame frame, PSocket socket, socket.setFd(INVALID_FD); gil.release(true); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 1b975d44da..572d3ac070 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -441,9 +441,8 @@ public TruffleString strerror(int errorCode) { return err.getMessage(); } - @ExportMessage(name = "close") - public int closeMessage(int fd) throws PosixException { - // TODO: to be replaced with super.close once the super class is merged with this class + @Override + public int close(int fd) throws PosixException { try { if (!removeFD(fd)) { throw posixException(OSErrorEnum.EBADF); @@ -454,18 +453,15 @@ public int closeMessage(int fd) throws PosixException { } } - @ExportMessage - @SuppressWarnings({"unused", "static-method"}) - public int openat(int dirFd, Object path, int flags, int mode, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public int openat(int dirFd, Object path, int flags, int mode) throws PosixException { TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); Set options = flagsToOptions(flags); FileAttribute> attributes = modeToAttributes(mode & ~currentUmask); try { return openTruffleFile(file, options, attributes); } catch (Exception e) { - errorBranch.enter(inliningTarget); ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } @@ -1732,7 +1728,7 @@ public void closedir(Object dirStreamObj) throws PosixException { throw posixException(OSErrorEnum.fromException(e)); } finally { if (dirStream.fd != -1) { - close(dirStream.fd); + closeResource(dirStream.fd); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 9d0c101915..568de2d18f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -148,23 +148,21 @@ public final int umask(int mask) throws PosixException { } } - @ExportMessage - final int openat(int dirFd, Object pathname, int flags, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { logEnter("openAt", "%d, %s, 0x%x, 0%o", dirFd, pathname, flags, mode); try { - return logExit("openAt", "%d", lib.openat(delegate, dirFd, pathname, flags, mode)); + return logExit("openAt", "%d", delegate.openat(dirFd, pathname, flags, mode)); } catch (PosixException e) { throw logException("openAt", e); } } - @ExportMessage - final int close(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int close(int fd) throws PosixException { logEnter("close", "%d", fd); try { - return lib.close(delegate, fd); + return delegate.close(fd); } catch (PosixException e) { throw logException("close", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 193232fe24..0bf2b2aa65 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -747,7 +747,7 @@ public int umask(int mask) { return posixNativeFunctionInvoker.call_umask(mask); } - @ExportMessage + @Override public int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { long pathnamePtr = pathToNativeCString(pathname); try { @@ -761,7 +761,7 @@ public int openat(int dirFd, Object pathname, int flags, int mode) throws PosixE } } - @ExportMessage + @Override public int close(int fd) throws PosixException { final int rv = posixNativeFunctionInvoker.call_close(fd); if (rv < 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java index 1cf9dde5bf..5d4c187ca4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java @@ -356,7 +356,7 @@ public String getFilePath(int fd) { } @TruffleBoundary - public void close(int fd) { + public void closeResource(int fd) { try { removeFD(fd); } catch (IOException ignored) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 993daf3458..26d1bd47a5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -69,6 +69,10 @@ public static PosixSupport get(Node node) { public abstract int umask(int mask) throws PosixException; + public abstract int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException; + + public abstract int close(int fd) throws PosixException; + public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 9b1c02f261..9ba9c6f967 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,10 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract int openat(Object receiver, int dirFd, Object pathname, int flags, int mode) throws PosixException; - - public abstract int close(Object receiver, int fd) throws PosixException; - public abstract long getOsfHandle(Object receiver, int fd) throws PosixException; public abstract int openOsfHandle(Object receiver, long handle, int flags) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index b8b6d14623..9287486394 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -176,22 +176,20 @@ public final int umask(int mask) throws PosixException { return nativePosixSupport.umask(mask); } - @ExportMessage - final int openat(int dirFd, Object pathname, int flags, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { if (inPreInitialization) { - return addFd(PosixSupportLibrary.getUncached().openat(emulatedPosixSupport, dirFd, pathname, flags, mode)); + return addFd(emulatedPosixSupport.openat(dirFd, pathname, flags, mode)); } - return nativeLib.openat(nativePosixSupport, dirFd, pathname, flags, mode); + return nativePosixSupport.openat(dirFd, pathname, flags, mode); } - @ExportMessage - final int close(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int close(int fd) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().close(emulatedPosixSupport, removeFd(fd)); + return emulatedPosixSupport.close(removeFd(fd)); } - return nativeLib.close(nativePosixSupport, fd); + return nativePosixSupport.close(fd); } @Override From e8087577b9fec8de91ad30a60dd18899fd1f2812 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 12:52:26 +0200 Subject: [PATCH 026/129] Convert PosixSupportLibrary Windows descriptor operations (cherry picked from commit c4de063fef376f3e0433cf8e5cdd5272b18831d5) --- .../modules/MsvcrtModuleBuiltins.java | 12 +++----- .../python/runtime/EmulatedPosixSupport.java | 14 ++++------ .../python/runtime/LoggingPosixSupport.java | 28 ++++++++----------- .../python/runtime/NativePosixSupport.java | 8 +++--- .../graal/python/runtime/PosixSupport.java | 8 ++++++ .../python/runtime/PosixSupportLibrary.java | 8 ------ .../python/runtime/PreInitPosixSupport.java | 28 ++++++++----------- 7 files changed, 45 insertions(+), 61 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java index 69d21c7834..200d0faed4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java @@ -102,14 +102,13 @@ public abstract static class LockingNode extends PythonTernaryClinicBuiltinNode Object locking(VirtualFrame frame, int fd, int mode, long nbytes, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gilNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_MSVCRT_LOCKING, fd, mode, nbytes); try { gilNode.release(true); try { - posixLib.msvcrtLocking(getPosixSupport(), fd, mode, nbytes); + getPosixSupport().msvcrtLocking(fd, mode, nbytes); } finally { gilNode.acquire(); } @@ -133,10 +132,9 @@ public abstract static class SetModeNode extends PythonBinaryClinicBuiltinNode { @Specialization int setMode(VirtualFrame frame, int fd, int flags, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.setMode(getPosixSupport(), fd, flags); + return getPosixSupport().setMode(fd, flags); } catch (PosixSupportLibrary.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -156,11 +154,10 @@ public abstract static class GetOsfHandleNode extends PythonUnaryClinicBuiltinNo long getOsfHandle(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_MSVCRT_GET_OSFHANDLE, fd); try { - return posixLib.getOsfHandle(getPosixSupport(), fd); + return getPosixSupport().getOsfHandle(fd); } catch (PosixSupportLibrary.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -181,11 +178,10 @@ public abstract static class OpenOsfHandleNode extends PythonBinaryClinicBuiltin int openOsfHandle(VirtualFrame frame, long handle, int flags, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_MSVCRT_OPEN_OSFHANDLE, handle, flags); try { - return posixLib.openOsfHandle(getPosixSupport(), handle, flags); + return getPosixSupport().openOsfHandle(handle, flags); } catch (PosixSupportLibrary.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 572d3ac070..906556a88f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -579,19 +579,19 @@ public void setInheritable(int fd, boolean inheritable) { compatibilityIgnored("setting inheritable '%b' for file descriptor %d in POSIX emulation layer (not supported)", inheritable, fd); } - @ExportMessage + @Override @SuppressWarnings("static-method") public long getOsfHandle(int fd) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("get_osfhandle"); } - @ExportMessage + @Override @SuppressWarnings("static-method") public int openOsfHandle(long handle, int flags) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("open_osfhandle"); } - @ExportMessage + @Override public int setMode(int fd, int mode) throws PosixException { int binary = PosixConstants.O_BINARY.getValueIfDefined(); int text = PosixConstants.O_TEXT.getValueIfDefined(); @@ -605,20 +605,16 @@ public int setMode(int fd, int mode) throws PosixException { return previousMode; } - @ExportMessage - public void msvcrtLocking(int fd, int mode, long nbytes, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } boolean unlock = mode == PosixConstants._LK_UNLCK.getValueIfDefined(); boolean blocking = mode == PosixConstants._LK_LOCK.getValueIfDefined() || mode == PosixConstants._LK_RLCK.getValueIfDefined(); boolean nonBlocking = mode == PosixConstants._LK_NBLCK.getValueIfDefined() || mode == PosixConstants._LK_NBRLCK.getValueIfDefined(); if (!unlock && !blocking && !nonBlocking) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EINVAL); } doLockOperation(fd, channel, unlock, false, blocking, SEEK_CUR.value, 0, nbytes); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 568de2d18f..a2633009a4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -248,45 +248,41 @@ public final void setInheritable(int fd, boolean inheritable) throws PosixExcept } } - @ExportMessage - final long getOsfHandle(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final long getOsfHandle(int fd) throws PosixException { logEnter("getOsfHandle", "%d", fd); try { - return logExit("getOsfHandle", "%d", lib.getOsfHandle(delegate, fd)); + return logExit("getOsfHandle", "%d", delegate.getOsfHandle(fd)); } catch (PosixException e) { throw logException("getOsfHandle", e); } } - @ExportMessage - final int openOsfHandle(long handle, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int openOsfHandle(long handle, int flags) throws PosixException { logEnter("openOsfHandle", "%d, %d", handle, flags); try { - return logExit("openOsfHandle", "%d", lib.openOsfHandle(delegate, handle, flags)); + return logExit("openOsfHandle", "%d", delegate.openOsfHandle(handle, flags)); } catch (PosixException e) { throw logException("openOsfHandle", e); } } - @ExportMessage - final int setMode(int fd, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int setMode(int fd, int mode) throws PosixException { logEnter("setMode", "%d, %d", fd, mode); try { - return logExit("setMode", "%d", lib.setMode(delegate, fd, mode)); + return logExit("setMode", "%d", delegate.setMode(fd, mode)); } catch (PosixException e) { throw logException("setMode", e); } } - @ExportMessage - final void msvcrtLocking(int fd, int mode, long nbytes, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { logEnter("msvcrtLocking", "%d, %d, %d", fd, mode, nbytes); try { - lib.msvcrtLocking(delegate, fd, mode, nbytes); + delegate.msvcrtLocking(fd, mode, nbytes); } catch (PosixException e) { throw logException("msvcrtLocking", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 0bf2b2aa65..10edfa04c6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -858,7 +858,7 @@ public void setInheritable(int fd, boolean inheritable) throws PosixException { } } - @ExportMessage + @Override public long getOsfHandle(int fd) throws PosixException { long nativeOut = NativeMemory.mallocLongArray(1); try { @@ -871,7 +871,7 @@ public long getOsfHandle(int fd) throws PosixException { } } - @ExportMessage + @Override public int openOsfHandle(long handle, int flags) throws PosixException { int fd = posixNativeFunctionInvoker.call_open_osfhandle(handle, flags); if (fd < 0) { @@ -880,7 +880,7 @@ public int openOsfHandle(long handle, int flags) throws PosixException { return fd; } - @ExportMessage + @Override public int setMode(int fd, int mode) throws PosixException { int previousMode = posixNativeFunctionInvoker.call_setmode(fd, mode); if (previousMode < 0) { @@ -889,7 +889,7 @@ public int setMode(int fd, int mode) throws PosixException { return previousMode; } - @ExportMessage + @Override public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { if (posixNativeFunctionInvoker.call_msvcrt_locking(fd, mode, nbytes) != 0) { throw getErrnoAndThrowPosixException(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 26d1bd47a5..765c1ac064 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -73,6 +73,14 @@ public static PosixSupport get(Node node) { public abstract int close(int fd) throws PosixException; + public abstract long getOsfHandle(int fd) throws PosixException; + + public abstract int openOsfHandle(long handle, int flags) throws PosixException; + + public abstract int setMode(int fd, int mode) throws PosixException; + + public abstract void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException; + public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 9ba9c6f967..8c0545a5fd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,14 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract long getOsfHandle(Object receiver, int fd) throws PosixException; - - public abstract int openOsfHandle(Object receiver, long handle, int flags) throws PosixException; - - public abstract int setMode(Object receiver, int fd, int mode) throws PosixException; - - public abstract void msvcrtLocking(Object receiver, int fd, int mode, long nbytes) throws PosixException; - public abstract int[] pipe(Object receiver) throws PosixException; public abstract SelectResult select(Object receiver, int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 9287486394..2788737993 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -249,32 +249,28 @@ public final void setInheritable(int fd, boolean inheritable) throws PosixExcept nativePosixSupport.setInheritable(fd, inheritable); } - @ExportMessage - final long getOsfHandle(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final long getOsfHandle(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getOsfHandle(nativePosixSupport, fd); + return nativePosixSupport.getOsfHandle(fd); } - @ExportMessage - final int openOsfHandle(long handle, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int openOsfHandle(long handle, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.openOsfHandle(nativePosixSupport, handle, flags); + return nativePosixSupport.openOsfHandle(handle, flags); } - @ExportMessage - final int setMode(int fd, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int setMode(int fd, int mode) throws PosixException { checkNotInPreInitialization(); - return nativeLib.setMode(nativePosixSupport, fd, mode); + return nativePosixSupport.setMode(fd, mode); } - @ExportMessage - final void msvcrtLocking(int fd, int mode, long nbytes, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { checkNotInPreInitialization(); - nativeLib.msvcrtLocking(nativePosixSupport, fd, mode, nbytes); + nativePosixSupport.msvcrtLocking(fd, mode, nbytes); } @ExportMessage From 4869778197a58055df30592fb10eae6bc0cd7917 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 12:56:47 +0200 Subject: [PATCH 027/129] Convert PosixSupportLibrary pipes and readiness (cherry picked from commit c2fae6cb2b939b67e79d3cb7286a839035ba0dce) --- .../oracle/graal/python/test/SocketTests.java | 16 +++--- .../builtins/modules/PosixModuleBuiltins.java | 3 +- .../modules/SelectModuleBuiltins.java | 3 +- .../builtins/objects/select/PollBuiltins.java | 3 +- .../objects/socket/SocketBuiltins.java | 4 +- .../builtins/objects/socket/SocketUtils.java | 13 ++--- .../python/runtime/EmulatedPosixSupport.java | 11 ++-- .../python/runtime/LoggingPosixSupport.java | 22 ++++---- .../python/runtime/NativePosixSupport.java | 51 ++++++++----------- .../graal/python/runtime/PosixResources.java | 2 +- .../graal/python/runtime/PosixSupport.java | 8 +++ .../python/runtime/PosixSupportLibrary.java | 6 --- .../python/runtime/PreInitPosixSupport.java | 20 ++++---- 13 files changed, 73 insertions(+), 89 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index bf1fd0c65f..d80500fb5f 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -647,7 +647,7 @@ public void nonBlockingAccept() throws PosixException { // A completed connect does not guarantee that the connection is already visible to a // non-blocking accept(). Wait until the listening socket reports that it is readable. - SelectResult res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(1, 0)); + SelectResult res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(1, 0)); assertTrue(res.getReadFds()[0]); srv.accept(cli.address()); } @@ -657,12 +657,12 @@ public void dgramSelect() throws PosixException { UdpServer srv = new UdpServer(AF_INET.value); UdpClient cli = new UdpClient(AF_INET.value); - SelectResult res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); + SelectResult res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertFalse(res.getReadFds()[0]); cli.sendto(DATA, 0, srv.usa()); - res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); + res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertTrue(res.getReadFds()[0]); checkUsa(cli.address(), srv.recvfrom(DATA, 0)); @@ -677,12 +677,12 @@ public void streamSelect() throws PosixException { TcpServer srv = new TcpServer(AF_INET.value); TcpClient cli = new TcpClient(AF_INET.value); - SelectResult res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); + SelectResult res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertFalse(res.getReadFds()[0]); cli.connect(srv.usa()); - res = lib.select(posixSupport, new int[]{srv.fd, cli.fd}, new int[0], new int[0], new Timeval(0, 100000)); + res = posixSupport.select(new int[]{srv.fd, cli.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertTrue(res.getReadFds()[0]); assertFalse(res.getReadFds()[1]); @@ -695,7 +695,7 @@ public void streamSelect() throws PosixException { c.send(DATA, 0); - res = lib.select(posixSupport, new int[]{srv.fd, cli.fd, c.fd}, new int[0], new int[0], new Timeval(0, 100000)); + res = posixSupport.select(new int[]{srv.fd, cli.fd, c.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertFalse(res.getReadFds()[0]); // c is readable immediately after shutdown(SHUT_RD), while the data sent to cli may arrive @@ -704,12 +704,12 @@ public void streamSelect() throws PosixException { boolean cliReadable = res.getReadFds()[1]; boolean cReadable = res.getReadFds()[2]; if (!cliReadable) { - SelectResult cliRes = lib.select(posixSupport, new int[]{cli.fd}, new int[0], new int[0], + SelectResult cliRes = posixSupport.select(new int[]{cli.fd}, new int[0], new int[0], new Timeval(1, 0)); cliReadable = cliRes.getReadFds()[0]; } if (!cReadable) { - SelectResult cRes = lib.select(posixSupport, new int[]{c.fd}, new int[0], new int[0], new Timeval(1, 0)); + SelectResult cRes = posixSupport.select(new int[]{c.fd}, new int[0], new int[0], new Timeval(1, 0)); cReadable = cRes.getReadFds()[0]; } assertTrue(cliReadable); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 9be241f9f8..db4eed2240 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1184,12 +1184,11 @@ static PTuple pipe(VirtualFrame frame, @Bind Node inliningTarget, @Cached GilNode gil, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int[] pipe; gil.release(true); try { - pipe = posixLib.pipe(context.getPosixSupport()); + pipe = context.getPosixSupport().pipe(); } catch (PosixException e) { gil.acquire(); // need to acquire the gil to construct the OSError object throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java index d66b51b34a..fd1b058f96 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java @@ -135,7 +135,6 @@ abstract static class SelectNode extends PythonBuiltinNode { static PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object xlist, Object timeout, @Bind Node inliningTarget, @Cached InlinedBranchProfile isNotNoneTimeout, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached PyObjectSizeNode sizeNode, @Cached PyObjectGetItem callGetItemNode, @Cached FastConstructListNode constructListNode, @@ -167,7 +166,7 @@ static PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object x try { gil.release(true); try { - result = posixLib.select(PosixSupport.get(inliningTarget), readFDs.fds, writeFDs.fds, xFDs.fds, timeoutval); + result = PosixSupport.get(inliningTarget).select(readFDs.fds, writeFDs.fds, xFDs.fds, timeoutval); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java index b57a8317b4..f2634ee309 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java @@ -158,7 +158,6 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, @Bind PythonLanguage language, @Cached PyTimeFromObjectNode fromTime, @Cached IsBuiltinObjectProfile typeErrorProfile, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -193,7 +192,7 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, try { gil.release(true); try { - posixLib.poll(PosixSupport.get(inliningTarget), pollFds, pollEvents, pollRevents, timeoutMs); + PosixSupport.get(inliningTarget).poll(pollFds, pollEvents, pollRevents, timeoutMs); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index e531c7f23c..99ff23ce8c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -430,7 +430,7 @@ static Object connect(VirtualFrame frame, PSocket self, Object address, return PNone.NONE; } - static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, Object posixSupport, GilNode gil, PSocket self, + static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, PosixSupport posixSupport, GilNode gil, PSocket self, UniversalSockAddr connectAddr) throws PosixException { try { gil.release(true); @@ -454,7 +454,7 @@ static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.L p.getsockopt(s, self.getFd(), SOL_SOCKET.value, SO_ERROR.value, tmp, tmp.length); int err = PythonUtils.ARRAY_ACCESSOR.getInt(tmp, 0); if (err != 0 && err != EISCONN.getNumber()) { - throw new PosixErrnoException(err, ((PosixSupport) s).strerror(err)); + throw new PosixErrnoException(err, s.strerror(err)); } return null; }, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java index e3513ecdb9..0785aedb90 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java @@ -50,6 +50,7 @@ import com.oracle.graal.python.nodes.PConstructAndRaiseNode; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; @@ -67,14 +68,14 @@ public interface SocketFunction { * NB: The library and support need to be passed as arguments and shouldn't be taken from * the closure. Otherwise, Truffle has trouble inlining the library call. */ - T run(PosixSupportLibrary posixLib, Object posixSupport) throws PosixException; + T run(PosixSupportLibrary posixLib, PosixSupport posixSupport) throws PosixException; } /** * Rough equivalent of CPython's {@code sock_call}. Takes care of calling select for connections * with timeouts and retrying the call on EINTR. Must be called with GIL held. */ - public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, Object posixSupport, GilNode gil, + public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, PosixSupport posixSupport, GilNode gil, PSocket socket, SocketFunction function, boolean writing, boolean connect) throws PosixException { return callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, socket, function, writing, connect, null); } @@ -83,7 +84,7 @@ public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget * Rough equivalent of CPython's {@code sock_call_ex}. Takes care of calling select for * connections with timeouts and retrying the call on EINTR. Must be called with GIL held. */ - public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, Object posixSupport, GilNode gil, + public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, PosixSupport posixSupport, GilNode gil, PSocket socket, SocketFunction function, boolean writing, boolean connect, TimeoutHelper timeoutHelperIn) throws PosixException { TimeoutHelper timeoutHelper = timeoutHelperIn; if (timeoutHelper == null && socket.getTimeoutNs() > 0) { @@ -107,10 +108,10 @@ public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget if (PosixConstants.IS_WIN32) { int[] errorfds = connect ? new int[]{socket.getFd()} : EMPTY_INT_ARRAY; if (writing) { - SelectResult selected = posixLib.select(posixSupport, EMPTY_INT_ARRAY, new int[]{socket.getFd()}, errorfds, selectTimeout); + SelectResult selected = posixSupport.select(EMPTY_INT_ARRAY, new int[]{socket.getFd()}, errorfds, selectTimeout); ready = selected.getWriteFds()[0] || connect && selected.getErrorFds()[0]; } else { - SelectResult selected = posixLib.select(posixSupport, new int[]{socket.getFd()}, EMPTY_INT_ARRAY, errorfds, selectTimeout); + SelectResult selected = posixSupport.select(new int[]{socket.getFd()}, EMPTY_INT_ARRAY, errorfds, selectTimeout); ready = selected.getReadFds()[0] || connect && selected.getErrorFds()[0]; } } else { @@ -119,7 +120,7 @@ public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget event |= PosixConstants.POLLERR.getValueIfDefined(); } int[] revents = new int[1]; - posixLib.poll(posixSupport, new int[]{socket.getFd()}, new int[]{event}, revents, pollTimeout(selectTimeout)); + posixSupport.poll(new int[]{socket.getFd()}, new int[]{event}, revents, pollTimeout(selectTimeout)); ready = revents[0] != 0; } if (!ready) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 906556a88f..c0c18e1003 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -620,17 +620,16 @@ public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { doLockOperation(fd, channel, unlock, false, blocking, SEEK_CUR.value, 0, nbytes); } - @ExportMessage(name = "pipe") - public int[] pipeMessage() throws PosixException { - // TODO: will merge with super.pipe once the super class is merged with this class + @Override + public int[] pipe() throws PosixException { try { - return super.pipe(); + return super.pipeResource(); } catch (IOException ex) { throw posixException(OSErrorEnum.fromException(ex)); } } - @ExportMessage + @Override @TruffleBoundary public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -791,7 +790,7 @@ private SelectableChannel getSelectableChannel(int fd) throws PosixException { throw ChannelNotSelectableException.INSTANCE; } - @ExportMessage + @Override @TruffleBoundary public void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { assert fds.length == events.length && fds.length == revents.length; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index a2633009a4..d1dd69e36a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -288,35 +288,31 @@ public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixExcep } } - @ExportMessage - final int[] pipe( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int[] pipe() throws PosixException { logEnter("pipe", ""); try { - return logExit("pipe", "%s", lib.pipe(delegate)); + return logExit("pipe", "%s", delegate.pipe()); } catch (PosixException e) { throw logException("pipe", e); } } - @SuppressWarnings("all") - @ExportMessage - public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { logEnter("select", "%s %s %s %s", readfds, writefds, errorfds, timeout); try { - return logExit("select", "%s", lib.select(delegate, readfds, writefds, errorfds, timeout)); + return logExit("select", "%s", delegate.select(readfds, writefds, errorfds, timeout)); } catch (PosixException e) { throw logException("select", e); } } - @ExportMessage - public void poll(int[] fds, int[] events, int[] revents, int timeout, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { logEnter("poll", "%s %s %s", fds, events, timeout); try { - lib.poll(delegate, fds, events, revents, timeout); + delegate.poll(fds, events, revents, timeout); logExit("poll", "%s", revents); } catch (PosixException e) { throw logException("poll", e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 10edfa04c6..ec57a44b2e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -147,7 +147,6 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; -import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.AbstractTruffleString; import com.oracle.truffle.api.strings.InternalByteArray; @@ -896,7 +895,7 @@ public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { } } - @ExportMessage + @Override public int[] pipe() throws PosixException { int[] fds = new int[2]; long nativeFds = NativeMemory.mallocIntArray(fds.length); @@ -911,13 +910,11 @@ public int[] pipe() throws PosixException { } } - @ExportMessage - public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout, - @Bind Node inliningTarget) throws PosixException { + @Override + public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { int largestFD = findMax(readfds, -1); largestFD = findMax(writefds, largestFD); largestFD = findMax(errorfds, largestFD); - LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) readfds.length + writefds.length + errorfds.length)); // This will be treated as boolean array (output parameter), each item indicating if given // FD was selected or not byte[] selected = new byte[readfds.length + writefds.length + errorfds.length]; @@ -979,7 +976,7 @@ private static int findMax(int[] items, int currentMax) { return max; } - @ExportMessage + @Override public void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { assert fds.length == events.length && fds.length == revents.length; int count = fds.length; @@ -1992,8 +1989,7 @@ public void unsetenv(Object name) throws PosixException { @ExportMessage public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, - @Bind Node inliningTarget) throws PosixException { + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { // The following strings and string arrays need to be present in the native function: // - char** of executable names ('\0'-terminated strings with an extra NULL at the end) @@ -2024,16 +2020,16 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en try { offsetsLen = executables.length + 1; - dataLen = addLengthsOfCStrings(inliningTarget, 0, executables); + dataLen = addLengthsOfCStrings(0, executables); argsPos = offsetsLen; offsetsLen += args.length + 1; - dataLen = addLengthsOfCStrings(inliningTarget, dataLen, args); + dataLen = addLengthsOfCStrings(dataLen, args); if (env != null) { envPos = offsetsLen; offsetsLen += env.length + 1; - dataLen = addLengthsOfCStrings(inliningTarget, dataLen, env); + dataLen = addLengthsOfCStrings(dataLen, env); } else { envPos = -1; } @@ -2106,8 +2102,7 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en } @ExportMessage - public void execv(Object pathname, Object[] args, - @Bind Node inliningTarget) throws PosixException { + public void execv(Object pathname, Object[] args) throws PosixException { if (WINDOWS) { throw newPosixException(OSErrorEnum.ENOSYS.getNumber()); @@ -2133,7 +2128,7 @@ public void execv(Object pathname, Object[] args, try { // The +1 can overflow only if the buffer contains 2^63-1 bytes, which is impossible // since we are using Java arrays limited to 2^31-1. - dataLen = addLengthsOfCStrings(inliningTarget, pathnameLen + 1L, args); + dataLen = addLengthsOfCStrings(pathnameLen + 1L, args); } catch (OverflowException e) { throw newPosixException(OSErrorEnum.E2BIG.getNumber()); } @@ -2177,12 +2172,11 @@ public int system(Object command) { } } - private static long addLengthsOfCStrings(Node inliningTarget, long prevLen, Object[] src) throws OverflowException { + private static long addLengthsOfCStrings(long prevLen, Object[] src) throws OverflowException { long len = prevLen; for (int i = 0; i < src.length; i++) { len = PythonUtils.addExact(len, ((Buffer) src[i]).length); } - LoopNode.reportLoopCount(inliningTarget, src.length); return PythonUtils.addExact(len, src.length); // add space for terminating '\0' } @@ -3414,7 +3408,7 @@ public Object createPathFromString(TruffleString path, TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); } - return checkNarrowPath(inliningTarget, encodeFSDefaultNode.execute(null, inliningTarget, path)); + return checkNarrowPath(encodeFSDefaultNode.execute(null, inliningTarget, path)); } @ExportMessage @@ -3429,7 +3423,7 @@ public Object createPathFromBytes(byte[] path, TruffleString utf16 = switchEncodingNode.execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(inliningTarget, path)); return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); } - return checkNarrowPath(inliningTarget, path); + return checkNarrowPath(path); } @ExportMessage @@ -3488,13 +3482,12 @@ public Object createCStringFromString(TruffleString string, @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, @Exclusive @Cached TruffleString.IsValidNode isValidNode, @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - return checkCString(inliningTarget, getUTF8StringBytes(inliningTarget, string, switchEncodingNode, isValidNode, copyToByteArrayNode)); + return checkCString(getUTF8StringBytes(inliningTarget, string, switchEncodingNode, isValidNode, copyToByteArrayNode)); } @ExportMessage - public Object createCStringFromBytes(byte[] bytes, - @Bind Node inliningTarget) { - return checkCString(inliningTarget, bytes); + public Object createCStringFromBytes(byte[] bytes) { + return checkCString(bytes); } @ExportMessage @@ -3565,22 +3558,20 @@ private static PException raiseSurrogatesEncodeError(Node node, TruffleString st return PRaiseNode.raiseExceptionObjectStatic(node, exception); } - private static Buffer checkCString(Node inliningTarget, byte[] path) { - for (int i = 0; i < path.length; i++) { - if (path[i] == 0) { - LoopNode.reportLoopCount(inliningTarget, i); + private static Buffer checkCString(byte[] path) { + for (byte b : path) { + if (b == 0) { return null; } } - LoopNode.reportLoopCount(inliningTarget, path.length); // TODO we keep a byte[] provided by the caller, who can potentially change it, making our // check for embedded nulls pointless. Maybe we should copy it and while on it, might as // well add the terminating null character, avoiding the copy we do later in pathToCString. return Buffer.wrap(path); } - private static NarrowPath checkNarrowPath(Node inliningTarget, byte[] path) { - return checkCString(inliningTarget, path) == null ? null : new NarrowPath(path); + private static NarrowPath checkNarrowPath(byte[] path) { + return checkCString(path) == null ? null : new NarrowPath(path); } private static WidePath checkWidePath(byte[] path) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java index 5d4c187ca4..6c44f6c362 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java @@ -417,7 +417,7 @@ public Object ftruncate(int fd, long size) throws IOException { } @TruffleBoundary - public int[] pipe() throws IOException { + public int[] pipeResource() throws IOException { synchronized (files) { Pipe pipe = Pipe.open(); int readFD = nextFreeFd(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 765c1ac064..e48fac10e6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -42,6 +42,8 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; +import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -81,6 +83,12 @@ public static PosixSupport get(Node node) { public abstract void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException; + public abstract int[] pipe() throws PosixException; + + public abstract SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException; + + public abstract void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException; + public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 8c0545a5fd..38903c10f2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,12 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract int[] pipe(Object receiver) throws PosixException; - - public abstract SelectResult select(Object receiver, int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException; - - public abstract void poll(Object receiver, int[] fds, int[] events, int[] revents, int timeout) throws PosixException; - public abstract long lseek(Object receiver, int fd, long offset, int how) throws PosixException; public abstract void ftruncate(Object receiver, int fd, long length) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 2788737993..daf2c40cc3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -273,24 +273,22 @@ public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixExcep nativePosixSupport.msvcrtLocking(fd, mode, nbytes); } - @ExportMessage - final int[] pipe(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int[] pipe() throws PosixException { checkNotInPreInitialization(); - return nativeLib.pipe(nativePosixSupport); + return nativePosixSupport.pipe(); } - @ExportMessage - final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { checkNotInPreInitialization(); - return nativeLib.select(nativePosixSupport, readfds, writefds, errorfds, timeout); + return nativePosixSupport.select(readfds, writefds, errorfds, timeout); } - @ExportMessage - final void poll(int[] fds, int[] events, int[] revents, int timeout, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { checkNotInPreInitialization(); - nativeLib.poll(nativePosixSupport, fds, events, revents, timeout); + nativePosixSupport.poll(fds, events, revents, timeout); } @ExportMessage From d5e2dccc7c15e903846b4d6ede38abfba1b708c8 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 13:02:34 +0200 Subject: [PATCH 028/129] Convert PosixSupportLibrary positioning operations (cherry picked from commit f76c88df7978352ba93ac7748c834ca95a88bd6c) --- .../builtins/modules/PosixModuleBuiltins.java | 12 +++------ .../builtins/modules/SysModuleBuiltins.java | 15 +++++------ .../io/AbstractBufferedIOBuiltins.java | 7 +++-- .../modules/io/BufferedReaderBuiltins.java | 7 +++-- .../modules/io/BufferedWriterBuiltins.java | 7 +++-- .../builtins/modules/io/FileIOBuiltins.java | 23 +++++++--------- .../python/runtime/EmulatedPosixSupport.java | 26 +++++++------------ .../python/runtime/LoggingPosixSupport.java | 21 +++++++-------- .../python/runtime/NativePosixSupport.java | 6 ++--- .../graal/python/runtime/PosixResources.java | 2 +- .../graal/python/runtime/PosixSupport.java | 6 +++++ .../python/runtime/PosixSupportLibrary.java | 6 ----- .../python/runtime/PreInitPosixSupport.java | 23 +++++++--------- 13 files changed, 67 insertions(+), 94 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index db4eed2240..3dd84928af 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1229,10 +1229,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static long lseek(VirtualFrame frame, int fd, long pos, int how, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.lseek(context.getPosixSupport(), fd, pos, mapPythonSeekWhenceToPosix(how)); + return context.getPosixSupport().lseek(fd, pos, mapPythonSeekWhenceToPosix(how)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1254,7 +1253,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone ftruncate(VirtualFrame frame, int fd, long length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @Cached InlinedBranchProfile errorProfile, @@ -1264,7 +1262,7 @@ static PNone ftruncate(VirtualFrame frame, int fd, long length, try { gil.release(true); try { - posixLib.ftruncate(context.getPosixSupport(), fd, length); + context.getPosixSupport().ftruncate(fd, length); } finally { gil.acquire(); } @@ -1296,7 +1294,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone truncate(VirtualFrame frame, PosixPath path, long length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Exclusive @Cached GilNode gil, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -1304,7 +1301,7 @@ static PNone truncate(VirtualFrame frame, PosixPath path, long length, try { gil.release(true); try { - posixLib.truncate(context.getPosixSupport(), path.value, length); + context.getPosixSupport().truncate(path.value, length); } finally { gil.acquire(); } @@ -1318,12 +1315,11 @@ static PNone truncate(VirtualFrame frame, PosixPath path, long length, static PNone ftruncate(VirtualFrame frame, PosixFd fd, long length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Exclusive @Cached GilNode gil, @Exclusive @Cached InlinedBranchProfile errorProfile, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return FtruncateNode.ftruncate(frame, fd.fd, length, inliningTarget, context, posixLib, auditNode, gil, errorProfile, constructAndRaiseNode); + return FtruncateNode.ftruncate(frame, fd.fd, length, inliningTarget, context, auditNode, gil, errorProfile, constructAndRaiseNode); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index 0e16aa772a..40b597135c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -256,7 +256,7 @@ import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.CApiState; @@ -801,8 +801,7 @@ static void initStd(Python3Core core) { GraalPythonModuleBuiltins gp = (GraalPythonModuleBuiltins) core.lookupBuiltinModule(T___GRAALPYTHON__).getBuiltins(); TruffleString stdioEncoding = gp.getStdIOEncoding(); TruffleString stdioError = gp.getStdIOError(); - Object posixSupport = context.getPosixSupport(); - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); + PosixSupport posixSupport = context.getPosixSupport(); PythonModule sysModule = core.lookupBuiltinModule(T_SYS); boolean buffering = !context.getOption(PythonOptions.UnbufferedIO); @@ -810,16 +809,16 @@ static void initStd(Python3Core core) { PFileIO stdinFileIO = PFactory.createFileIO(language); FileIOBuiltins.FileIOInit.internalInit(stdinFileIO, toTruffleStringUncached(""), 0, IOMode.RB); PBuffered stdinBuffer = PFactory.createBufferedReader(language); - BufferedReaderBuiltins.BufferedReaderInit.internalInit(stdinBuffer, stdinFileIO, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); + BufferedReaderBuiltins.BufferedReaderInit.internalInit(stdinBuffer, stdinFileIO, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport); setWrapper(T_STDIN, T___STDIN__, T_R, stdioEncoding, stdioError, PNone.NONE, stdinBuffer, sysModule, language, true); PFileIO stdoutFileIO = createStdoutRaw(context, language, toTruffleStringUncached(""), 1); - Object stdoutBuffer = createBufferedIO(buffering, language, stdoutFileIO, posixSupport, posixLib); + Object stdoutBuffer = createBufferedIO(buffering, language, stdoutFileIO, posixSupport); TruffleString stdoutEncoding = isWindowsConsoleIO(stdoutFileIO) ? StringLiterals.T_UTF8 : stdioEncoding; setWrapper(T_STDOUT, T___STDOUT__, T_W, stdoutEncoding, stdioError, PNone.NONE, stdoutBuffer, sysModule, language, buffering); PFileIO stderr = createStdoutRaw(context, language, toTruffleStringUncached(""), 2); - Object stderrBuffer = createBufferedIO(buffering, language, stderr, posixSupport, posixLib); + Object stderrBuffer = createBufferedIO(buffering, language, stderr, posixSupport); TruffleString stderrEncoding = isWindowsConsoleIO(stderr) ? StringLiterals.T_UTF8 : stdioEncoding; setWrapper(T_STDERR, T___STDERR__, T_W, stderrEncoding, T_BACKSLASHREPLACE, PNone.NONE, stderrBuffer, sysModule, language, buffering); } @@ -842,7 +841,7 @@ private static boolean isWindowsConsoleIO(PFileIO fileIO) { return getPythonOS() == PLATFORM_WIN32 && fileIO.getPythonClass() == PWindowsConsoleIO; } - private static Object createBufferedIO(boolean buffering, PythonLanguage language, PFileIO fileIo, Object posixSupport, PosixSupportLibrary posixLib) { + private static Object createBufferedIO(boolean buffering, PythonLanguage language, PFileIO fileIo, PosixSupport posixSupport) { if (!buffering) { return fileIo; } @@ -850,7 +849,7 @@ private static Object createBufferedIO(boolean buffering, PythonLanguage languag if (isWindowsConsoleIO(fileIo)) { BufferedWriterBuiltins.BufferedWriterInit.internalInitConsole(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language); } else { - BufferedWriterBuiltins.BufferedWriterInit.internalInit(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); + BufferedWriterBuiltins.BufferedWriterInit.internalInit(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport); } return writer; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java index c32199d450..878188e5b0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java @@ -64,7 +64,7 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -116,11 +116,10 @@ static void init(PBuffered self, int bufferSize, PythonLanguage language) { } public static void internalInit(PBuffered self, int bufferSize, PythonLanguage language, - Object posixSupport, - PosixSupportLibrary posixLib) { + PosixSupport posixSupport) { init(self, bufferSize, language); try { - FileIOBuiltins.TellNode.internalTell(self.getFileIORaw(), posixSupport, posixLib); + FileIOBuiltins.TellNode.internalTell(self.getFileIORaw(), posixSupport); } catch (PosixException e) { // ignore.. it's ok if it's not seekable } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java index 577b1f4413..43ecac6a7e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java @@ -60,7 +60,7 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -116,11 +116,10 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PBuffered self, Obje } public static void internalInit(PBuffered self, PFileIO raw, int bufferSize, PythonLanguage language, - Object posixSupport, - PosixSupportLibrary posixLib) { + PosixSupport posixSupport) { self.setDetached(false); self.setRaw(raw, true); - BufferedInitNode.internalInit(self, bufferSize, language, posixSupport, posixLib); + BufferedInitNode.internalInit(self, bufferSize, language, posixSupport); self.resetRead(); self.setOK(true); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java index 82339302c7..d1bf1b29b2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java @@ -57,7 +57,7 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -115,11 +115,10 @@ static void doInit(VirtualFrame frame, @SuppressWarnings("unused") Node ignored, } public static void internalInit(PBuffered self, PFileIO raw, int bufferSize, PythonLanguage language, - Object posixSupport, - PosixSupportLibrary posixLib) { + PosixSupport posixSupport) { self.setDetached(false); self.setRaw(raw, true); - BufferedInitNode.internalInit(self, bufferSize, language, posixSupport, posixLib); + BufferedInitNode.internalInit(self, bufferSize, language, posixSupport); self.resetWrite(); self.setPos(0); self.setOK(true); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index e246e5bfb1..13a75ae83b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -430,7 +430,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object try { gil.release(true); try { - long res = posixLib.lseek(context.getPosixSupport(), self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_END)); + long res = context.getPosixSupport().lseek(self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_END)); self.setSeekable(res >= 0 ? 1 : 0); } finally { gil.acquire(); @@ -562,7 +562,6 @@ static Object readall(VirtualFrame frame, PFileIO self, @Cached InlinedBranchProfile readErrorProfile, @Cached SequenceStorageNodes.GetInternalByteArrayNode getBytes, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile multipleReadsProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -571,7 +570,7 @@ static Object readall(VirtualFrame frame, PFileIO self, boolean mayBeQuick = false; try { PosixSupport posixSupport = PosixSupport.get(inliningTarget); - long pos = posixLib.lseek(posixSupport, self.getFD(), 0L, mapPythonSeekWhenceToPosix(SEEK_CUR)); + long pos = posixSupport.lseek(self.getFD(), 0L, mapPythonSeekWhenceToPosix(SEEK_CUR)); long[] status = posixSupport.fstat(self.getFD()); long end = status[6]; // TODO: st_size if (end > 0 && end >= pos && pos >= 0 && end - pos < MAX_SIZE) { @@ -762,13 +761,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization(guards = "!self.isClosed()") Object seek(VirtualFrame frame, PFileIO self, long pos, int whence, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { gil.release(true); try { - return internalSeek(self, pos, whence, getPosixSupport(), posixLib); + return internalSeek(self, pos, whence, getPosixSupport()); } finally { gil.acquire(); } @@ -784,10 +782,9 @@ static Object closedError(@SuppressWarnings("unused") PFileIO self, @SuppressWar } protected static long internalSeek(PFileIO self, long pos, int whence, - Object posixSupport, - PosixSupportLibrary posixLib) throws PosixException { + PosixSupport posixSupport) throws PosixException { try { - long res = posixLib.lseek(posixSupport, self.getFD(), pos, mapPythonSeekWhenceToPosix(whence)); + long res = posixSupport.lseek(self.getFD(), pos, mapPythonSeekWhenceToPosix(whence)); if (self.getSeekable() < 0) { self.setSeekable(1); } @@ -810,9 +807,8 @@ static Object tell(VirtualFrame frame, PFileIO self, } static long internalTell(PFileIO self, - Object posixSupport, - PosixSupportLibrary posixLib) throws PosixException { - return SeekNode.internalSeek(self, 0, SEEK_CUR, posixSupport, posixLib); + PosixSupport posixSupport) throws PosixException { + return SeekNode.internalSeek(self, 0, SEEK_CUR, posixSupport); } } @@ -871,10 +867,9 @@ protected static boolean isUnknown(PFileIO self) { } @Specialization(guards = {"!self.isClosed()", "isUnknown(self)"}) - Object unknown(PFileIO self, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { + Object unknown(PFileIO self) { try { - posixLib.lseek(getPosixSupport(), self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_CUR)); + getPosixSupport().lseek(self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_CUR)); self.setSeekable(1); return true; } catch (PosixException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index c0c18e1003..c78f0606fa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -858,17 +858,14 @@ private static int pollFlag(PosixConstants.IntConstant constant) { return constant.defined ? constant.getValueIfDefined() : 0; } - @ExportMessage - public long lseek(int fd, long offset, int how, - @Bind Node inliningTarget, - @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile noFile, - @Exclusive @Cached InlinedConditionProfile notSeekable) throws PosixException { + @Override + @TruffleBoundary + public long lseek(int fd, long offset, int how) throws PosixException { Channel channel = getFileChannel(fd); - if (noFile.profile(inliningTarget, channel == null)) { + if (channel == null) { throw posixException(OSErrorEnum.EBADF); } - if (notSeekable.profile(inliningTarget, !(channel instanceof SeekableByteChannel))) { + if (!(channel instanceof SeekableByteChannel)) { throw posixException(OSErrorEnum.ESPIPE); } if (SEEK_DATA.defined && how == SEEK_DATA.getValueIfDefined()) { @@ -882,7 +879,6 @@ public long lseek(int fd, long offset, int how, try { newPos = setPosition(offset, how, fc); } catch (Exception e) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } return newPos; @@ -910,24 +906,20 @@ private static long setPosition(long pos, int how, SeekableByteChannel fc) throw return fc.position(); } - @ExportMessage(name = "ftruncate") - public void ftruncateMessage(int fd, long length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { - // TODO: will merge with super.ftruncate once the super class is merged with this class + @Override + public void ftruncate(int fd, long length) throws PosixException { Object ret; try { - ret = ftruncate(fd, length); + ret = ftruncateResource(fd, length); } catch (Exception e) { throw posixException(OSErrorEnum.fromException(e)); } if (ret == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } } - @ExportMessage + @Override public void truncate(Object path, long length) throws PosixException { TruffleFile file = getTruffleFile(pathToJavaString(path)); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index d1dd69e36a..a057c69c20 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -319,34 +319,31 @@ public final void poll(int[] fds, int[] events, int[] revents, int timeout) thro } } - @ExportMessage - final long lseek(int fd, long offset, int how, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final long lseek(int fd, long offset, int how) throws PosixException { logEnter("lseek", "%d, %d, %d", fd, offset, how); try { - return logExit("lseek", "%d", lib.lseek(delegate, fd, offset, how)); + return logExit("lseek", "%d", delegate.lseek(fd, offset, how)); } catch (PosixException e) { throw logException("lseek", e); } } - @ExportMessage - final void ftruncate(int fd, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void ftruncate(int fd, long length) throws PosixException { logEnter("ftruncate", "%d, %d", fd, length); try { - lib.ftruncate(delegate, fd, length); + delegate.ftruncate(fd, length); } catch (PosixException e) { throw logException("ftruncate", e); } } - @ExportMessage - final void truncate(Object path, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void truncate(Object path, long length) throws PosixException { logEnter("truncate", "%s, %d", path, length); try { - lib.truncate(delegate, path, length); + delegate.truncate(path, length); } catch (PosixException e) { throw logException("truncate", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index ec57a44b2e..4b9dfb4092 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1007,7 +1007,7 @@ public void poll(int[] fds, int[] events, int[] revents, int timeout) throws Pos } } - @ExportMessage + @Override public long lseek(int fd, long offset, int how) throws PosixException { long res = posixNativeFunctionInvoker.call_lseek(fd, offset, how); if (res < 0) { @@ -1016,7 +1016,7 @@ public long lseek(int fd, long offset, int how) throws PosixException { return res; } - @ExportMessage + @Override public void ftruncate(int fd, long length) throws PosixException { int res = posixNativeFunctionInvoker.call_ftruncate(fd, length); if (res != 0) { @@ -1024,7 +1024,7 @@ public void ftruncate(int fd, long length) throws PosixException { } } - @ExportMessage + @Override public void truncate(Object path, long length) throws PosixException { long pathPtr = pathToNativeCString(path); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java index 6c44f6c362..f545a1eb9c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java @@ -408,7 +408,7 @@ public boolean fsync(int fd) { } @TruffleBoundary - public Object ftruncate(int fd, long size) throws IOException { + public Object ftruncateResource(int fd, long size) throws IOException { Channel channel = getFileChannel(fd); if (channel instanceof SeekableByteChannel) { return ((SeekableByteChannel) channel).truncate(size); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index e48fac10e6..dc4f7a195c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -89,6 +89,12 @@ public static PosixSupport get(Node node) { public abstract void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException; + public abstract long lseek(int fd, long offset, int how) throws PosixException; + + public abstract void ftruncate(int fd, long length) throws PosixException; + + public abstract void truncate(Object path, long length) throws PosixException; + public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 38903c10f2..ca6f26af22 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,12 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract long lseek(Object receiver, int fd, long offset, int how) throws PosixException; - - public abstract void ftruncate(Object receiver, int fd, long length) throws PosixException; - - public abstract void truncate(Object receiver, Object path, long length) throws PosixException; - public abstract void fsync(Object receiver, int fd) throws PosixException; public abstract void flock(Object receiver, int fd, int operation) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index daf2c40cc3..fa278d7021 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -291,27 +291,24 @@ public final void poll(int[] fds, int[] events, int[] revents, int timeout) thro nativePosixSupport.poll(fds, events, revents, timeout); } - @ExportMessage - final long lseek(int fd, long offset, int how, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final long lseek(int fd, long offset, int how) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().lseek(emulatedPosixSupport, fd, offset, how); + return emulatedPosixSupport.lseek(fd, offset, how); } - return nativeLib.lseek(nativePosixSupport, fd, offset, how); + return nativePosixSupport.lseek(fd, offset, how); } - @ExportMessage - final void ftruncate(int fd, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void ftruncate(int fd, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.ftruncate(nativePosixSupport, fd, length); + nativePosixSupport.ftruncate(fd, length); } - @ExportMessage - final void truncate(Object path, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void truncate(Object path, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.truncate(nativePosixSupport, path, length); + nativePosixSupport.truncate(path, length); } @ExportMessage From f29abc6b1b51f246b1b63a68b534baa99a8f3a72 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 14:41:06 +0200 Subject: [PATCH 029/129] Convert PosixSupportLibrary synchronization and locking operations (cherry picked from commit 09d8a120678c83a329aabcc5f08f892518889099) --- .../builtins/modules/FcntlModuleBuiltins.java | 6 ++--- .../builtins/modules/PosixModuleBuiltins.java | 3 +-- .../python/runtime/EmulatedPosixSupport.java | 22 ++++++------------- .../python/runtime/LoggingPosixSupport.java | 21 ++++++++---------- .../python/runtime/NativePosixSupport.java | 10 ++++----- .../graal/python/runtime/PosixResources.java | 2 +- .../graal/python/runtime/PosixSupport.java | 6 +++++ .../python/runtime/PosixSupportLibrary.java | 6 ----- .../python/runtime/PreInitPosixSupport.java | 21 ++++++++---------- 9 files changed, 40 insertions(+), 57 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java index caca032aba..68d542c33b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java @@ -135,11 +135,10 @@ protected ArgumentClinicProvider getArgumentClinic() { synchronized PNone flock(VirtualFrame frame, int fd, int operation, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posix, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_FCNTL_FLOCK, fd, operation); try { - posix.flock(getPosixSupport(), fd, operation); + getPosixSupport().flock(fd, operation); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -157,7 +156,6 @@ abstract static class LockfNode extends PythonClinicBuiltinNode { PNone lockf(VirtualFrame frame, int fd, int code, Object lenObj, Object startObj, int whence, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posix, @Cached PyLongAsLongNode asLongNode, @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -181,7 +179,7 @@ PNone lockf(VirtualFrame frame, int fd, int code, Object lenObj, Object startObj len = asLongNode.execute(frame, inliningTarget, lenObj); } try { - posix.fcntlLock(getPosixSupport(), fd, (code & LOCK_NB.value) == 0, lockType, whence, start, len); + getPosixSupport().fcntlLock(fd, (code & LOCK_NB.value) == 0, lockType, whence, start, len); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 3dd84928af..ad0d3129ce 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1337,12 +1337,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone fsync(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { while (true) { try { - posixLib.fsync(context.getPosixSupport(), fd); + context.getPosixSupport().fsync(fd); return PNone.NONE; } catch (PosixException e) { errorProfile.enter(inliningTarget); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index c78f0606fa..800e864ada 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -936,20 +936,17 @@ private static void doTruncate(TruffleFile file, long length) throws IOException } } - @ExportMessage(name = "fsync") - public void fsyncMessage(int fd) throws PosixException { - if (!fsync(fd)) { + @Override + public void fsync(int fd) throws PosixException { + if (!hasFsyncResource(fd)) { throw posixException(OSErrorEnum.ENOENT); } } - @ExportMessage - void flock(int fd, int operation, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + public void flock(int fd, int operation) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADFD); } boolean unlock = operation == LOCK_UN.value; @@ -957,26 +954,21 @@ void flock(int fd, int operation, boolean exclusive = (operation & LOCK_EX.value) != 0; boolean blocking = (operation & LOCK_NB.value) == 0; if (!unlock && !shared && !exclusive) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EINVAL); } doLockOperation(fd, channel, unlock, shared, blocking, 0, 0, Long.MAX_VALUE); } - @ExportMessage - void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADFD); } boolean unlock = lockType == F_UNLCK.getValueIfDefined(); boolean shared = lockType == F_RDLCK.getValueIfDefined(); boolean exclusive = lockType == F_WRLCK.getValueIfDefined(); if (!unlock && !shared && !exclusive) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EINVAL); } doLockOperation(fd, channel, unlock, shared, blocking, whence, start, length); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index a057c69c20..53980f17a1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -349,34 +349,31 @@ public final void truncate(Object path, long length) throws PosixException { } } - @ExportMessage - final void fsync(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void fsync(int fd) throws PosixException { logEnter("fsync", "%d", fd); try { - lib.fsync(delegate, fd); + delegate.fsync(fd); } catch (PosixException e) { throw logException("fsync", e); } } - @ExportMessage - final void flock(int fd, int operation, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void flock(int fd, int operation) throws PosixException { logEnter("flock", "%d %d", fd, operation); try { - lib.flock(delegate, fd, operation); + delegate.flock(fd, operation); } catch (PosixException e) { throw logException("flock", e); } } - @ExportMessage - final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { logEnter("fcntlLock", "%d %s %d %d %d %d", fd, blocking, lockType, whence, start, length); try { - lib.fcntlLock(delegate, fd, blocking, lockType, whence, start, length); + delegate.fcntlLock(fd, blocking, lockType, whence, start, length); } catch (PosixException e) { throw logException("fcntlLock", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 4b9dfb4092..aad1a78e6c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1037,7 +1037,7 @@ public void truncate(Object path, long length) throws PosixException { } } - @ExportMessage + @Override public void fsync(int fd) throws PosixException { int res = posixNativeFunctionInvoker.call_fsync(fd); if (res != 0) { @@ -1045,16 +1045,16 @@ public void fsync(int fd) throws PosixException { } } - @ExportMessage - void flock(int fd, int operation) throws PosixException { + @Override + public void flock(int fd, int operation) throws PosixException { int res = posixNativeFunctionInvoker.call_flock(fd, operation); if (res != 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage - void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { + @Override + public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { int res = posixNativeFunctionInvoker.call_fcntl_lock(fd, blocking ? 1 : 0, lockType, whence, start, length); if (res != 0) { throw getErrnoAndThrowPosixException(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java index f545a1eb9c..74cb436a51 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java @@ -403,7 +403,7 @@ public int dup2(int fd, int fd2) throws IOException { } @TruffleBoundary - public boolean fsync(int fd) { + public boolean hasFsyncResource(int fd) { return files.getOrDefault(fd, null) != null; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index dc4f7a195c..26b7869bb3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -95,6 +95,12 @@ public static PosixSupport get(Node node) { public abstract void truncate(Object path, long length) throws PosixException; + public abstract void fsync(int fd) throws PosixException; + + public abstract void flock(int fd, int operation) throws PosixException; + + public abstract void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException; + public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index ca6f26af22..443a815c81 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,12 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract void fsync(Object receiver, int fd) throws PosixException; - - public abstract void flock(Object receiver, int fd, int operation) throws PosixException; - - public abstract void fcntlLock(Object receiver, int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException; - public abstract boolean getBlocking(Object receiver, int fd) throws PosixException; public abstract void setBlocking(Object receiver, int fd, boolean blocking) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index fa278d7021..e99d9d7d86 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -311,25 +311,22 @@ public final void truncate(Object path, long length) throws PosixException { nativePosixSupport.truncate(path, length); } - @ExportMessage - final void fsync(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void fsync(int fd) throws PosixException { checkNotInPreInitialization(); - nativeLib.fsync(nativePosixSupport, fd); + nativePosixSupport.fsync(fd); } - @ExportMessage - final void flock(int fd, int operation, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void flock(int fd, int operation) throws PosixException { checkNotInPreInitialization(); - nativeLib.flock(nativePosixSupport, fd, operation); + nativePosixSupport.flock(fd, operation); } - @ExportMessage - final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.fcntlLock(nativePosixSupport, fd, blocking, lockType, whence, start, length); + nativePosixSupport.fcntlLock(fd, blocking, lockType, whence, start, length); } @ExportMessage From 89bac6d98e4c626f5292ce38613f55cdb7ad2e84 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 14:51:49 +0200 Subject: [PATCH 030/129] Convert PosixSupportLibrary descriptor modes and terminal size (cherry picked from commit a4dd588cd01d861c9e85d4b374ebdc830c3865c2) --- .../oracle/graal/python/test/SocketTests.java | 4 +- .../builtins/modules/PosixModuleBuiltins.java | 9 ++-- .../objects/socket/SocketBuiltins.java | 8 ++-- .../python/runtime/EmulatedPosixSupport.java | 46 +++++-------------- .../python/runtime/LoggingPosixSupport.java | 21 ++++----- .../python/runtime/NativePosixSupport.java | 6 +-- .../graal/python/runtime/PosixSupport.java | 6 +++ .../python/runtime/PosixSupportLibrary.java | 6 --- .../python/runtime/PreInitPosixSupport.java | 21 ++++----- 9 files changed, 47 insertions(+), 80 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index d80500fb5f..de5aa2ed1d 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -1249,11 +1249,11 @@ void shutdown(int how) throws PosixException { } void setBlocking(boolean block) throws PosixException { - lib.setBlocking(posixSupport, fd, block); + posixSupport.setBlocking(fd, block); } boolean getBlocking() throws PosixException { - return lib.getBlocking(posixSupport, fd); + return posixSupport.getBlocking(fd); } FamilySpecificSockAddr address() throws PosixException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index ad0d3129ce..04ec6f1cdb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1369,10 +1369,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static boolean getBlocking(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getBlocking(context.getPosixSupport(), fd); + return context.getPosixSupport().getBlocking(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1394,10 +1393,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone setBlocking(VirtualFrame frame, int fd, boolean blocking, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setBlocking(context.getPosixSupport(), fd, blocking); + context.getPosixSupport().setBlocking(fd, blocking); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1419,11 +1417,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple getTerminalSize(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // TODO default value should be fileno(stdout) try { - int[] result = posixLib.getTerminalSize(context.getPosixSupport(), fd); + int[] result = context.getPosixSupport().getTerminalSize(fd); return PFactory.createStructSeq(context.getLanguage(inliningTarget), TERMINAL_SIZE_DESC, result[0], result[1]); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index 99ff23ce8c..3088eaed71 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -277,7 +277,7 @@ private static void sockInit(PythonContext context, PosixSupportLibrary posixLib long defaultTimeout = context.lookupBuiltinModule(T__SOCKET).getModuleState(Long.class); self.setTimeoutNs(defaultTimeout); if (defaultTimeout >= 0) { - posixLib.setBlocking(context.getPosixSupport(), fd, false); + context.getPosixSupport().setBlocking(fd, false); } } @@ -1006,10 +1006,9 @@ public abstract static class SetBlockingNode extends PythonBinaryClinicBuiltinNo static PNone doBoolean(VirtualFrame frame, PSocket socket, boolean blocking, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setBlocking(context.getPosixSupport(), socket.getFd(), blocking); + context.getPosixSupport().setBlocking(socket.getFd(), blocking); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1031,13 +1030,12 @@ abstract static class SetTimeoutNode extends PythonBinaryBuiltinNode { static Object setTimeout(VirtualFrame frame, PSocket socket, Object seconds, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.ParseTimeoutNode parseTimeoutNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long timeout = parseTimeoutNode.execute(frame, inliningTarget, seconds); socket.setTimeoutNs(timeout); try { - posixLib.setBlocking(context.getPosixSupport(), socket.getFd(), timeout < 0); + context.getPosixSupport().setBlocking(socket.getFd(), timeout < 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 800e864ada..93e3296050 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -1022,18 +1022,19 @@ private void doLockOperation(int fd, Channel channel, boolean unlock, boolean sh } } - @ExportMessage + @Override + @TruffleBoundary public boolean getBlocking(int fd) throws PosixException { Channel channel = getChannel(fd); if (channel == null) { throw posixException(OSErrorEnum.EBADF); } - if (channel instanceof EmulatedSocket) { - return getBlocking((EmulatedSocket) channel); + if (channel instanceof EmulatedSocket emulatedSocket) { + return emulatedSocket.isBlocking(); } Channel fileChannel = getFileChannel(fd); - if (fileChannel instanceof SelectableChannel) { - return getBlocking((SelectableChannel) fileChannel); + if (fileChannel instanceof SelectableChannel selectableChannel) { + return selectableChannel.isBlocking(); } if (fileChannel == null) { throw posixException(OSErrorEnum.EBADFD); @@ -1043,33 +1044,21 @@ public boolean getBlocking(int fd) throws PosixException { return true; } + @Override @TruffleBoundary - @Ignore - private static boolean getBlocking(SelectableChannel channel) { - return channel.isBlocking(); - } - - @TruffleBoundary - @Ignore - private static boolean getBlocking(EmulatedSocket socket) { - return socket.isBlocking(); - } - - @ExportMessage - @SuppressWarnings({"static-method", "unused"}) public void setBlocking(int fd, boolean blocking) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { throw new UnsupportedPosixFeatureException("setBlocking was excluded"); } try { Channel channel = getChannel(fd); - if (channel instanceof EmulatedSocket) { - setBlocking((EmulatedSocket) channel, blocking); + if (channel instanceof EmulatedSocket emulatedSocket) { + emulatedSocket.configureBlocking(blocking); return; } Channel fileChannel = getFileChannel(fd); - if (fileChannel instanceof SelectableChannel) { - setBlocking((SelectableChannel) fileChannel, blocking); + if (fileChannel instanceof SelectableChannel selectableChannel) { + selectableChannel.configureBlocking(blocking); } else if (fileChannel != null) { if (blocking) { // Already blocking @@ -1086,19 +1075,8 @@ public void setBlocking(int fd, boolean blocking) throws PosixException { throw posixException(OSErrorEnum.EBADFD); } + @Override @TruffleBoundary - @Ignore - private static void setBlocking(SelectableChannel channel, boolean block) throws IOException { - channel.configureBlocking(block); - } - - @TruffleBoundary - @Ignore - private static void setBlocking(EmulatedSocket socket, boolean block) throws IOException { - socket.configureBlocking(block); - } - - @ExportMessage public int[] getTerminalSize(int fd) throws PosixException { if (getFileChannel(fd) == null) { throw posixException(OSErrorEnum.EBADF); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 53980f17a1..711ead2d31 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -379,34 +379,31 @@ public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, } } - @ExportMessage - final boolean getBlocking(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final boolean getBlocking(int fd) throws PosixException { logEnter("getBlocking", "%d", fd); try { - return logExit("getBlocking", "%b", lib.getBlocking(delegate, fd)); + return logExit("getBlocking", "%b", delegate.getBlocking(fd)); } catch (PosixException e) { throw logException("getBlocking", e); } } - @ExportMessage - final void setBlocking(int fd, boolean blocking, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final void setBlocking(int fd, boolean blocking) throws PosixException { logEnter("setBlocking", "%d, %b", fd, blocking); try { - lib.setBlocking(delegate, fd, blocking); + delegate.setBlocking(fd, blocking); } catch (PosixException e) { throw logException("setBlocking", e); } } - @ExportMessage - final int[] getTerminalSize(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final int[] getTerminalSize(int fd) throws PosixException { logEnter("getTerminalSize", "%d", fd); try { - return logExit("getTerminalSize", "%s", lib.getTerminalSize(delegate, fd)); + return logExit("getTerminalSize", "%s", delegate.getTerminalSize(fd)); } catch (PosixException e) { throw logException("getTerminalSize", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index aad1a78e6c..7a00bf7ca9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1061,7 +1061,7 @@ public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long s } } - @ExportMessage + @Override public boolean getBlocking(int fd) throws PosixException { int result = posixNativeFunctionInvoker.get_blocking(fd); if (result < 0) { @@ -1070,14 +1070,14 @@ public boolean getBlocking(int fd) throws PosixException { return result != 0; } - @ExportMessage + @Override public void setBlocking(int fd, boolean blocking) throws PosixException { if (posixNativeFunctionInvoker.set_blocking(fd, blocking ? 1 : 0) < 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage + @Override public int[] getTerminalSize(int fd) throws PosixException { int[] size = new int[2]; long nativeSize = NativeMemory.mallocIntArray(size.length); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 26b7869bb3..839cdcdb15 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -101,6 +101,12 @@ public static PosixSupport get(Node node) { public abstract void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException; + public abstract boolean getBlocking(int fd) throws PosixException; + + public abstract void setBlocking(int fd, boolean blocking) throws PosixException; + + public abstract int[] getTerminalSize(int fd) throws PosixException; + public abstract Buffer read(int fd, long length) throws PosixException; public abstract long write(int fd, Buffer data) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 443a815c81..abf8c9779c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,12 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract boolean getBlocking(Object receiver, int fd) throws PosixException; - - public abstract void setBlocking(Object receiver, int fd, boolean blocking) throws PosixException; - - public abstract int[] getTerminalSize(Object receiver, int fd) throws PosixException; - public abstract long sysconf(Object receiver, int name) throws PosixException; public abstract Object[] uname(Object receiver) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index e99d9d7d86..0017dae717 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -329,25 +329,22 @@ public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, nativePosixSupport.fcntlLock(fd, blocking, lockType, whence, start, length); } - @ExportMessage - final boolean getBlocking(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final boolean getBlocking(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getBlocking(nativePosixSupport, fd); + return nativePosixSupport.getBlocking(fd); } - @ExportMessage - final void setBlocking(int fd, boolean blocking, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final void setBlocking(int fd, boolean blocking) throws PosixException { checkNotInPreInitialization(); - nativeLib.setBlocking(nativePosixSupport, fd, blocking); + nativePosixSupport.setBlocking(fd, blocking); } - @ExportMessage - final int[] getTerminalSize(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final int[] getTerminalSize(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getTerminalSize(nativePosixSupport, fd); + return nativePosixSupport.getTerminalSize(fd); } @ExportMessage From 6391368bda3376dee7e2121bada249d43aa93a25 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 14:57:08 +0200 Subject: [PATCH 031/129] Convert PosixSupportLibrary system information operations (cherry picked from commit ff0c9aedede28128f2ff409f828c8e1f74457ce4) --- .../oracle/graal/python/PythonLanguage.java | 5 ++-- .../builtins/modules/PosixModuleBuiltins.java | 6 ++--- .../builtins/modules/SysModuleBuiltins.java | 2 +- .../python/runtime/EmulatedPosixSupport.java | 17 ++++++-------- .../python/runtime/LoggingPosixSupport.java | 23 ++++++++----------- .../python/runtime/NativePosixSupport.java | 21 ++++++++--------- .../graal/python/runtime/PosixSupport.java | 12 ++++++++++ .../python/runtime/PosixSupportLibrary.java | 12 ---------- .../python/runtime/PreInitPosixSupport.java | 21 ++++++++--------- 9 files changed, 53 insertions(+), 66 deletions(-) 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 aa23d8192e..8e73ecbfae 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 @@ -103,9 +103,8 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport.WindowsVersion; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.PythonThreadState; import com.oracle.graal.python.runtime.PythonImageBuildOptions; @@ -1075,7 +1074,7 @@ public WindowsVersion getWindowsVersion(Node node) { CompilerDirectives.transferToInterpreterAndInvalidate(); assert !ImageInfo.inImageBuildtimeCode(); try { - windowsVersion = PosixSupportLibrary.getUncached().getWindowsVersion(PythonContext.get(node).getPosixSupport()); + windowsVersion = PythonContext.get(node).getPosixSupport().getWindowsVersion(); } catch (PosixException e) { EncapsulatingNodeReference encapsulating = EncapsulatingNodeReference.getCurrent(); Node previousNode = encapsulating.set(node); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 04ec6f1cdb..1c54788a1b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1621,10 +1621,9 @@ abstract static class UnameNode extends PythonBuiltinNode { static PTuple uname(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return PFactory.createStructSeq(context.getLanguage(inliningTarget), UNAME_RESULT_DESC, posixLib.uname(context.getPosixSupport())); + return PFactory.createStructSeq(context.getLanguage(inliningTarget), UNAME_RESULT_DESC, context.getPosixSupport().uname()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -2985,7 +2984,6 @@ static long sysconf(VirtualFrame frame, PythonModule self, Object arg, @Cached PyObjectGetItem getItem, @Cached PRaiseNode raiseNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int id; if (longCheckNode.execute(inliningTarget, arg)) { @@ -3002,7 +3000,7 @@ static long sysconf(VirtualFrame frame, PythonModule self, Object arg, throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.CONFIGURATION_NAMES_MUST_BE_STRINGS_OR_INTEGERS); } try { - return posixLib.sysconf(context.getPosixSupport(), id); + return context.getPosixSupport().sysconf(id); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index 40b597135c..909f0b0685 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -257,7 +257,7 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; +import com.oracle.graal.python.runtime.PosixSupport.WindowsVersion; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.CApiState; import com.oracle.graal.python.runtime.PythonImageBuildOptions; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 93e3296050..4e8400b316 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -250,7 +250,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; import com.oracle.graal.python.runtime.exception.PythonExitException; import com.oracle.graal.python.util.FileDeleteShutdownHook; import com.oracle.graal.python.util.IPAddressUtil; @@ -1084,7 +1083,7 @@ public int[] getTerminalSize(int fd) throws PosixException { return new int[]{context.getOption(PythonOptions.TerminalWidth), context.getOption(PythonOptions.TerminalHeight)}; } - @ExportMessage + @Override @TruffleBoundary public long sysconf(int name) throws PosixException { // Constants derived from POSIX specs or common kernel configs @@ -1426,22 +1425,20 @@ private static int posixPermissionsToMode(int inputMode, final Set Date: Wed, 30 Sep 2026 15:03:56 +0200 Subject: [PATCH 032/129] Convert PosixSupportLibrary path namespace operations (cherry picked from commit ae199352a36fd2f4da7f903e99a5d5144b210659) --- .../builtins/modules/PosixModuleBuiltins.java | 17 +++----- .../python/runtime/EmulatedPosixSupport.java | 35 +++++++---------- .../python/runtime/LoggingPosixSupport.java | 39 +++++++++---------- .../python/runtime/NativePosixSupport.java | 14 ++++--- .../graal/python/runtime/PosixSupport.java | 10 +++++ .../python/runtime/PosixSupportLibrary.java | 10 ----- .../python/runtime/PreInitPosixSupport.java | 39 +++++++++---------- 7 files changed, 76 insertions(+), 88 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 1c54788a1b..d0376f2f0c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1644,13 +1644,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone unlink(VirtualFrame frame, PosixPath path, int dirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_REMOVE, path.originalObject, dirFdForAudit(dirFd)); try { - posixLib.unlinkat(context.getPosixSupport(), dirFd, path.value, false); + context.getPosixSupport().unlinkat(dirFd, path.value, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1691,10 +1690,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone link(VirtualFrame frame, PosixPath src, PosixPath dst, int srcDirFd, int dstDirFd, boolean followSymlinks, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.linkat(context.getPosixSupport(), srcDirFd, src.value, dstDirFd, dst.value, followSymlinks ? AT_SYMLINK_FOLLOW.value : 0); + context.getPosixSupport().linkat(srcDirFd, src.value, dstDirFd, dst.value, followSymlinks ? AT_SYMLINK_FOLLOW.value : 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } @@ -1719,10 +1717,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone symlink(VirtualFrame frame, PosixPath src, PosixPath dst, @SuppressWarnings("unused") boolean targetIsDir, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.symlinkat(context.getPosixSupport(), src.value, dirFd, dst.value); + context.getPosixSupport().symlinkat(src.value, dirFd, dst.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } @@ -1745,13 +1742,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone mkdir(VirtualFrame frame, PosixPath path, int mode, int dirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_MKDIR, path.originalObject, mode, dirFdForAudit(dirFd)); try { - posixLib.mkdirat(context.getPosixSupport(), dirFd, path.value, mode); + context.getPosixSupport().mkdirat(dirFd, path.value, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1773,13 +1769,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone rmdir(VirtualFrame frame, PosixPath path, int dirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_RMDIR, path.originalObject, dirFdForAudit(dirFd)); try { - posixLib.unlinkat(context.getPosixSupport(), dirFd, path.value, true); + context.getPosixSupport().unlinkat(dirFd, path.value, true); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -2610,7 +2605,7 @@ static Object readlinkAsBytes(VirtualFrame frame, PosixPath path, int dirFd, @Cached InlinedConditionProfile wasBufferLikeProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object link = posixLib.readlinkat(context.getPosixSupport(), dirFd, path.value); + Object link = context.getPosixSupport().readlinkat(dirFd, path.value); if (wasBufferLikeProfile.profile(inliningTarget, path.wasBufferLike)) { return opaquePathToBytes(link, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 4e8400b316..defc3fba29 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -1487,31 +1487,27 @@ private static String getHostName(boolean withoutSocket) { } } - @ExportMessage - public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean rmdir, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void unlinkat(int dirFd, Object path, @SuppressWarnings("unused") boolean rmdir) throws PosixException { TruffleFile f = resolvePath(dirFd, pathToJavaString(path)); if (f.exists(LinkOption.NOFOLLOW_LINKS)) { // we cannot check this if the file does not exist boolean isDirectory = f.isDirectory(LinkOption.NOFOLLOW_LINKS); if (isDirectory != rmdir) { - errorBranch.enter(inliningTarget); throw posixException(isDirectory ? OSErrorEnum.EISDIR : OSErrorEnum.ENOTDIR); } } try { f.delete(); } catch (Exception e) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage - public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { TruffleFile srcFile = resolvePath(oldFdDir, pathToJavaString(oldPath)); TruffleFile dstFile = resolvePath(newFdDir, pathToJavaString(newPath)); try { @@ -1520,34 +1516,29 @@ public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, i } srcFile.createLink(dstFile); } catch (Exception e) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage - public void symlinkat(Object target, int linkDirFd, Object link, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void symlinkat(Object target, int linkDirFd, Object link) throws PosixException { TruffleFile linkFile = resolvePath(linkDirFd, pathToJavaString(link)); TruffleFile targetFile = getTruffleFile(pathToJavaString(target)); try { linkFile.createSymbolicLink(targetFile); } catch (Exception e) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage - public void mkdirat(int dirFd, Object path, int mode, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void mkdirat(int dirFd, Object path, int mode) throws PosixException { TruffleFile linkFile = resolvePath(dirFd, pathToJavaString(path)); try { linkFile.createDirectory(); } catch (Exception e) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } @@ -1989,7 +1980,7 @@ public void fchown(int fd, long owner, long group) throws PosixException { throw createUnsupportedFeature("fchown"); } - @ExportMessage + @Override public Object readlinkat(int dirFd, Object path) throws PosixException { TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index faef2eee12..40a2cfc0a2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -483,45 +483,45 @@ public final WindowsVersion getWindowsVersion() throws PosixException { } } - @ExportMessage - final void unlinkat(int dirFd, Object pathname, boolean rmdir, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException { logEnter("unlinkAt", "%d, %s, %b", dirFd, pathname, rmdir); try { - lib.unlinkat(delegate, dirFd, pathname, rmdir); + delegate.unlinkat(dirFd, pathname, rmdir); } catch (PosixException e) { throw logException("unlinkAt", e); } } - @ExportMessage - final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { logEnter("linkAt", "%d, %s, %d, %s, %d", oldFdDir, oldPath, newFdDir, newPath, flags); try { - lib.linkat(delegate, oldFdDir, oldPath, newFdDir, newPath, flags); + delegate.linkat(oldFdDir, oldPath, newFdDir, newPath, flags); } catch (PosixException e) { throw logException("symlinkAt", e); } } - @ExportMessage - final void symlinkat(Object target, int linkpathDirFd, Object linkpath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException { logEnter("symlinkAt", "%s, %d, %s", target, linkpathDirFd, linkpath); try { - lib.symlinkat(delegate, target, linkpathDirFd, linkpath); + delegate.symlinkat(target, linkpathDirFd, linkpath); } catch (PosixException e) { throw logException("symlinkAt", e); } } - @ExportMessage - final void mkdirat(int dirFd, Object pathname, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void mkdirat(int dirFd, Object pathname, int mode) throws PosixException { logEnter("mkdirAt", "%d, %s, 0%o", dirFd, pathname, mode); try { - lib.mkdirat(delegate, dirFd, pathname, mode); + delegate.mkdirat(dirFd, pathname, mode); } catch (PosixException e) { throw logException("mkdirAt", e); } @@ -790,12 +790,11 @@ final void fchown(int fd, long owner, long group, } } - @ExportMessage - final Object readlinkat(int dirFd, Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + public final Object readlinkat(int dirFd, Object path) throws PosixException { logEnter("readlinkat", "%d, %s", dirFd, path); try { - return logExit("readlinkat", "%s", lib.readlinkat(delegate, dirFd, path)); + return logExit("readlinkat", "%s", delegate.readlinkat(dirFd, path)); } catch (PosixException e) { throw logException("readlinkat", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 724f369a7b..3732862f17 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1231,7 +1231,8 @@ public WindowsVersion getWindowsVersion() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException { long pathnamePtr = pathToNativeCString(pathname); try { @@ -1244,7 +1245,8 @@ public void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixExce } } - @ExportMessage + @Override + @TruffleBoundary public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { long oldPathPtr = NULLPTR; long newPathPtr = NULLPTR; @@ -1261,7 +1263,8 @@ public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, i } } - @ExportMessage + @Override + @TruffleBoundary public void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException { long targetPtr = NULLPTR; long linkpathPtr = NULLPTR; @@ -1278,7 +1281,8 @@ public void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws } } - @ExportMessage + @Override + @TruffleBoundary public void mkdirat(int dirFd, Object pathname, int mode) throws PosixException { long pathnamePtr = pathToNativeCString(pathname); try { @@ -1646,7 +1650,7 @@ public void fchown(int fd, long owner, long group) throws PosixException { } } - @ExportMessage + @Override public Object readlinkat(int dirFd, Object path) throws PosixException { int bufferBytes = WINDOWS ? PATH_MAX.value * 2 : PATH_MAX.value; byte[] buffer = new byte[bufferBytes]; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 361e792c93..2210dac89e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -152,4 +152,14 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf /** Returns the Windows version and product information. */ public abstract WindowsVersion getWindowsVersion() throws PosixException; + + public abstract void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException; + + public abstract void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException; + + public abstract void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException; + + public abstract void mkdirat(int dirFd, Object pathname, int mode) throws PosixException; + + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 9260e65a70..6cbcba46df 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,14 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract void unlinkat(Object receiver, int dirFd, Object pathname, boolean rmdir) throws PosixException; - - public abstract void linkat(Object receiver, int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException; - - public abstract void symlinkat(Object receiver, Object target, int linkpathDirFd, Object linkpath) throws PosixException; - - public abstract void mkdirat(Object receiver, int dirFd, Object pathname, int mode) throws PosixException; - public abstract Object getcwd(Object receiver) throws PosixException; public abstract void chdir(Object receiver, Object path) throws PosixException; @@ -188,8 +180,6 @@ public abstract class PosixSupportLibrary extends Library { public abstract void fchown(Object receiver, int fd, long owner, long group) throws PosixException; - public abstract Object readlinkat(Object receiver, int dirFd, Object path) throws PosixException; - public abstract void raise(Object receiver, int signal) throws PosixException; public abstract int alarm(Object receiver, int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index eb0eec3ae4..ed6f287607 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -397,32 +397,32 @@ public final WindowsVersion getWindowsVersion() throws PosixException { return nativePosixSupport.getWindowsVersion(); } - @ExportMessage - final void unlinkat(int dirFd, Object pathname, boolean rmdir, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException { checkNotInPreInitialization(); - nativeLib.unlinkat(nativePosixSupport, dirFd, pathname, rmdir); + nativePosixSupport.unlinkat(dirFd, pathname, rmdir); } - @ExportMessage - final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { checkNotInPreInitialization(); - nativeLib.linkat(nativePosixSupport, oldFdDir, oldPath, newFdDir, newPath, flags); + nativePosixSupport.linkat(oldFdDir, oldPath, newFdDir, newPath, flags); } - @ExportMessage - final void symlinkat(Object target, int linkpathDirFd, Object linkpath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException { checkNotInPreInitialization(); - nativeLib.symlinkat(nativePosixSupport, target, linkpathDirFd, linkpath); + nativePosixSupport.symlinkat(target, linkpathDirFd, linkpath); } - @ExportMessage - final void mkdirat(int dirFd, Object pathname, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mkdirat(int dirFd, Object pathname, int mode) throws PosixException { checkNotInPreInitialization(); - nativeLib.mkdirat(nativePosixSupport, dirFd, pathname, mode); + nativePosixSupport.mkdirat(dirFd, pathname, mode); } @ExportMessage @@ -610,11 +610,10 @@ final void fchown(int fd, long owner, long group, nativeLib.fchown(nativePosixSupport, fd, owner, group); } - @ExportMessage - final Object readlinkat(int dirFd, Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + public final Object readlinkat(int dirFd, Object path) throws PosixException { checkNotInPreInitialization(); - return nativeLib.readlinkat(nativePosixSupport, dirFd, path); + return nativePosixSupport.readlinkat(dirFd, path); } @ExportMessage From 9a11a241b91d0752f2931c79bf5aad7157e52542 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 15:10:59 +0200 Subject: [PATCH 033/129] Convert PosixSupportLibrary working directory and TTY operations (cherry picked from commit 54aadbd21b45e4e3b343c492c52392e3684d748e) --- .../builtins/modules/BuiltinFunctions.java | 3 +- .../builtins/modules/PosixModuleBuiltins.java | 18 ++++---- .../builtins/modules/io/FileIOBuiltins.java | 3 +- .../builtins/modules/io/IOModuleBuiltins.java | 11 ++--- .../python/runtime/EmulatedPosixSupport.java | 41 ++++++++----------- .../python/runtime/LoggingPosixSupport.java | 32 +++++++-------- .../python/runtime/NativePosixSupport.java | 12 ++++-- .../graal/python/runtime/PosixSupport.java | 8 ++++ .../python/runtime/PosixSupportLibrary.java | 15 ------- .../python/runtime/PreInitPosixSupport.java | 31 +++++++------- 10 files changed, 78 insertions(+), 96 deletions(-) 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 ae404df180..cd369906d2 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 @@ -269,7 +269,6 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -2481,7 +2480,7 @@ private static Object doInput(Object prompt, Node node, PythonContext context) { try { long fileno = PyLongAsLongNode.executeUncached(PyObjectCallMethodObjArgs.executeUncached(stdin, T_FILENO)); if (fileno == 0) { - tty = PosixSupportLibrary.getUncached().isatty(context.getPosixSupport(), 0); + tty = context.getPosixSupport().isatty(0); } } catch (AbstractTruffleException e) { // not a tty diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index d0376f2f0c..5e7f53811c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1792,7 +1792,7 @@ static TruffleString getcwd(VirtualFrame frame, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getPathAsString(context.getPosixSupport(), posixLib.getcwd(context.getPosixSupport())); + return posixLib.getPathAsString(context.getPosixSupport(), context.getPosixSupport().getcwd()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1809,7 +1809,7 @@ static PBytes getcwdb(VirtualFrame frame, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object path = posixLib.getcwd(context.getPosixSupport()); + Object path = context.getPosixSupport().getcwd(); return opaquePathToBytes(path, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -1831,10 +1831,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone chdirPath(VirtualFrame frame, PosixPath path, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.chdir(context.getPosixSupport(), path.value); + context.getPosixSupport().chdir(path.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1845,10 +1844,9 @@ static PNone chdirPath(VirtualFrame frame, PosixPath path, static PNone chdirFd(VirtualFrame frame, PosixFd fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.fchdir(context.getPosixSupport(), fd.fd); + context.getPosixSupport().fchdir(fd.fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd.originalObject); } @@ -1870,12 +1868,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone fchdir(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { while (true) { try { - posixLib.fchdir(context.getPosixSupport(), fd); + context.getPosixSupport().fchdir(fd); return PNone.NONE; } catch (PosixException e) { errorProfile.enter(inliningTarget); @@ -1902,11 +1899,10 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean isatty(int fd, @Cached GilNode gil, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { + @Bind PythonContext context) { gil.release(true); try { - return posixLib.isatty(context.getPosixSupport(), fd); + return context.getPosixSupport().isatty(fd); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index 13a75ae83b..75721e6bcb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -896,11 +896,10 @@ static Object closedError(@SuppressWarnings("unused") PFileIO self, abstract static class IsattyNode extends PythonUnaryBuiltinNode { @Specialization(guards = "!self.isClosed()") boolean isatty(@SuppressWarnings("unused") PFileIO self, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil) { gil.release(true); try { - return posixLib.isatty(getPosixSupport(), self.getFD()); + return getPosixSupport().isatty(self.getFD()); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java index f963de8106..19c15ef504 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java @@ -93,7 +93,6 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -107,7 +106,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -206,7 +204,6 @@ protected static Object openText(VirtualFrame frame, Object file, IONodes.IOMode @Exclusive @Cached IONodes.CreateBufferedIONode createBufferedIO, @Cached TextIOWrapperNodes.TextIOWrapperInitNode initTextIO, @Cached PyObjectSetAttr setAttrNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PyObjectCallMethodObjArgs callClose, @Bind PythonLanguage language, @Exclusive @Cached PRaiseNode raiseNode) { @@ -218,7 +215,7 @@ protected static Object openText(VirtualFrame frame, Object file, IONodes.IOMode int buffering = bufferingValue; if (buffering < 0) { // copied from PFileIOBuiltins.IsAttyNode - isatty = posixLib.isatty(PosixSupport.get(inliningTarget), fileIO.getFD()); + isatty = PosixSupport.get(inliningTarget).isatty(fileIO.getFD()); /*- // CPython way is slow in our case. Object res = libFileIO.lookupAndCallRegularMethod(fileIO, frame, ISATTY); @@ -292,11 +289,10 @@ protected static Object openBinaryB1(VirtualFrame frame, Object file, IONodes.IO @Exclusive @Cached PyNumberCheckNode numberCheckNode, @Exclusive @Cached PyOSFSPathNode fsPathNode, @Exclusive @Cached IONodes.CreateBufferedIONode createBufferedIO, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PyObjectCallMethodObjArgs callClose, @Exclusive @Cached PRaiseNode raiseNode) { warnNode.warnEx(frame, RuntimeWarning, LINE_BUFFERING_ISNT_SUPPORTED, 1); - return openBinary(frame, file, mode, bufferingValue, encoding, errors, newline, closefd, opener, inliningTarget, initFileIO, numberCheckNode, fsPathNode, createBufferedIO, posixLib, + return openBinary(frame, file, mode, bufferingValue, encoding, errors, newline, closefd, opener, inliningTarget, initFileIO, numberCheckNode, fsPathNode, createBufferedIO, callClose, raiseNode); } @@ -311,7 +307,6 @@ protected static Object openBinary(VirtualFrame frame, Object file, IONodes.IOMo @Exclusive @Cached PyNumberCheckNode numberCheckNode, @Exclusive @Cached PyOSFSPathNode fsPathNode, @Exclusive @Cached IONodes.CreateBufferedIONode createBufferedIO, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PyObjectCallMethodObjArgs callClose, @Exclusive @Cached PRaiseNode raiseNode) { PFileIO fileIO = createFileIOFromOpen(frame, inliningTarget, file, mode, closefd, opener, initFileIO, numberCheckNode, fsPathNode); @@ -321,7 +316,7 @@ protected static Object openBinary(VirtualFrame frame, Object file, IONodes.IOMo int buffering = bufferingValue; if (buffering < 0) { // copied from PFileIOBuiltins.IsAttyNode - isatty = posixLib.isatty(PosixSupport.get(inliningTarget), fileIO.getFD()); + isatty = PosixSupport.get(inliningTarget).isatty(fileIO.getFD()); /*- // CPython way is slow in our case. Object res = libFileIO.lookupAndCallRegularMethod(fileIO, frame, ISATTY); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index defc3fba29..dc776f408b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -255,6 +255,7 @@ import com.oracle.graal.python.util.IPAddressUtil; import com.oracle.graal.python.util.OverflowException; 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.TruffleFile; import com.oracle.truffle.api.TruffleFile.Attributes; @@ -1543,66 +1544,60 @@ public void mkdirat(int dirFd, Object path, int mode) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object getcwd() { return context.getEnv().getCurrentWorkingDirectory().toString(); } - @ExportMessage - public void chdir(Object path, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { - chdirStr(inliningTarget, pathToJavaString(path), errorBranch); + @Override + @TruffleBoundary + public void chdir(Object path) throws PosixException { + chdirStr(pathToJavaString(path)); } - @ExportMessage - public void fchdir(int fd, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void fchdir(int fd) throws PosixException { String path = getFilePath(fd); if (path == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } - chdirStr(inliningTarget, path, errorBranch); + chdirStr(path); } private static final TruffleString T_FILESYSTEM_DOES_NOT_SUPPORT_CHANGING_CUR_DIR = tsLiteral("The filesystem does not support changing of the current working directory"); - private void chdirStr(Node inliningTarget, String pathStr, InlinedBranchProfile errorBranch) throws PosixException { + private void chdirStr(String pathStr) throws PosixException { + CompilerAsserts.neverPartOfCompilation(); TruffleFile truffleFile = getTruffleFile(pathStr).getAbsoluteFile(); if (!truffleFile.exists()) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.ENOENT); } if (!truffleFile.isDirectory()) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.ENOTDIR); } try { context.getEnv().setCurrentWorkingDirectory(truffleFile); } catch (IllegalArgumentException ignored) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.ENOENT); } catch (SecurityException ignored) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EACCES); } catch (UnsupportedOperationException ignored) { - errorBranch.enter(inliningTarget); throw posixException(new ErrorAndMessagePair(OSErrorEnum.EIO, T_FILESYSTEM_DOES_NOT_SUPPORT_CHANGING_CUR_DIR)); } } - @ExportMessage + @Override @TruffleBoundary public boolean isatty(int fd) { if (isStandardStream(fd)) { return context.getOption(PythonOptions.TerminalIsInteractive); - } else { - // These two files are explicitly specified by POSIX - String path = getFilePath(fd); - return path != null && (path.equals("/dev/tty") || path.equals("/dev/console")); } + + // These two files are explicitly specified by POSIX + String path = getFilePath(fd); + return "/dev/tty".equals(path) || "/dev/console".equals(path); } private static final class EmulatedDirStream { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 40a2cfc0a2..4b9f15160e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -527,44 +527,44 @@ public final void mkdirat(int dirFd, Object pathname, int mode) throws PosixExce } } - @ExportMessage - final Object getcwd( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object getcwd() throws PosixException { logEnter("getcwd", ""); try { - return logExit("getcwd", "%s", lib.getcwd(delegate)); + return logExit("getcwd", "%s", delegate.getcwd()); } catch (PosixException e) { throw logException("getcwd", e); } } - @ExportMessage - final void chdir(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void chdir(Object path) throws PosixException { logEnter("chdir", "%s", path); try { - lib.chdir(delegate, path); + delegate.chdir(path); } catch (PosixException e) { throw logException("chdir", e); } } - @ExportMessage - final void fchdir(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchdir(int fd) throws PosixException { logEnter("fchdir", "%d", fd); try { - lib.fchdir(delegate, fd); + delegate.fchdir(fd); } catch (PosixException e) { throw logException("fchdir", e); } } - @ExportMessage - final boolean isatty(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean isatty(int fd) { logEnter("isatty", "%d", fd); - return logExit("isatty", "%b", lib.isatty(delegate, fd)); + return logExit("isatty", "%b", delegate.isatty(fd)); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 3732862f17..76661345de 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1295,7 +1295,8 @@ public void mkdirat(int dirFd, Object pathname, int mode) throws PosixException } } - @ExportMessage + @Override + @TruffleBoundary public Object getcwd() throws PosixException { for (int bufLen = 1024;; bufLen += 1024) { int byteLen = WINDOWS ? bufLen * 2 : bufLen; @@ -1320,7 +1321,8 @@ public Object getcwd() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void chdir(Object path) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1333,7 +1335,8 @@ public void chdir(Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void fchdir(int fd) throws PosixException { int result = posixNativeFunctionInvoker.call_fchdir(fd); if (result != 0) { @@ -1341,7 +1344,8 @@ public void fchdir(int fd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public boolean isatty(int fd) { return posixNativeFunctionInvoker.call_isatty(fd) != 0; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 2210dac89e..7193264294 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -161,5 +161,13 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf public abstract void mkdirat(int dirFd, Object pathname, int mode) throws PosixException; + public abstract Object getcwd() throws PosixException; + + public abstract void chdir(Object path) throws PosixException; + + public abstract void fchdir(int fd) throws PosixException; + + public abstract boolean isatty(int fd); + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 6cbcba46df..54249e29b9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,21 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract Object getcwd(Object receiver) throws PosixException; - - public abstract void chdir(Object receiver, Object path) throws PosixException; - - /** - * Performs operation of fchdir(fd). - * - * @param receiver the receiver of the message - * @param fd the file descriptor - * @throws PosixException if an error occurs - */ - public abstract void fchdir(Object receiver, int fd) throws PosixException; - - public abstract boolean isatty(Object receiver, int fd); - /** * Caller is responsible for calling {@link #closedir(Object, Object)} to free the allocated * resources. diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index ed6f287607..c67a3bed9b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -425,31 +425,32 @@ public final void mkdirat(int dirFd, Object pathname, int mode) throws PosixExce nativePosixSupport.mkdirat(dirFd, pathname, mode); } - @ExportMessage - final Object getcwd(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object getcwd() throws PosixException { checkNotInPreInitialization(); - return nativeLib.getcwd(nativePosixSupport); + return nativePosixSupport.getcwd(); } - @ExportMessage - final void chdir(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void chdir(Object path) throws PosixException { checkNotInPreInitialization(); - nativeLib.chdir(nativePosixSupport, path); + nativePosixSupport.chdir(path); } - @ExportMessage - final void fchdir(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchdir(int fd) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchdir(nativePosixSupport, fd); + nativePosixSupport.fchdir(fd); } - @ExportMessage - final boolean isatty(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean isatty(int fd) { checkNotInPreInitialization(); - return nativeLib.isatty(nativePosixSupport, fd); + return nativePosixSupport.isatty(fd); } @ExportMessage From 46cfe7c6a15cea37c88fc67c0554822af9e882c7 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 15:24:26 +0200 Subject: [PATCH 034/129] Convert PosixSupportLibrary directory stream lifecycle operations (cherry picked from commit ab66a9d7cec7bab7f7d36cb1dfdc869cd1699c84) --- .../builtins/modules/PosixModuleBuiltins.java | 20 ++++---- .../objects/posix/PScandirIterator.java | 8 +-- .../posix/ScandirIteratorBuiltins.java | 23 +++------ .../python/runtime/EmulatedPosixSupport.java | 30 +++++------- .../python/runtime/LoggingPosixSupport.java | 40 +++++++-------- .../python/runtime/NativePosixSupport.java | 17 ++++--- .../graal/python/runtime/PosixSupport.java | 13 +++++ .../python/runtime/PosixSupportLibrary.java | 25 ---------- .../python/runtime/PreInitPosixSupport.java | 49 ++++++++++--------- 9 files changed, 101 insertions(+), 124 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 5e7f53811c..dee965ae95 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1922,13 +1922,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PScandirIterator scandirPath(VirtualFrame frame, PosixPath path, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_SCANDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { - return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, posixLib.opendir(context.getPosixSupport(), path.value), path, false); + return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, context.getPosixSupport().opendir(path.value), path, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1937,12 +1936,11 @@ static PScandirIterator scandirPath(VirtualFrame frame, PosixPath path, @Specialization static PScandirIterator scandirFd(VirtualFrame frame, PosixFd fd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_SCANDIR, fd.originalObject); - Object dirStream = dupAndFdopendir(frame, inliningTarget, posixLib, context.getPosixSupport(), fd, constructAndRaiseNode); + Object dirStream = dupAndFdopendir(frame, inliningTarget, context.getPosixSupport(), fd, constructAndRaiseNode); return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, dirStream, fd, true); } } @@ -1966,7 +1964,7 @@ static PList listdirPath(VirtualFrame frame, PosixPath path, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { - return listdir(frame, inliningTarget, posixLib.opendir(context.getPosixSupport(), path.value), path.wasBufferLike, false, posixLib, constructAndRaiseNode, + return listdir(frame, inliningTarget, context.getPosixSupport().opendir(path.value), path.wasBufferLike, false, posixLib, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -1981,7 +1979,7 @@ static PList listdirFd(VirtualFrame frame, PosixFd fd, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, fd.originalObject); - Object dirStream = dupAndFdopendir(frame, inliningTarget, posixLib, context.getPosixSupport(), fd, constructAndRaiseNode); + Object dirStream = dupAndFdopendir(frame, inliningTarget, context.getPosixSupport(), fd, constructAndRaiseNode); return listdir(frame, inliningTarget, dirStream, false, true, posixLib, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); } @@ -1990,7 +1988,7 @@ private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dir List list = new ArrayList<>(); try { while (true) { - Object dirEntry = posixLib.readdir(posixSupport, dirStream); + Object dirEntry = posixSupport.readdir(dirStream); if (dirEntry == null) { return PFactory.createList(language, listToArray(list)); } @@ -2005,10 +2003,10 @@ private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dir throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } finally { if (needsRewind) { - posixLib.rewinddir(posixSupport, dirStream); + posixSupport.rewinddir(dirStream); } try { - posixLib.closedir(posixSupport, dirStream); + posixSupport.closedir(dirStream); } catch (PosixException e) { // ignored (CPython does not check the return value of closedir) } @@ -2026,12 +2024,12 @@ private static Object[] listToArray(List list) { } } - static Object dupAndFdopendir(VirtualFrame frame, Node inliningTarget, PosixSupportLibrary posixLib, PosixSupport posixSupport, PosixFd fd, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { + static Object dupAndFdopendir(VirtualFrame frame, Node inliningTarget, PosixSupport posixSupport, PosixFd fd, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int dupFd = -1; try { dupFd = posixSupport.dup(fd.fd); // when fdopenddir succeeds, we are no longer responsible for closing dupFd - return posixLib.fdopendir(posixSupport, dupFd); + return posixSupport.fdopendir(dupFd); } catch (PosixException e) { if (dupFd != -1) { try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java index fbe75c77dc..3ab811c013 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java @@ -45,7 +45,7 @@ import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.runtime.AsyncHandler.AsyncAction; import com.oracle.graal.python.runtime.AsyncHandler.SharedFinalizer; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.object.Shape; @@ -75,16 +75,16 @@ public AsyncAction release() { return new ScandirIteratorBuiltins.ReleaseCallback(this); } - void rewindAndClose(PosixSupportLibrary posixLib, Object posixSupport) { + void rewindAndClose(PosixSupport posixSupport) { if (!markReleased()) { return; } Object dirStream = getReference(); if (needsRewind) { - posixLib.rewinddir(posixSupport, dirStream); + posixSupport.rewinddir(dirStream); } try { - posixLib.closedir(posixSupport, dirStream); + posixSupport.closedir(dirStream); } catch (PosixException e) { // ignored (CPython does not chek the return value of closedir) } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java index 6e5b03fee1..c62de55eea 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java @@ -61,7 +61,6 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.runtime.AsyncHandler.AsyncAction; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; @@ -73,7 +72,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; @@ -91,9 +89,8 @@ protected List> getNodeFa @GenerateNodeFactory abstract static class CloseNode extends PythonUnaryBuiltinNode { @Specialization - PNone close(PScandirIterator self, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) { - self.ref.rewindAndClose(posixLib, getPosixSupport()); + PNone close(PScandirIterator self) { + self.ref.rewindAndClose(getPosixSupport()); return PNone.NONE; } } @@ -113,7 +110,6 @@ abstract static class NextNode extends TpIterNextBuiltin { @Specialization static Object next(VirtualFrame frame, PScandirIterator self, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language) { if (self.ref.isReleased()) { @@ -121,14 +117,14 @@ static Object next(VirtualFrame frame, PScandirIterator self, } PosixSupport posixSupport = PosixSupport.get(inliningTarget); try { - Object dirEntryData = posixLib.readdir(posixSupport, self.ref.getReference()); + Object dirEntryData = posixSupport.readdir(self.ref.getReference()); if (dirEntryData == null) { - self.ref.rewindAndClose(posixLib, posixSupport); + self.ref.rewindAndClose(posixSupport); throw iteratorExhausted(); } return PFactory.createDirEntry(language, dirEntryData, self.path); } catch (PosixException e) { - self.ref.rewindAndClose(posixLib, posixSupport); + self.ref.rewindAndClose(posixSupport); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -148,9 +144,8 @@ PScandirIterator iter(PScandirIterator self) { abstract static class ExitNode extends PythonBuiltinNode { @Specialization @SuppressWarnings("unused") - PNone exit(PScandirIterator self, Object type, Object value, Object traceback, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) { - self.ref.rewindAndClose(posixLib, getPosixSupport()); + PNone exit(PScandirIterator self, Object type, Object value, Object traceback) { + self.ref.rewindAndClose(getPosixSupport()); return PNone.NONE; } } @@ -174,8 +169,6 @@ public void execute(PythonContext context, Access access) { } private static class ReleaserRootNode extends RootNode { - @Child private PosixSupportLibrary posixSupportLibrary = PosixSupportLibrary.getFactory().createDispatched(1); - ReleaserRootNode(TruffleLanguage language) { super(language); } @@ -183,7 +176,7 @@ private static class ReleaserRootNode extends RootNode { @Override public Object execute(VirtualFrame frame) { PScandirIterator.DirStreamRef ref = (PScandirIterator.DirStreamRef) frame.getArguments()[0]; - ref.rewindAndClose(posixSupportLibrary, PythonContext.get(this).getPosixSupport()); + ref.rewindAndClose(PythonContext.get(this).getPosixSupport()); return null; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index dc776f408b..7cc1720f68 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -1635,31 +1635,24 @@ void reopen() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object opendir(Object path) throws PosixException { - return opendirImpl(pathToJavaString(path), -1); + return new EmulatedDirStream(getTruffleFile(pathToJavaString(path)), -1); } - @ExportMessage - public Object fdopendir(int fd, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public Object fdopendir(int fd) throws PosixException { String path = getFilePath(fd); if (path == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.ENOENT); } - return opendirImpl(path, fd); - } - - private EmulatedDirStream opendirImpl(String path, int fd) throws PosixException { - TruffleFile file = getTruffleFile(path); - return new EmulatedDirStream(file, fd); + return new EmulatedDirStream(getTruffleFile(path), fd); } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") public void closedir(Object dirStreamObj) throws PosixException { EmulatedDirStream dirStream = (EmulatedDirStream) dirStreamObj; try { @@ -1673,9 +1666,8 @@ public void closedir(Object dirStreamObj) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") public Object readdir(Object dirStreamObj) throws PosixException { EmulatedDirStream dirStream = (EmulatedDirStream) dirStreamObj; if (dirStream.needsReopen) { @@ -1692,8 +1684,8 @@ public Object readdir(Object dirStreamObj) throws PosixException { } } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public void rewinddir(Object dirStreamObj) { EmulatedDirStream dirStream = (EmulatedDirStream) dirStreamObj; // rewind must not fail => postpone reopen until readdir() is called diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 4b9f15160e..65ec2006be 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -567,55 +567,55 @@ public final boolean isatty(int fd) { return logExit("isatty", "%b", delegate.isatty(fd)); } - @ExportMessage - final Object opendir(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object opendir(Object path) throws PosixException { logEnter("opendir", "%s", path); try { - return logExit("opendir", "%s", lib.opendir(delegate, path)); + return logExit("opendir", "%s", delegate.opendir(path)); } catch (PosixException e) { throw logException("opendir", e); } } - @ExportMessage - final Object fdopendir(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object fdopendir(int fd) throws PosixException { logEnter("fdopendir", "%d", fd); try { - return logExit("fdopendir", "%s", lib.fdopendir(delegate, fd)); + return logExit("fdopendir", "%s", delegate.fdopendir(fd)); } catch (PosixException e) { throw logException("fdopendir", e); } } - @ExportMessage - final void closedir(Object dirStream, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void closedir(Object dirStream) throws PosixException { logEnter("closedir", "%s", dirStream); try { - lib.closedir(delegate, dirStream); + delegate.closedir(dirStream); } catch (PosixException e) { throw logException("closedir", e); } } - @ExportMessage - final Object readdir(Object dirStream, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object readdir(Object dirStream) throws PosixException { logEnter("readdir", "%s", dirStream); try { - return logExit("readdir", "%s", lib.readdir(delegate, dirStream)); + return logExit("readdir", "%s", delegate.readdir(dirStream)); } catch (PosixException e) { throw logException("readdir", e); } } - @ExportMessage - final void rewinddir(Object dirStream, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final void rewinddir(Object dirStream) { logEnter("rewinddir", "%s", dirStream); - lib.rewinddir(delegate, dirStream); + delegate.rewinddir(dirStream); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 76661345de..fba6e0b3c1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1350,7 +1350,8 @@ public boolean isatty(int fd) { return posixNativeFunctionInvoker.call_isatty(fd) != 0; } - @ExportMessage + @Override + @TruffleBoundary public Object opendir(Object path) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1364,7 +1365,8 @@ public Object opendir(Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object fdopendir(int fd) throws PosixException { long ptr = posixNativeFunctionInvoker.call_fdopendir(fd); if (ptr == 0) { @@ -1373,7 +1375,8 @@ public Object fdopendir(int fd) throws PosixException { return ptr; } - @ExportMessage + @Override + @TruffleBoundary public void closedir(Object dirStreamObj) throws PosixException { int res = posixNativeFunctionInvoker.call_closedir(((Long) dirStreamObj).longValue()); if (res != 0) { @@ -1381,7 +1384,8 @@ public void closedir(Object dirStreamObj) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object readdir(Object dirStreamObj) throws PosixException { int nameBufBytes = WINDOWS ? DIRENT_NAME_BUF_LENGTH * 2 : DIRENT_NAME_BUF_LENGTH; byte[] name = new byte[nameBufBytes]; @@ -1416,9 +1420,10 @@ public Object readdir(Object dirStreamObj) throws PosixException { return null; } - @ExportMessage + @Override + @TruffleBoundary public void rewinddir(Object dirStreamObj) { - posixNativeFunctionInvoker.call_rewinddir(((Long) dirStreamObj).longValue()); + posixNativeFunctionInvoker.call_rewinddir((Long) dirStreamObj); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 7193264294..9176a876dd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -169,5 +169,18 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf public abstract boolean isatty(int fd); + /** Caller is responsible for closing the returned directory stream with {@link #closedir(Object)}. */ + public abstract Object opendir(Object path) throws PosixException; + + public abstract Object fdopendir(int fd) throws PosixException; + + /** Implementations must deal with this being called more than once. */ + public abstract void closedir(Object dirStream) throws PosixException; + + /** Returns null when there are no more entries or the stream has been closed. */ + public abstract Object readdir(Object dirStream) throws PosixException; + + public abstract void rewinddir(Object dirStream); + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 54249e29b9..268c8c5a1a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,31 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - /** - * Caller is responsible for calling {@link #closedir(Object, Object)} to free the allocated - * resources. - * - * @return an opaque directory stream object to be used in calls to {@code readdir} and - * {@code closedir} - */ - public abstract Object opendir(Object receiver, Object path) throws PosixException; - - public abstract Object fdopendir(Object receiver, int fd) throws PosixException; - - /** - * Implementations must deal with this being called more than once. - */ - public abstract void closedir(Object receiver, Object dirStream) throws PosixException; - - /** - * @return an opaque dir entry object to be used in calls to {@code dirEntry*()} methods or - * {@code null} when there are no more items or if the stream has been closed by - * {@code closedir}. - */ - public abstract Object readdir(Object receiver, Object dirStream) throws PosixException; - - public abstract void rewinddir(Object receiver, Object dirStream); - /** * @return an opaque object representing the dir entry name * @see #getPathAsBytes(Object, Object) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index c67a3bed9b..ebabb586d9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -453,48 +453,49 @@ public final boolean isatty(int fd) { return nativePosixSupport.isatty(fd); } - @ExportMessage - final Object opendir(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object opendir(Object path) throws PosixException { if (inPreInitialization) { - return addDirStream(PosixSupportLibrary.getUncached().opendir(emulatedPosixSupport, path)); + return addDirStream(emulatedPosixSupport.opendir(path)); } - return nativeLib.opendir(nativePosixSupport, path); + return nativePosixSupport.opendir(path); } - @ExportMessage - final Object fdopendir(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object fdopendir(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.fdopendir(nativePosixSupport, fd); + return nativePosixSupport.fdopendir(fd); } - @ExportMessage - final void closedir(Object dirStream, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void closedir(Object dirStream) throws PosixException { if (inPreInitialization) { - PosixSupportLibrary.getUncached().closedir(emulatedPosixSupport, removeDirStream(dirStream)); + emulatedPosixSupport.closedir(removeDirStream(dirStream)); return; } - nativeLib.closedir(nativePosixSupport, dirStream); + nativePosixSupport.closedir(dirStream); } - @ExportMessage - final Object readdir(Object dirStream, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object readdir(Object dirStream) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().readdir(emulatedPosixSupport, dirStream); + return emulatedPosixSupport.readdir(dirStream); } - return nativeLib.readdir(nativePosixSupport, dirStream); + return nativePosixSupport.readdir(dirStream); } - @ExportMessage - final void rewinddir(Object dirStream, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final void rewinddir(Object dirStream) { if (inPreInitialization) { - PosixSupportLibrary.getUncached().rewinddir(emulatedPosixSupport, dirStream); + emulatedPosixSupport.rewinddir(dirStream); + return; } - nativeLib.rewinddir(nativePosixSupport, dirStream); + nativePosixSupport.rewinddir(dirStream); } @ExportMessage From 6fc054b58ea1beb99fa3022e8b991f887127df1b Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 15:33:32 +0200 Subject: [PATCH 035/129] Convert PosixSupportLibrary directory entry access operations (cherry picked from commit 51857683dbdb06f48b750c9d97f427504412643f) --- .../builtins/modules/PosixModuleBuiltins.java | 2 +- .../objects/posix/DirEntryBuiltins.java | 16 ++--- .../python/runtime/EmulatedPosixSupport.java | 14 ++-- .../python/runtime/LoggingPosixSupport.java | 32 ++++----- .../python/runtime/NativePosixSupport.java | 66 +++++++------------ .../graal/python/runtime/PosixSupport.java | 10 +++ .../python/runtime/PosixSupportLibrary.java | 24 ------- .../python/runtime/PreInitPosixSupport.java | 34 +++++----- 8 files changed, 81 insertions(+), 117 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index dee965ae95..f813d2e1d5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1992,7 +1992,7 @@ private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dir if (dirEntry == null) { return PFactory.createList(language, listToArray(list)); } - Object name = posixLib.dirEntryGetName(posixSupport, dirEntry); + Object name = posixSupport.dirEntryGetName(dirEntry); if (produceBytes) { addToList(list, opaquePathToBytes(name, posixLib, posixSupport, language)); } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java index d471c9bbf3..f166ace632 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java @@ -121,9 +121,9 @@ static Object nameAsBytes(VirtualFrame frame, PDirEntry self, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { if (produceBytesProfile.profile(inliningTarget, self.produceBytes())) { - return opaquePathToBytes(posixLib.dirEntryGetName(context.getPosixSupport(), self.dirEntryData), posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytes(context.getPosixSupport().dirEntryGetName(self.dirEntryData), posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); } else { - return posixLib.getPathAsString(context.getPosixSupport(), posixLib.dirEntryGetName(context.getPosixSupport(), self.dirEntryData)); + return posixLib.getPathAsString(context.getPosixSupport(), context.getPosixSupport().dirEntryGetName(self.dirEntryData)); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -165,9 +165,9 @@ static PosixPath createBytes(VirtualFrame frame, Node inliningTarget, PDirEntry Object opaquePath; try { if (posixPathProfile.profile(inliningTarget, self.scandirPath instanceof PosixPath)) { - opaquePath = posixLib.dirEntryGetPath(context.getPosixSupport(), self.dirEntryData, ((PosixPath) self.scandirPath).value); + opaquePath = context.getPosixSupport().dirEntryGetPath(self.dirEntryData, ((PosixPath) self.scandirPath).value); } else { - opaquePath = posixLib.dirEntryGetName(context.getPosixSupport(), self.dirEntryData); + opaquePath = context.getPosixSupport().dirEntryGetName(self.dirEntryData); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -208,10 +208,9 @@ abstract static class InodeNode extends PythonUnaryBuiltinNode { @Specialization long inode(VirtualFrame frame, PDirEntry self, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.dirEntryGetInode(getPosixSupport(), self.dirEntryData); + return getPosixSupport().dirEntryGetInode(self.dirEntryData); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -343,9 +342,8 @@ boolean testModeUsingStat(VirtualFrame frame, PDirEntry self, boolean followSyml boolean useTypeIfKnown(VirtualFrame frame, PDirEntry self, @SuppressWarnings("unused") boolean followSymlinks, @Bind Node inliningTarget, @Shared @Cached StatHelperNode statHelperNode, - @Shared @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { - int entryType = posixLib.dirEntryGetType(PosixSupport.get(this), self.dirEntryData); + @Shared @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode) { + int entryType = PosixSupport.get(this).dirEntryGetType(self.dirEntryData); if (entryType != DT_UNKNOWN.value) { return entryType == expectedDirEntryType; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 7cc1720f68..f5965f0012 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -1692,15 +1692,15 @@ public void rewinddir(Object dirStreamObj) { dirStream.needsReopen = true; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public Object dirEntryGetName(Object dirEntry) { TruffleFile file = (TruffleFile) dirEntry; return file.getName(); } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public Object dirEntryGetPath(Object dirEntry, Object scandirPath) { TruffleFile file = (TruffleFile) dirEntry; // Given that scandirPath must have been successfully channeled via opendir, we can assume @@ -1710,9 +1710,8 @@ public Object dirEntryGetPath(Object dirEntry, Object scandirPath) { return dir.resolve(file.getName()).getPath(); } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") public long dirEntryGetInode(Object dirEntry) throws PosixException { TruffleFile file = (TruffleFile) dirEntry; try { @@ -1725,9 +1724,8 @@ public long dirEntryGetInode(Object dirEntry) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") public int dirEntryGetType(Object dirEntry) { TruffleFile file = (TruffleFile) dirEntry; try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 65ec2006be..12f9667d4b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -618,44 +618,44 @@ public final void rewinddir(Object dirStream) { delegate.rewinddir(dirStream); } - @ExportMessage - final Object dirEntryGetName(Object dirEntry, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetName(Object dirEntry) throws PosixException { logEnter("dirEntryGetName", "%s", dirEntry); try { - return logExit("dirEntryGetName", "%s", lib.dirEntryGetName(delegate, dirEntry)); + return logExit("dirEntryGetName", "%s", delegate.dirEntryGetName(dirEntry)); } catch (PosixException e) { throw logException("dirEntryGetName", e); } } - @ExportMessage - final Object dirEntryGetPath(Object dirEntry, Object scandirPath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetPath(Object dirEntry, Object scandirPath) throws PosixException { logEnter("dirEntryGetPath", "%s, %s", dirEntry, scandirPath); try { - return logExit("dirEntryGetPath", "%s", lib.dirEntryGetPath(delegate, dirEntry, scandirPath)); + return logExit("dirEntryGetPath", "%s", delegate.dirEntryGetPath(dirEntry, scandirPath)); } catch (PosixException e) { throw logException("dirEntryGetPath", e); } } - @ExportMessage - final long dirEntryGetInode(Object dirEntry, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long dirEntryGetInode(Object dirEntry) throws PosixException { logEnter("dirEntryGetInode", "%s", dirEntry); try { - return logExit("dirEntryGetInode", "%d", lib.dirEntryGetInode(delegate, dirEntry)); + return logExit("dirEntryGetInode", "%d", delegate.dirEntryGetInode(dirEntry)); } catch (PosixException e) { throw logException("dirEntryGetInode", e); } } - @ExportMessage - final int dirEntryGetType(Object dirEntry, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int dirEntryGetType(Object dirEntry) { logEnter("dirEntryGetType", "%s", dirEntry); - return logExit("dirEntryGetType", "%d", lib.dirEntryGetType(delegate, dirEntry)); + return logExit("dirEntryGetType", "%d", delegate.dirEntryGetType(dirEntry)); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index fba6e0b3c1..0c0f5c333d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -142,7 +142,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; @@ -1426,59 +1425,42 @@ public void rewinddir(Object dirStreamObj) { posixNativeFunctionInvoker.call_rewinddir((Long) dirStreamObj); } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public Object dirEntryGetName(Object dirEntryObj) { DirEntry dirEntry = (DirEntry) dirEntryObj; return dirEntry.name; } - @ExportMessage - public static class DirEntryGetPath { - @Specialization(guards = "endsWithSlash(scandirPath)") - static NativePath withSlash(@SuppressWarnings("unused") NativePosixSupport receiver, DirEntry dirEntry, Object scandirPath) { - NativePath scandirPathBuffer = (NativePath) scandirPath; - int pathLen = scandirPathBuffer.data.length; - int nameLen = dirEntry.name.data.length; - byte[] buf = new byte[pathLen + nameLen]; - PythonUtils.arraycopy(scandirPathBuffer.data, 0, buf, 0, pathLen); - PythonUtils.arraycopy(dirEntry.name.data, 0, buf, pathLen, nameLen); - return createLike(scandirPathBuffer, buf); - } - - @Specialization(guards = "!endsWithSlash(scandirPath)") - static NativePath withoutSlash(@SuppressWarnings("unused") NativePosixSupport receiver, DirEntry dirEntry, Object scandirPath) { - NativePath scandirPathBuffer = (NativePath) scandirPath; - int pathLen = scandirPathBuffer.data.length; - int nameLen = dirEntry.name.data.length; - int separatorBytes = scandirPathBuffer instanceof WidePath ? 2 : 1; - byte[] buf = new byte[pathLen + separatorBytes + nameLen]; - PythonUtils.arraycopy(scandirPathBuffer.data, 0, buf, 0, pathLen); - buf[pathLen] = (byte) (scandirPathBuffer instanceof WidePath ? '\\' : '/'); - PythonUtils.arraycopy(dirEntry.name.data, 0, buf, pathLen + separatorBytes, nameLen); - return createLike(scandirPathBuffer, buf); - } - - protected static boolean endsWithSlash(Object path) { - NativePath b = (NativePath) path; - byte last = b.data[b.data.length - (b instanceof WidePath ? 2 : 1)]; - return last == '/' || last == '\\'; - } - - private static NativePath createLike(NativePath path, byte[] data) { - return path instanceof WidePath ? new WidePath(data) : new NarrowPath(data); - } + @Override + @TruffleBoundary + public Object dirEntryGetPath(Object dirEntryObj, Object scandirPath) { + DirEntry dirEntry = (DirEntry) dirEntryObj; + NativePath path = (NativePath) scandirPath; + int pathLen = path.data.length; + int nameLen = dirEntry.name.data.length; + boolean wide = path instanceof WidePath; + byte last = path.data[pathLen - (wide ? 2 : 1)]; + boolean hasSlash = last == '/' || last == '\\'; + int separatorBytes = hasSlash ? 0 : wide ? 2 : 1; + byte[] buf = new byte[pathLen + separatorBytes + nameLen]; + PythonUtils.arraycopy(path.data, 0, buf, 0, pathLen); + if (!hasSlash) { + buf[pathLen] = (byte) (wide ? '\\' : '/'); + } + PythonUtils.arraycopy(dirEntry.name.data, 0, buf, pathLen + separatorBytes, nameLen); + return wide ? new WidePath(buf) : new NarrowPath(buf); } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public long dirEntryGetInode(Object dirEntry) { DirEntry entry = (DirEntry) dirEntry; return entry.ino; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public int dirEntryGetType(Object dirEntryObj) { DirEntry dirEntry = (DirEntry) dirEntryObj; return dirEntry.type; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 9176a876dd..6ad1677ff4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -182,5 +182,15 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf public abstract void rewinddir(Object dirStream); + /** Returns an opaque directory-entry name suitable for path conversion. */ + public abstract Object dirEntryGetName(Object dirEntry) throws PosixException; + + /** Returns the entry name joined to the path originally passed to {@link #opendir(Object)}. */ + public abstract Object dirEntryGetPath(Object dirEntry, Object scandirPath) throws PosixException; + + public abstract long dirEntryGetInode(Object dirEntry) throws PosixException; + + public abstract int dirEntryGetType(Object dirEntry); + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 268c8c5a1a..4090cb0790 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,30 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - /** - * @return an opaque object representing the dir entry name - * @see #getPathAsBytes(Object, Object) - * @see #getPathAsString(Object, Object) - */ - public abstract Object dirEntryGetName(Object receiver, Object dirEntry) throws PosixException; - - /** - * Returns the dir entry path, which is the name of the dir entry joined with the given path. - * - * @param scandirPath the path originally passed to {@link #opendir(Object, Object)} - * @return an opaque object representing the dir entry path - * @see #getPathAsBytes(Object, Object) - * @see #getPathAsString(Object, Object) - */ - public abstract Object dirEntryGetPath(Object receiver, Object dirEntry, Object scandirPath) throws PosixException; - - public abstract long dirEntryGetInode(Object receiver, Object dirEntry) throws PosixException; - - /** - * @return one of the {@code DT_xxx} constants - */ - public abstract int dirEntryGetType(Object receiver, Object dirEntry); - /** * Equivalent of POSIX {@code utimensat()}. * diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index ebabb586d9..6714b90f24 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -498,34 +498,34 @@ public final void rewinddir(Object dirStream) { nativePosixSupport.rewinddir(dirStream); } - @ExportMessage - final Object dirEntryGetName(Object dirEntry, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetName(Object dirEntry) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().dirEntryGetName(emulatedPosixSupport, dirEntry); + return emulatedPosixSupport.dirEntryGetName(dirEntry); } - return nativeLib.dirEntryGetName(nativePosixSupport, dirEntry); + return nativePosixSupport.dirEntryGetName(dirEntry); } - @ExportMessage - final Object dirEntryGetPath(Object dirEntry, Object scandirPath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetPath(Object dirEntry, Object scandirPath) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dirEntryGetPath(nativePosixSupport, dirEntry, scandirPath); + return nativePosixSupport.dirEntryGetPath(dirEntry, scandirPath); } - @ExportMessage - final long dirEntryGetInode(Object dirEntry, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long dirEntryGetInode(Object dirEntry) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dirEntryGetInode(nativePosixSupport, dirEntry); + return nativePosixSupport.dirEntryGetInode(dirEntry); } - @ExportMessage - final int dirEntryGetType(Object dirEntry, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int dirEntryGetType(Object dirEntry) { checkNotInPreInitialization(); - return nativeLib.dirEntryGetType(nativePosixSupport, dirEntry); + return nativePosixSupport.dirEntryGetType(dirEntry); } @ExportMessage From 92eb2af095e7a98cd69c477bcef61f6dd827de82 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 15:42:28 +0200 Subject: [PATCH 036/129] Convert PosixSupportLibrary file time operations (cherry picked from commit 26147a9beb40b97e42fbda83aeb4b1825257c15a) --- .../builtins/modules/PosixModuleBuiltins.java | 15 +-- .../python/runtime/EmulatedPosixSupport.java | 126 ++++++------------ .../python/runtime/LoggingPosixSupport.java | 40 +++--- .../python/runtime/NativePosixSupport.java | 15 ++- .../graal/python/runtime/PosixSupport.java | 12 ++ .../python/runtime/PosixSupportLibrary.java | 23 ---- .../python/runtime/PreInitPosixSupport.java | 40 +++--- 7 files changed, 111 insertions(+), 160 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index f813d2e1d5..066dfdd3ba 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -2146,12 +2146,11 @@ static PNone utimensat(VirtualFrame frame, PosixPath path, Object times, Object @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] timespec = timespecNode.execute(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.utimensat(context.getPosixSupport(), dirFd, path.value, timespec, followSymlinks); + context.getPosixSupport().utimensat(dirFd, path.value, timespec, followSymlinks); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2165,12 +2164,11 @@ static PNone utimes(VirtualFrame frame, PosixPath path, Object times, Object ns, @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.utimes(context.getPosixSupport(), path.value, timeval); + context.getPosixSupport().utimes(path.value, timeval); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2184,12 +2182,11 @@ static PNone lutimes(VirtualFrame frame, PosixPath path, Object times, Object ns @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.lutimes(context.getPosixSupport(), path.value, timeval); + context.getPosixSupport().lutimes(path.value, timeval); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2217,12 +2214,11 @@ static PNone futimens(VirtualFrame frame, PosixFd fd, Object times, Object ns, i @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] timespec = timespecNode.execute(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.futimens(context.getPosixSupport(), fd.fd, timespec); + context.getPosixSupport().futimens(fd.fd, timespec); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2236,12 +2232,11 @@ static PNone futimes(VirtualFrame frame, PosixFd fd, Object times, Object ns, in @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.futimes(context.getPosixSupport(), fd.fd, timeval); + context.getPosixSupport().futimes(fd.fd, timeval); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index f5965f0012..1d0a2e789b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -268,10 +268,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.dsl.GenerateCached; -import com.oracle.truffle.api.dsl.GenerateInline; -import com.oracle.truffle.api.dsl.GenerateUncached; -import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.io.TruffleProcessBuilder; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; @@ -1745,44 +1741,39 @@ public int dirEntryGetType(Object dirEntry) { return DT_UNKNOWN.value; } - @ExportMessage - public void utimensat(int dirFd, Object path, long[] timespec, boolean followSymlinks, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + @Override + @TruffleBoundary + public void utimensat(int dirFd, Object path, long[] timespec, boolean followSymlinks) throws PosixException { TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); - setUTimeNode.execute(inliningTarget, file, timespec, followSymlinks); + setUTime(file, timespec, followSymlinks); } - @ExportMessage - public void futimens(int fd, long[] timespec, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + @Override + @TruffleBoundary + public void futimens(int fd, long[] timespec) throws PosixException { TruffleFile file = getTruffleFile(getFilePath(fd)); - setUTimeNode.execute(inliningTarget, file, timespec, true); + setUTime(file, timespec, true); } - @ExportMessage - public void futimes(int fd, Timeval[] timeval, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + @Override + @TruffleBoundary + public void futimes(int fd, Timeval[] timeval) throws PosixException { TruffleFile file = getTruffleFile(getFilePath(fd)); - setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); + setUTime(file, timevalToTimespec(timeval), true); } - @ExportMessage - public void lutimes(Object filename, Timeval[] timeval, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + @Override + @TruffleBoundary + public void lutimes(Object filename, Timeval[] timeval) throws PosixException { TruffleFile file = getTruffleFile(pathToJavaString(filename)); - setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), false); + setUTime(file, timevalToTimespec(timeval), false); } - @ExportMessage - public void utimes(Object filename, Timeval[] timeval, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode) throws PosixException { + @Override + @TruffleBoundary + public void utimes(Object filename, Timeval[] timeval) throws PosixException { TruffleFile file = getTruffleFile(pathToJavaString(filename)); - setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); + setUTime(file, timevalToTimespec(timeval), true); } private static long[] timevalToTimespec(Timeval[] timeval) { @@ -1793,63 +1784,34 @@ private static long[] timevalToTimespec(Timeval[] timeval) { timeval[1].getSeconds(), timeval[1].getMicroseconds() * 1000}; } - @GenerateUncached - @GenerateInline - @GenerateCached(false) - public abstract static class SetUTimeNode extends Node { - abstract void execute(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks) throws PosixException; - - @Specialization(guards = "timespec == null") - static void doCurrentTime(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws PosixException { - FileTime time = currentFileTime(); - setFileTimes(inliningTarget, followSymlinks, file, time, time, errBranch); - } - - @TruffleBoundary - private static FileTime currentFileTime() { - return FileTime.from(Instant.now()); - } - - // the second guard is just so that Truffle does not generate dead code that throws - // UnsupportedSpecializationException.. - @Specialization(guards = {"timespec != null", "file != null"}) - static void doGivenTime(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws PosixException { - FileTime atime = toFileTime(timespec[0], timespec[1]); - FileTime mtime = toFileTime(timespec[2], timespec[3]); - setFileTimes(inliningTarget, followSymlinks, file, mtime, atime, errBranch); + private static void setUTime(TruffleFile file, long[] timespec, boolean followSymlinks) throws PosixException { + CompilerAsserts.neverPartOfCompilation(); + FileTime atime; + FileTime mtime; + if (timespec == null) { + atime = mtime = FileTime.from(Instant.now()); + } else { + atime = toFileTime(timespec[0], timespec[1]); + mtime = toFileTime(timespec[2], timespec[3]); } - - private static void setFileTimes(Node inliningTarget, boolean followSymlinks, TruffleFile file, FileTime mtime, FileTime atime, InlinedBranchProfile errBranch) - throws PosixException { - try { - file.setLastAccessTime(atime, getLinkOptions(followSymlinks)); - file.setLastModifiedTime(mtime, getLinkOptions(followSymlinks)); - } catch (Exception e) { - errBranch.enter(inliningTarget); - final ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); - // setLastAccessTime/setLastModifiedTime and NOFOLLOW_LINKS does not work (at least) - // on OpenJDK8 on Linux and gives ELOOP error. See some explanation in this thread: - // https://stackoverflow.com/questions/17308363/symlink-lastmodifiedtime-in-java-1-7 - if (errAndMsg.oserror == OSErrorEnum.ELOOP && !followSymlinks) { - throw createUnsupportedFeature("utime with 'follow symlinks' flag"); - } - throw posixException(errAndMsg); + try { + file.setLastAccessTime(atime, getLinkOptions(followSymlinks)); + file.setLastModifiedTime(mtime, getLinkOptions(followSymlinks)); + } catch (Exception e) { + final ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); + // setLastAccessTime/setLastModifiedTime and NOFOLLOW_LINKS does not work (at least) + // on OpenJDK8 on Linux and gives ELOOP error. + if (errAndMsg.oserror == OSErrorEnum.ELOOP && !followSymlinks) { + throw createUnsupportedFeature("utime with 'follow symlinks' flag"); } + throw posixException(errAndMsg); } + } - private static FileTime toFileTime(long seconds, long nanos) { - // JDK allows to set only one "time" per one operation, so - // UnixFileAttributeViews#setTimes is setting only one of the mtime/atime but internally - // it needs to call POSIX utime providing both, so it takes the other from fstat, but - // since JDK's fstat wrapper does not support better granularity than seconds, it - // will override nanoseconds component that may have been set by our code already. - // To make this less confusing, we intentionally ignore the nanoseconds component, even - // thought we could set microseconds for one of the mtime/atime (the one that is set - // last) - return FileTime.from(seconds, TimeUnit.SECONDS); - } + private static FileTime toFileTime(long seconds, long nanos) { + // JDK allows to set only one time per operation, so setting one may round the other to + // seconds. Ignore nanoseconds consistently for both times. + return FileTime.from(seconds, TimeUnit.SECONDS); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 12f9667d4b..e6dd7c8a51 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -658,56 +658,56 @@ public final int dirEntryGetType(Object dirEntry) { return logExit("dirEntryGetType", "%d", delegate.dirEntryGetType(dirEntry)); } - @ExportMessage - final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException { logEnter("utimeNsAt", "%d, %s, %s, %b", dirFd, pathname, timespec, followSymlinks); try { - lib.utimensat(delegate, dirFd, pathname, timespec, followSymlinks); + delegate.utimensat(dirFd, pathname, timespec, followSymlinks); } catch (PosixException e) { throw logException("utimeNsAt", e); } } - @ExportMessage - final void futimens(int fd, long[] timespec, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void futimens(int fd, long[] timespec) throws PosixException { logEnter("futimeNs", "%d, %s", fd, timespec); try { - lib.futimens(delegate, fd, timespec); + delegate.futimens(fd, timespec); } catch (PosixException e) { throw logException("futimeNs", e); } } - @ExportMessage - final void futimes(int fd, Timeval[] timeval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void futimes(int fd, Timeval[] timeval) throws PosixException { logEnter("futimes", "%d, %s", fd, timeval); try { - lib.futimes(delegate, fd, timeval); + delegate.futimes(fd, timeval); } catch (PosixException e) { throw logException("futimes", e); } } - @ExportMessage - final void lutimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void lutimes(Object filename, Timeval[] timeval) throws PosixException { logEnter("lutimes", "%s, %s", filename, timeval); try { - lib.lutimes(delegate, filename, timeval); + delegate.lutimes(filename, timeval); } catch (PosixException e) { throw logException("lutimes", e); } } - @ExportMessage - final void utimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void utimes(Object filename, Timeval[] timeval) throws PosixException { logEnter("utimes", "%s, %s", filename, timeval); try { - lib.utimes(delegate, filename, timeval); + delegate.utimes(filename, timeval); } catch (PosixException e) { throw logException("utimes", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 0c0f5c333d..19dd59c47f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1466,7 +1466,8 @@ public int dirEntryGetType(Object dirEntryObj) { return dirEntry.type; } - @ExportMessage + @Override + @TruffleBoundary public void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException { assert PosixConstants.HAVE_UTIMENSAT.value; assert timespec == null || timespec.length == 4; @@ -1485,7 +1486,8 @@ public void utimensat(int dirFd, Object pathname, long[] timespec, boolean follo } } - @ExportMessage + @Override + @TruffleBoundary public void futimens(int fd, long[] timespec) throws PosixException { assert PosixConstants.HAVE_FUTIMENS.value; assert timespec == null || timespec.length == 4; @@ -1500,7 +1502,8 @@ public void futimens(int fd, long[] timespec) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void futimes(int fd, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; long timevalPtr = copyTimevalArrayToNativeOrNull(timeval); @@ -1514,7 +1517,8 @@ public void futimes(int fd, Timeval[] timeval) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void lutimes(Object filename, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; long filenamePtr = NULLPTR; @@ -1532,7 +1536,8 @@ public void lutimes(Object filename, Timeval[] timeval) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void utimes(Object filename, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; long filenamePtr = NULLPTR; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 6ad1677ff4..f54f5fc22c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -192,5 +192,17 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf public abstract int dirEntryGetType(Object dirEntry); + /** The timespec contains access seconds/nanoseconds, then modification seconds/nanoseconds, or is null for now. */ + public abstract void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException; + + public abstract void futimens(int fd, long[] timespec) throws PosixException; + + /** The timeval is null or contains access and modification times. */ + public abstract void futimes(int fd, Timeval[] timeval) throws PosixException; + + public abstract void lutimes(Object filename, Timeval[] timeval) throws PosixException; + + public abstract void utimes(Object filename, Timeval[] timeval) throws PosixException; + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 4090cb0790..93c72c773b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,29 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - /** - * Equivalent of POSIX {@code utimensat()}. - * - * @param timespec an array of 4 longs in this order: - * {@code atime.tv_sec, atime.tv_nsec, mtime.tv_sec, mtime.tv_nsec} or {@code null} - * to set both times to 'now' TODO change long[] timespec to Timespec[] timespec - */ - public abstract void utimensat(Object receiver, int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException; - - /** - * Equivalent of POSIX {@code futimens()}. - */ - public abstract void futimens(Object receiver, int fd, long[] timespec) throws PosixException; - - /** - * @param timeval either {@code null} or has two elements: access time and modification time - */ - public abstract void futimes(Object receiver, int fd, Timeval[] timeval) throws PosixException; - - public abstract void lutimes(Object receiver, Object filename, Timeval[] timeval) throws PosixException; - - public abstract void utimes(Object receiver, Object filename, Timeval[] timeval) throws PosixException; - public abstract void renameat(Object receiver, int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; public abstract void replaceat(Object receiver, int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 6714b90f24..a869715189 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -528,39 +528,39 @@ public final int dirEntryGetType(Object dirEntry) { return nativePosixSupport.dirEntryGetType(dirEntry); } - @ExportMessage - final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException { checkNotInPreInitialization(); - nativeLib.utimensat(nativePosixSupport, dirFd, pathname, timespec, followSymlinks); + nativePosixSupport.utimensat(dirFd, pathname, timespec, followSymlinks); } - @ExportMessage - final void futimens(int fd, long[] timespec, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void futimens(int fd, long[] timespec) throws PosixException { checkNotInPreInitialization(); - nativeLib.futimens(nativePosixSupport, fd, timespec); + nativePosixSupport.futimens(fd, timespec); } - @ExportMessage - final void futimes(int fd, Timeval[] timeval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void futimes(int fd, Timeval[] timeval) throws PosixException { checkNotInPreInitialization(); - nativeLib.futimes(nativePosixSupport, fd, timeval); + nativePosixSupport.futimes(fd, timeval); } - @ExportMessage - final void lutimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void lutimes(Object filename, Timeval[] timeval) throws PosixException { checkNotInPreInitialization(); - nativeLib.lutimes(nativePosixSupport, filename, timeval); + nativePosixSupport.lutimes(filename, timeval); } - @ExportMessage - final void utimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void utimes(Object filename, Timeval[] timeval) throws PosixException { checkNotInPreInitialization(); - nativeLib.utimes(nativePosixSupport, filename, timeval); + nativePosixSupport.utimes(filename, timeval); } @ExportMessage From 5c0551e0fcaa666c7ad550b5fe62b14a403759a5 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 15:47:04 +0200 Subject: [PATCH 037/129] Convert PosixSupportLibrary renaming operations (cherry picked from commit 36b4d0d2107a84d625b0ce83d66e02b56b65bfea) --- .../builtins/modules/PosixModuleBuiltins.java | 6 ++---- .../python/runtime/EmulatedPosixSupport.java | 6 ++++-- .../python/runtime/LoggingPosixSupport.java | 16 ++++++++-------- .../graal/python/runtime/NativePosixSupport.java | 6 ++++-- .../graal/python/runtime/PosixSupport.java | 4 ++++ .../python/runtime/PosixSupportLibrary.java | 4 ---- .../python/runtime/PreInitPosixSupport.java | 16 ++++++++-------- 7 files changed, 30 insertions(+), 28 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 066dfdd3ba..fe2a6bb82f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -2279,13 +2279,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone rename(VirtualFrame frame, PosixPath src, PosixPath dst, int srcDirFd, int dstDirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_RENAME, src.originalObject, dst.originalObject, dirFdForAudit(srcDirFd), dirFdForAudit(dstDirFd)); try { - posixLib.renameat(context.getPosixSupport(), srcDirFd, src.value, dstDirFd, dst.value); + context.getPosixSupport().renameat(srcDirFd, src.value, dstDirFd, dst.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } @@ -2309,13 +2308,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone replace(VirtualFrame frame, PosixPath src, PosixPath dst, int srcDirFd, int dstDirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_RENAME, src.originalObject, dst.originalObject, dirFdForAudit(srcDirFd), dirFdForAudit(dstDirFd)); try { - posixLib.replaceat(context.getPosixSupport(), srcDirFd, src.value, dstDirFd, dst.value); + context.getPosixSupport().replaceat(srcDirFd, src.value, dstDirFd, dst.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 1d0a2e789b..769a494afe 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -1814,7 +1814,8 @@ private static FileTime toFileTime(long seconds, long nanos) { return FileTime.from(seconds, TimeUnit.SECONDS); } - @ExportMessage + @Override + @TruffleBoundary public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { try { TruffleFile newFile = resolvePath(newDirFd, pathToJavaString(newPath)); @@ -1828,7 +1829,8 @@ public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) } } - @ExportMessage + @Override + @TruffleBoundary public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { try { TruffleFile newFile = resolvePath(newDirFd, pathToJavaString(newPath)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index e6dd7c8a51..e9d6e8d2ed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -713,23 +713,23 @@ public final void utimes(Object filename, Timeval[] timeval) throws PosixExcepti } } - @ExportMessage - final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { logEnter("renameAt", "%d, %s, %d, %s", oldDirFd, oldPath, newDirFd, newPath); try { - lib.renameat(delegate, oldDirFd, oldPath, newDirFd, newPath); + delegate.renameat(oldDirFd, oldPath, newDirFd, newPath); } catch (PosixException e) { throw logException("renameAt", e); } } - @ExportMessage - final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { logEnter("replaceAt", "%d, %s, %d, %s", oldDirFd, oldPath, newDirFd, newPath); try { - lib.replaceat(delegate, oldDirFd, oldPath, newDirFd, newPath); + delegate.replaceat(oldDirFd, oldPath, newDirFd, newPath); } catch (PosixException e) { throw logException("replaceAt", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 19dd59c47f..587743834c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1555,7 +1555,8 @@ public void utimes(Object filename, Timeval[] timeval) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { long oldPathPtr = NULLPTR; long newPathPtr = NULLPTR; @@ -1572,7 +1573,8 @@ public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) } } - @ExportMessage + @Override + @TruffleBoundary public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { long oldPathPtr = NULLPTR; long newPathPtr = NULLPTR; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index f54f5fc22c..cb514e82d4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -204,5 +204,9 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf public abstract void utimes(Object filename, Timeval[] timeval) throws PosixException; + public abstract void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; + + public abstract void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 93c72c773b..1ac8c126cf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,10 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract void renameat(Object receiver, int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; - - public abstract void replaceat(Object receiver, int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; - public abstract boolean faccessat(Object receiver, int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException; public abstract void fchmodat(Object receiver, int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index a869715189..b239036fab 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -563,18 +563,18 @@ public final void utimes(Object filename, Timeval[] timeval) throws PosixExcepti nativePosixSupport.utimes(filename, timeval); } - @ExportMessage - final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { checkNotInPreInitialization(); - nativeLib.renameat(nativePosixSupport, oldDirFd, oldPath, newDirFd, newPath); + nativePosixSupport.renameat(oldDirFd, oldPath, newDirFd, newPath); } - @ExportMessage - final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { checkNotInPreInitialization(); - nativeLib.replaceat(nativePosixSupport, oldDirFd, oldPath, newDirFd, newPath); + nativePosixSupport.replaceat(oldDirFd, oldPath, newDirFd, newPath); } @ExportMessage From dbd5217e5f40d14c93b50c9b708c7a3cdfebfe9b Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 15:54:33 +0200 Subject: [PATCH 038/129] Convert PosixSupportLibrary access and ownership operations (cherry picked from commit d6a29bb5e10289a1841e0489c0c22fc080ff9a4e) --- .../builtins/modules/PosixModuleBuiltins.java | 24 ++++------- .../python/runtime/EmulatedPosixSupport.java | 23 ++++++----- .../python/runtime/LoggingPosixSupport.java | 40 +++++++++---------- .../python/runtime/NativePosixSupport.java | 15 ++++--- .../graal/python/runtime/PosixSupport.java | 11 +++++ .../python/runtime/PosixSupportLibrary.java | 10 ----- .../python/runtime/PreInitPosixSupport.java | 40 +++++++++---------- 7 files changed, 81 insertions(+), 82 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index fe2a6bb82f..a7b7a5759e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -2339,10 +2339,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static boolean access(PosixPath path, int mode, int dirFd, boolean effectiveIds, boolean followSymlinks, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.faccessat(context.getPosixSupport(), dirFd, path.value, mode, effectiveIds, followSymlinks); + return context.getPosixSupport().faccessat(dirFd, path.value, mode, effectiveIds, followSymlinks); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -2364,11 +2363,10 @@ static PNone fchmod(VirtualFrame frame, int fd, int mode, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHMOD, fd, mode, -1); try { - posixLib.fchmod(context.getPosixSupport(), fd, mode); + context.getPosixSupport().fchmod(fd, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd); } @@ -2394,12 +2392,11 @@ static PNone chmodFollow(VirtualFrame frame, PosixPath path, int mode, int dirFd @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Shared @Cached PRaiseNode raiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHMOD, path.originalObject, mode, dirFdForAudit(dirFd)); try { - posixLib.fchmodat(context.getPosixSupport(), dirFd, path.value, mode, followSymlinks); + context.getPosixSupport().fchmodat(dirFd, path.value, mode, followSymlinks); } catch (PosixException e) { // TODO CPython checks for ENOTSUP as well if (e.hasErrno(OSErrorEnum.EOPNOTSUPP) && !followSymlinks) { @@ -2419,7 +2416,6 @@ static PNone chmodFollow(VirtualFrame frame, PosixFd fd, int mode, int dirFd, @S @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, // unused node to avoid mixing shared and non-shared inlined nodes @SuppressWarnings("unused") @Shared @Cached PRaiseNode raiseNode) { @@ -2429,7 +2425,7 @@ static PNone chmodFollow(VirtualFrame frame, PosixFd fd, int mode, int dirFd, @S // arguments is used, CPython's implementation of chmod simply ignores dir_fd and // follow_symlinks if a fd is specified instead of a path. try { - posixLib.fchmod(context.getPosixSupport(), fd.fd, mode); + context.getPosixSupport().fchmod(fd.fd, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd.originalObject); } @@ -2448,14 +2444,13 @@ static Object chown(VirtualFrame frame, int fd, long uid, long gid, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHOWN, fd, uid, gid, -1); try { gil.release(true); try { - posixLib.fchown(context.getPosixSupport(), fd, uid, gid); + context.getPosixSupport().fchown(fd, uid, gid); } finally { gil.acquire(); } @@ -2482,14 +2477,13 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHOWN, path.originalObject, uid, gid, -1); try { gil.release(true); try { - posixLib.fchownat(context.getPosixSupport(), AT_FDCWD.value, path.value, uid, gid, false); + context.getPosixSupport().fchownat(AT_FDCWD.value, path.value, uid, gid, false); } finally { gil.acquire(); } @@ -2518,7 +2512,6 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, int @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached GilNode gil, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, // unused node to avoid mixing shared and non-shared inlined nodes @@ -2527,7 +2520,7 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, int try { gil.release(true); try { - posixLib.fchownat(context.getPosixSupport(), dirFd, path.value, uid, gid, followSymlinks); + context.getPosixSupport().fchownat(dirFd, path.value, uid, gid, followSymlinks); } finally { gil.acquire(); } @@ -2542,7 +2535,6 @@ static Object chown(VirtualFrame frame, PosixFd fd, long uid, long gid, int dirF @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached GilNode gil, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Shared @Cached PRaiseNode raiseNode) { @@ -2556,7 +2548,7 @@ static Object chown(VirtualFrame frame, PosixFd fd, long uid, long gid, int dirF try { gil.release(true); try { - posixLib.fchown(context.getPosixSupport(), fd.fd, uid, gid); + context.getPosixSupport().fchown(fd.fd, uid, gid); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 769a494afe..8dc27de055 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -366,8 +366,8 @@ public EmulatedPosixSupport(PythonContext context) { withoutIOSocket = !context.getContext().getEnv().isSocketIOAllowed(); } - @TruffleBoundary static UnsupportedPosixFeatureException createUnsupportedFeature(String message) { + CompilerAsserts.neverPartOfCompilation(); // TODO should have a link to some doc that tells you what to do about it return new UnsupportedPosixFeatureException("Feature not supported on 'java' POSIX backend: " + message); } @@ -1844,12 +1844,10 @@ public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath } } - @ExportMessage - public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException { if (effectiveIds) { - errBranch.enter(inliningTarget); throw createUnsupportedFeature("faccess with effective user IDs"); } TruffleFile file; @@ -1869,7 +1867,6 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, if (!followSymlinks) { // TruffleFile#isExecutable/isReadable/isWriteable does not support LinkOptions, but // that's probably because Java NIO does not support NOFOLLOW_LINKS in permissions check - errBranch.enter(inliningTarget); throw createUnsupportedFeature("faccess with effective user IDs"); } boolean result = true; @@ -1885,7 +1882,8 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, return result; } - @ExportMessage + @Override + @TruffleBoundary public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); Set permissions = modeToPosixFilePermissions(mode); @@ -1904,7 +1902,8 @@ public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) t } } - @ExportMessage + @Override + @TruffleBoundary public void fchmod(int fd, int mode) throws PosixException { String path = getFilePath(fd); if (path == null) { @@ -1919,12 +1918,14 @@ public void fchmod(int fd, int mode) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { throw createUnsupportedFeature("fchownat"); } - @ExportMessage + @Override + @TruffleBoundary public void fchown(int fd, long owner, long group) throws PosixException { throw createUnsupportedFeature("fchown"); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index e9d6e8d2ed..2cce658598 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -735,56 +735,56 @@ public final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object n } } - @ExportMessage - final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException { logEnter("faccessAt", "%d, %s, 0%o, %b, %b", dirFd, path, mode, effectiveIds, followSymlinks); try { - return logExit("faccessAt", "%b", lib.faccessat(delegate, dirFd, path, mode, effectiveIds, followSymlinks)); + return logExit("faccessAt", "%b", delegate.faccessat(dirFd, path, mode, effectiveIds, followSymlinks)); } catch (UnsupportedPosixFeatureException e) { throw logException("faccessAt", e); } } - @ExportMessage - final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { logEnter("fchmodat", "%d, %s, 0%o, %b", dirFd, path, mode, followSymlinks); try { - lib.fchmodat(delegate, dirFd, path, mode, followSymlinks); + delegate.fchmodat(dirFd, path, mode, followSymlinks); } catch (PosixException e) { throw logException("fchmodat", e); } } - @ExportMessage - final void fchmod(int fd, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmod(int fd, int mode) throws PosixException { logEnter("fchmod", "%d, 0%o", fd, mode); try { - lib.fchmod(delegate, fd, mode); + delegate.fchmod(fd, mode); } catch (PosixException e) { throw logException("fchmod", e); } } - @ExportMessage - final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { logEnter("fchownat", "%d, %s, %d, %d, %b", dirFd, path, owner, group, followSymlinks); try { - lib.fchownat(delegate, dirFd, path, owner, group, followSymlinks); + delegate.fchownat(dirFd, path, owner, group, followSymlinks); } catch (PosixException e) { throw logException("fchownat", e); } } - @ExportMessage - final void fchown(int fd, long owner, long group, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchown(int fd, long owner, long group) throws PosixException { logEnter("fchown", "%d, %d, %d", fd, owner, group); try { - lib.fchown(delegate, fd, owner, group); + delegate.fchown(fd, owner, group); } catch (PosixException e) { throw logException("fchown", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 587743834c..aad9ab2f03 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1591,7 +1591,8 @@ public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath } } - @ExportMessage + @Override + @TruffleBoundary public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) { long pathPtr = pathToNativeCString(path); int ret; @@ -1606,7 +1607,8 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, return ret == 0; } - @ExportMessage + @Override + @TruffleBoundary public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1619,7 +1621,8 @@ public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) t } } - @ExportMessage + @Override + @TruffleBoundary public void fchmod(int fd, int mode) throws PosixException { int ret = posixNativeFunctionInvoker.call_fchmod(fd, mode); if (ret != 0) { @@ -1627,7 +1630,8 @@ public void fchmod(int fd, int mode) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1640,7 +1644,8 @@ public void fchownat(int dirFd, Object path, long owner, long group, boolean fol } } - @ExportMessage + @Override + @TruffleBoundary public void fchown(int fd, long owner, long group) throws PosixException { int ret = posixNativeFunctionInvoker.call_fchown(fd, owner, group); if (ret != 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index cb514e82d4..20b05b3d00 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -44,6 +44,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -208,5 +209,15 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf public abstract void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; + public abstract boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException; + + public abstract void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException; + + public abstract void fchmod(int fd, int mode) throws PosixException; + + public abstract void fchownat(int dirFd, Object pathname, long owner, long group, boolean followSymlinks) throws PosixException; + + public abstract void fchown(int fd, long owner, long group) throws PosixException; + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 1ac8c126cf..7f7e22487d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,16 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract boolean faccessat(Object receiver, int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException; - - public abstract void fchmodat(Object receiver, int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException; - - public abstract void fchmod(Object receiver, int fd, int mode) throws PosixException; - - public abstract void fchownat(Object receiver, int dirFd, Object pathname, long owner, long group, boolean followSymlinks) throws PosixException; - - public abstract void fchown(Object receiver, int fd, long owner, long group) throws PosixException; - public abstract void raise(Object receiver, int signal) throws PosixException; public abstract int alarm(Object receiver, int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index b239036fab..eadf1d09fe 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -577,39 +577,39 @@ public final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object n nativePosixSupport.replaceat(oldDirFd, oldPath, newDirFd, newPath); } - @ExportMessage - final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.faccessat(nativePosixSupport, dirFd, path, mode, effectiveIds, followSymlinks); + return nativePosixSupport.faccessat(dirFd, path, mode, effectiveIds, followSymlinks); } - @ExportMessage - final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchmodat(nativePosixSupport, dirFd, path, mode, followSymlinks); + nativePosixSupport.fchmodat(dirFd, path, mode, followSymlinks); } - @ExportMessage - final void fchmod(int fd, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmod(int fd, int mode) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchmod(nativePosixSupport, fd, mode); + nativePosixSupport.fchmod(fd, mode); } - @ExportMessage - final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchownat(nativePosixSupport, dirFd, path, owner, group, followSymlinks); + nativePosixSupport.fchownat(dirFd, path, owner, group, followSymlinks); } - @ExportMessage - final void fchown(int fd, long owner, long group, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchown(int fd, long owner, long group) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchown(nativePosixSupport, fd, owner, group); + nativePosixSupport.fchown(fd, owner, group); } @Override From a0270fb2c7e4bbad19cadf6a532e2847bfca2f2c Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:17:47 +0200 Subject: [PATCH 039/129] Convert PosixSupportLibrary signals and timers (cherry picked from commit 222d20974a2b40dfa1222d2119ebdcc4dd13637c) --- .../modules/FaulthandlerModuleBuiltins.java | 11 ++-- .../builtins/modules/PosixModuleBuiltins.java | 6 +- .../modules/SignalModuleBuiltins.java | 14 ++--- .../python/runtime/EmulatedPosixSupport.java | 25 +++++---- .../python/runtime/LoggingPosixSupport.java | 56 +++++++++---------- .../python/runtime/NativePosixSupport.java | 21 ++++--- .../graal/python/runtime/PosixSupport.java | 14 +++++ .../python/runtime/PosixSupportLibrary.java | 14 ----- .../python/runtime/PreInitPosixSupport.java | 56 +++++++++---------- 9 files changed, 108 insertions(+), 109 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java index 9264f75e7f..a664258afa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java @@ -104,7 +104,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -281,10 +280,9 @@ abstract static class SigSegvNode extends PythonUnaryClinicBuiltinNode { static PNone doIt(VirtualFrame frame, boolean releaseGil, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return raiseFatalSignal(frame, context, inliningTarget, posixLib, gil, constructAndRaiseNode, "SEGV", releaseGil); + return raiseFatalSignal(frame, context, inliningTarget, gil, constructAndRaiseNode, "SEGV", releaseGil); } @Override @@ -300,14 +298,13 @@ abstract static class SigAbrtNode extends PythonBuiltinNode { static PNone doIt(VirtualFrame frame, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return raiseFatalSignal(frame, context, inliningTarget, posixLib, gil, constructAndRaiseNode, "ABRT", false); + return raiseFatalSignal(frame, context, inliningTarget, gil, constructAndRaiseNode, "ABRT", false); } } - private static PNone raiseFatalSignal(VirtualFrame frame, PythonContext context, Node inliningTarget, PosixSupportLibrary posixLib, GilNode gil, + private static PNone raiseFatalSignal(VirtualFrame frame, PythonContext context, Node inliningTarget, GilNode gil, PConstructAndRaiseNode.Lazy constructAndRaiseNode, String signalName, boolean releaseGil) { try { int signum = SignalModuleBuiltins.signalFromName(context, signalName); @@ -315,7 +312,7 @@ private static PNone raiseFatalSignal(VirtualFrame frame, PythonContext context, gil.release(true); } try { - posixLib.signalSelf(context.getPosixSupport(), signum); + context.getPosixSupport().signalSelf(signum); } finally { if (releaseGil) { gil.acquire(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index a7b7a5759e..6b636f8951 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -3036,11 +3036,10 @@ static PNone kill(VirtualFrame frame, long pid, int signal, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_KILL, pid, signal); try { - posixLib.kill(context.getPosixSupport(), pid, signal); + context.getPosixSupport().kill(pid, signal); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -3063,11 +3062,10 @@ static PNone kill(VirtualFrame frame, long pid, int signal, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_KILLPG, pid, signal); try { - posixLib.killpg(context.getPosixSupport(), pid, signal); + context.getPosixSupport().killpg(pid, signal); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java index b832b16b2a..f80e547447 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java @@ -82,7 +82,6 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.AsyncHandler; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; @@ -99,7 +98,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -298,10 +296,9 @@ abstract static class AlarmNode extends PythonUnaryClinicBuiltinNode { static int alarm(VirtualFrame frame, int seconds, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.alarm(context.getPosixSupport(), seconds); + return context.getPosixSupport().alarm(seconds); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -474,10 +471,9 @@ abstract static class RaiseSignalNode extends PythonUnaryClinicBuiltinNode { static PNone doInt(VirtualFrame frame, int signum, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.raise(context.getPosixSupport(), signum); + context.getPosixSupport().raise(signum); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -504,14 +500,13 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object doIt(VirtualFrame frame, int which, Object seconds, Object interval, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PyTimeFromObjectNode timeFromObjectNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language) { Timeval delay = toTimeval(frame, inliningTarget, seconds, timeFromObjectNode); Timeval intervalTimeval = toTimeval(frame, inliningTarget, interval, timeFromObjectNode); try { - return createResultTuple(language, posixLib.setitimer(context.getPosixSupport(), which, delay, intervalTimeval)); + return createResultTuple(language, context.getPosixSupport().setitimer(which, delay, intervalTimeval)); } catch (PosixException e) { throw raiseItimerError(frame, inliningTarget, e, constructAndRaiseNode); } @@ -556,11 +551,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object doIt(VirtualFrame frame, int which, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language) { try { - return SetitimerNode.createResultTuple(language, posixLib.getitimer(context.getPosixSupport(), which)); + return SetitimerNode.createResultTuple(language, context.getPosixSupport().getitimer(which)); } catch (PosixException e) { throw SetitimerNode.raiseItimerError(frame, inliningTarget, e, constructAndRaiseNode); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 8dc27de055..4c43d2e193 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -1946,10 +1946,10 @@ public Object readlinkat(int dirFd, Object path) throws PosixException { } } - @ExportMessage - public void kill(long pid, int signal, - @Bind Node inliningTarget) throws PosixException { - PythonContext context = PythonContext.get(inliningTarget); + @Override + @TruffleBoundary + public void kill(long pid, int signal) throws PosixException { + PythonContext context = this.context; try { if (signal == signalFromName(context, "KILL")) { sigkill((int) pid); @@ -1965,13 +1965,14 @@ public void kill(long pid, int signal, } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void raise(int signal) throws PosixException { throw createUnsupportedFeature("raise"); } - @ExportMessage + @Override @TruffleBoundary public synchronized int alarm(int seconds) { int remaining = 0; @@ -1991,7 +1992,7 @@ public synchronized int alarm(int seconds) { return remaining; } - @ExportMessage + @Override @TruffleBoundary public synchronized Timeval[] getitimer(int which) throws PosixException { if (which != 0) { @@ -2000,7 +2001,7 @@ public synchronized Timeval[] getitimer(int which) throws PosixException { return currentItimer(); } - @ExportMessage + @Override @TruffleBoundary public synchronized Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { if (which != 0 || delay.getSeconds() < 0 || delay.getMicroseconds() < 0 || interval.getSeconds() < 0 || interval.getMicroseconds() < 0) { @@ -2097,15 +2098,17 @@ int getRemainingSeconds() { } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void signalSelf(int signal) throws PosixException { throw createUnsupportedFeature("signalSelf"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public long killpg(long pgid, int signal) throws PosixException { + public void killpg(long pgid, int signal) throws PosixException { throw createUnsupportedFeature("killpg"); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 2cce658598..e406206583 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -800,78 +800,78 @@ public final Object readlinkat(int dirFd, Object path) throws PosixException { } } - @ExportMessage - final void kill(long pid, int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void kill(long pid, int signal) throws PosixException { logEnter("kill", "%d, %d", pid, signal); try { - lib.kill(delegate, pid, signal); + delegate.kill(pid, signal); } catch (PosixException e) { throw logException("kill", e); } } - @ExportMessage - final void raise(int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void raise(int signal) throws PosixException { logEnter("raise", "%d", signal); try { - lib.raise(delegate, signal); + delegate.raise(signal); } catch (PosixException e) { throw logException("raise", e); } } - @ExportMessage - final int alarm(int seconds, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int alarm(int seconds) throws PosixException { logEnter("alarm", "%d", seconds); try { - return logExit("alarm", "%d", lib.alarm(delegate, seconds)); + return logExit("alarm", "%d", delegate.alarm(seconds)); } catch (PosixException e) { throw logException("alarm", e); } } - @ExportMessage - final Timeval[] getitimer(int which, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] getitimer(int which) throws PosixException { logEnter("getitimer", "%d", which); try { - return logExit("getitimer", "%s", lib.getitimer(delegate, which)); + return logExit("getitimer", "%s", delegate.getitimer(which)); } catch (PosixException e) { throw logException("getitimer", e); } } - @ExportMessage - final Timeval[] setitimer(int which, Timeval delay, Timeval interval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { logEnter("setitimer", "%d, %s, %s", which, delay, interval); try { - return logExit("setitimer", "%s", lib.setitimer(delegate, which, delay, interval)); + return logExit("setitimer", "%s", delegate.setitimer(which, delay, interval)); } catch (PosixException e) { throw logException("setitimer", e); } } - @ExportMessage - final void signalSelf(int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void signalSelf(int signal) throws PosixException { logEnter("signalSelf", "%d", signal); try { - lib.signalSelf(delegate, signal); + delegate.signalSelf(signal); } catch (PosixException e) { throw logException("signalSelf", e); } } - @ExportMessage - final void killpg(long pgid, int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void killpg(long pgid, int signal) throws PosixException { logEnter("killpg", "%d, %d", pgid, signal); try { - lib.killpg(delegate, pgid, signal); + delegate.killpg(pgid, signal); } catch (PosixException e) { throw logException("killpg", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index aad9ab2f03..79c1850cd9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1677,7 +1677,8 @@ public Object readlinkat(int dirFd, Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void kill(long pid, int signal) throws PosixException { int res = posixNativeFunctionInvoker.call_kill(pid, signal); if (res == -1) { @@ -1685,7 +1686,8 @@ public void kill(long pid, int signal) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void raise(int signal) throws PosixException { int res = posixNativeFunctionInvoker.call_raise(signal); if (res != 0) { @@ -1693,12 +1695,14 @@ public void raise(int signal) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int alarm(int seconds) { return posixNativeFunctionInvoker.call_alarm(seconds); } - @ExportMessage + @Override + @TruffleBoundary public Timeval[] getitimer(int which) throws PosixException { long nativeCurrentValue = NativeMemory.mallocLongArray(4); try { @@ -1712,7 +1716,8 @@ public Timeval[] getitimer(int which) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { long nativeNewValue = NULLPTR; long nativeOldValue = NULLPTR; @@ -1730,7 +1735,8 @@ public Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws Po } } - @ExportMessage + @Override + @TruffleBoundary public void signalSelf(int signal) throws PosixException { if (!ImageInfo.inImageRuntimeCode()) { throw new UnsupportedPosixFeatureException("self-signals are only supported in native standalone"); @@ -1741,7 +1747,8 @@ public void signalSelf(int signal) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void killpg(long pgid, int signal) throws PosixException { int res = posixNativeFunctionInvoker.call_killpg(pgid, signal); if (res == -1) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 20b05b3d00..2aa0ad1817 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -64,6 +64,20 @@ public static PosixSupport get(Node node) { return PythonContext.get(node).getPosixSupport(); } + public abstract void raise(int signal) throws PosixException; + + public abstract int alarm(int seconds) throws PosixException; + + public abstract Timeval[] getitimer(int which) throws PosixException; + + public abstract Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException; + + public abstract void signalSelf(int signal) throws PosixException; + + public abstract void kill(long pid, int signal) throws PosixException; + + public abstract void killpg(long pid, int signal) throws PosixException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 7f7e22487d..6581078fa2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,20 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract void raise(Object receiver, int signal) throws PosixException; - - public abstract int alarm(Object receiver, int seconds) throws PosixException; - - public abstract Timeval[] getitimer(Object receiver, int which) throws PosixException; - - public abstract Timeval[] setitimer(Object receiver, int which, Timeval delay, Timeval interval) throws PosixException; - - public abstract void signalSelf(Object receiver, int signal) throws PosixException; - - public abstract void kill(Object receiver, long pid, int signal) throws PosixException; - - public abstract void killpg(Object receiver, long pid, int signal) throws PosixException; - public abstract long[] waitpid(Object receiver, long pid, int options) throws PosixException; public abstract boolean wcoredump(Object receiver, int status); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index eadf1d09fe..ca1d40a604 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -618,53 +618,53 @@ public final Object readlinkat(int dirFd, Object path) throws PosixException { return nativePosixSupport.readlinkat(dirFd, path); } - @ExportMessage - final void raise(int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void raise(int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.raise(nativePosixSupport, signal); + nativePosixSupport.raise(signal); } - @ExportMessage - final int alarm(int seconds, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int alarm(int seconds) throws PosixException { checkNotInPreInitialization(); - return nativeLib.alarm(nativePosixSupport, seconds); + return nativePosixSupport.alarm(seconds); } - @ExportMessage - final Timeval[] getitimer(int which, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] getitimer(int which) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getitimer(nativePosixSupport, which); + return nativePosixSupport.getitimer(which); } - @ExportMessage - final Timeval[] setitimer(int which, Timeval delay, Timeval interval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { checkNotInPreInitialization(); - return nativeLib.setitimer(nativePosixSupport, which, delay, interval); + return nativePosixSupport.setitimer(which, delay, interval); } - @ExportMessage - final void signalSelf(int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void signalSelf(int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.signalSelf(nativePosixSupport, signal); + nativePosixSupport.signalSelf(signal); } - @ExportMessage - final void kill(long pid, int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void kill(long pid, int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.kill(nativePosixSupport, pid, signal); + nativePosixSupport.kill(pid, signal); } - @ExportMessage - final void killpg(long pgid, int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void killpg(long pgid, int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.killpg(nativePosixSupport, pgid, signal); + nativePosixSupport.killpg(pgid, signal); } @ExportMessage From 1f27018c61680fb3e4cba1c26ee866550dc60b77 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:20:46 +0200 Subject: [PATCH 040/129] Convert PosixSupportLibrary process waiting (cherry picked from commit 6a74bf7b7ef8acb8d589fe11a7d291050339adba) --- .../python/builtins/modules/PosixModuleBuiltins.java | 3 +-- .../graal/python/runtime/EmulatedPosixSupport.java | 8 ++++---- .../oracle/graal/python/runtime/LoggingPosixSupport.java | 8 ++++---- .../oracle/graal/python/runtime/NativePosixSupport.java | 6 +++--- .../com/oracle/graal/python/runtime/PosixSupport.java | 2 ++ .../oracle/graal/python/runtime/PosixSupportLibrary.java | 2 -- .../oracle/graal/python/runtime/PreInitPosixSupport.java | 9 +++++---- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 6b636f8951..a72ed0b881 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -2667,14 +2667,13 @@ static PTuple waitpid(VirtualFrame frame, long pid, int options, @Bind Node inliningTarget, @Cached GilNode gil, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { gil.release(true); try { while (true) { try { - long[] result = posixLib.waitpid(context.getPosixSupport(), pid, options); + long[] result = context.getPosixSupport().waitpid(inliningTarget, pid, options); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{result[0], result[1]}); } catch (PosixException e) { errorProfile.enter(inliningTarget); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 4c43d2e193..cf8387fd93 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2112,13 +2112,13 @@ public void killpg(long pgid, int signal) throws PosixException { throw createUnsupportedFeature("killpg"); } - @ExportMessage - public long[] waitpid(long pid, int options, - @CachedLibrary("this") PosixSupportLibrary posixLib) throws PosixException { + @Override + @TruffleBoundary + public long[] waitpid(Node location, long pid, int options) throws PosixException { try { if (options == 0) { int[] exitStatus = new int[1]; - TruffleSafepoint.setBlockedThreadInterruptible(posixLib, (s) -> { + TruffleSafepoint.setBlockedThreadInterruptible(location, (s) -> { exitStatus[0] = s.waitpid((int) pid); }, this); return new long[]{pid, exitStatus[0]}; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index e406206583..7404ea5a73 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -888,12 +888,12 @@ public Object mmap(long length, int prot, int flags, int fd, long offset, Object } } - @ExportMessage - final long[] waitpid(long pid, int options, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] waitpid(Node location, long pid, int options) throws PosixException { logEnter("waitpid", "%d, %d", pid, options); try { - return logExit("waitpid", "%s", lib.waitpid(delegate, pid, options)); + return logExit("waitpid", "%s", delegate.waitpid(location, pid, options)); } catch (PosixException e) { throw logException("waitpid", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 79c1850cd9..05cdd8d855 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1756,9 +1756,9 @@ public void killpg(long pgid, int signal) throws PosixException { } } - @ExportMessage - public long[] waitpid(long pid, int options, - @Bind Node node) throws PosixException { + @Override + @TruffleBoundary + public long[] waitpid(Node node, long pid, int options) throws PosixException { boolean hasNohang = (options & WNOHANG.getValueIfDefined()) != 0; int subOptions = options | WNOHANG.getValueIfDefined(); long nativeStatus = NativeMemory.callocIntArray(1); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 2aa0ad1817..4e4502eeb0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -78,6 +78,8 @@ public static PosixSupport get(Node node) { public abstract void killpg(long pid, int signal) throws PosixException; + public abstract long[] waitpid(Node location, long pid, int options) throws PosixException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 6581078fa2..b0bf28747e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,8 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract long[] waitpid(Object receiver, long pid, int options) throws PosixException; - public abstract boolean wcoredump(Object receiver, int status); public abstract boolean wifcontinued(Object receiver, int status); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index ca1d40a604..72c845c849 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -68,6 +68,7 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @ExportLibrary(PosixSupportLibrary.class) @@ -667,11 +668,11 @@ public final void killpg(long pgid, int signal) throws PosixException { nativePosixSupport.killpg(pgid, signal); } - @ExportMessage - final long[] waitpid(long pid, int options, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] waitpid(Node location, long pid, int options) throws PosixException { checkNotInPreInitialization(); - return nativeLib.waitpid(nativePosixSupport, pid, options); + return nativePosixSupport.waitpid(location, pid, options); } @ExportMessage From fc80cf45850a4a8d6b91ccb5d8b8ec0b81e98398 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:25:11 +0200 Subject: [PATCH 041/129] Convert PosixSupportLibrary wait-status decoding (cherry picked from commit 46f5ca33342c49d981cde8f1e64f685c037ec7c4) --- .../builtins/modules/PosixModuleBuiltins.java | 53 +++++++-------- .../python/runtime/EmulatedPosixSupport.java | 24 ++++--- .../python/runtime/LoggingPosixSupport.java | 64 +++++++++---------- .../python/runtime/NativePosixSupport.java | 24 ++++--- .../graal/python/runtime/PosixSupport.java | 16 +++++ .../python/runtime/PosixSupportLibrary.java | 16 ----- .../python/runtime/PreInitPosixSupport.java | 64 +++++++++---------- 7 files changed, 134 insertions(+), 127 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index a72ed0b881..127027c33d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -2697,28 +2697,27 @@ abstract static class WaitstatusToExitcodeNode extends PythonUnaryBuiltinNode { @Specialization static int waitstatusToExitcode(VirtualFrame frame, Object statusObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached PyLongAsIntNode longAsInt, @Cached PRaiseNode raiseNode) { int status = longAsInt.execute(frame, inliningTarget, statusObj); PosixSupport posixSupport = context.getPosixSupport(); - if (posixLib.wifexited(posixSupport, status)) { - int exitcode = posixLib.wexitstatus(posixSupport, status); + if (posixSupport.wifexited(status)) { + int exitcode = posixSupport.wexitstatus(status); if (exitcode < 0) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.INVALID_WEXITSTATUS, exitcode); } return exitcode; } - if (posixLib.wifsignaled(posixSupport, status)) { - int signum = posixLib.wtermsig(posixSupport, status); + if (posixSupport.wifsignaled(status)) { + int signum = posixSupport.wtermsig(status); if (signum <= 0) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.INVALID_WTERMSIG, signum); } return -signum; } - if (posixLib.wifstopped(posixSupport, status)) { - int signum = posixLib.wstopsig(posixSupport, status); + if (posixSupport.wifstopped(status)) { + int signum = posixSupport.wstopsig(status); throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.PROCESS_STOPPED_BY_DELIVERY_OF_SIGNAL, signum); } throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.INVALID_WAIT_STATUS, status); @@ -2736,9 +2735,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wcoredump(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wcoredump(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wcoredump(status); } } @@ -2753,9 +2751,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifcontinued(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifcontinued(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifcontinued(status); } } @@ -2770,9 +2767,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifstopped(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifstopped(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifstopped(status); } } @@ -2787,9 +2783,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifsignaled(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifsignaled(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifsignaled(status); } } @@ -2804,9 +2799,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifexited(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifexited(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifexited(status); } } @@ -2821,9 +2815,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static int wexitstatus(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wexitstatus(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wexitstatus(status); } } @@ -2838,9 +2831,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization int wtermsig(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wtermsig(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wtermsig(status); } } @@ -2855,9 +2847,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static int wstopsig(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wstopsig(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wstopsig(status); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index cf8387fd93..9369d566ca 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2148,49 +2148,57 @@ private static void interruptThread() { // TODO the implementation of the following builtins is taken from posix.py, // do they really make sense for the emulated backend? Is the handling of exist status correct? - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wcoredump(int status) { return false; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifcontinued(int status) { return false; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifstopped(int status) { return false; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifsignaled(int status) { return status > 128; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifexited(int status) { return !wifsignaled(status); } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public int wexitstatus(int status) { return status & 127; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public int wtermsig(int status) { return status - 128; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public int wstopsig(int status) { return 0; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 7404ea5a73..4f1bdc716e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -921,60 +921,60 @@ public void mmapWriteByte(Object mmap, long index, byte value, } } - @ExportMessage - final boolean wcoredump(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wcoredump(int status) { logEnter("wcoredump", "%d", status); - return logExit("wcoredump", "%b", lib.wcoredump(delegate, status)); + return logExit("wcoredump", "%b", delegate.wcoredump(status)); } - @ExportMessage - final boolean wifcontinued(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifcontinued(int status) { logEnter("wifcontinued", "%d", status); - return logExit("wifcontinued", "%b", lib.wifcontinued(delegate, status)); + return logExit("wifcontinued", "%b", delegate.wifcontinued(status)); } - @ExportMessage - final boolean wifstopped(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifstopped(int status) { logEnter("wifstopped", "%d", status); - return logExit("wifstopped", "%b", lib.wifstopped(delegate, status)); + return logExit("wifstopped", "%b", delegate.wifstopped(status)); } - @ExportMessage - final boolean wifsignaled(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifsignaled(int status) { logEnter("wifsignaled", "%d", status); - return logExit("wifsignaled", "%b", lib.wifsignaled(delegate, status)); + return logExit("wifsignaled", "%b", delegate.wifsignaled(status)); } - @ExportMessage - final boolean wifexited(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifexited(int status) { logEnter("wifexited", "%d", status); - return logExit("wifexited", "%b", lib.wifexited(delegate, status)); + return logExit("wifexited", "%b", delegate.wifexited(status)); } - @ExportMessage - final int wexitstatus(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int wexitstatus(int status) { logEnter("wexitstatus", "%d", status); - return logExit("wexitstatus", "%d", lib.wexitstatus(delegate, status)); + return logExit("wexitstatus", "%d", delegate.wexitstatus(status)); } - @ExportMessage - final int wtermsig(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int wtermsig(int status) { logEnter("wtermsig", "%d", status); - return logExit("wtermsig", "%d", lib.wtermsig(delegate, status)); + return logExit("wtermsig", "%d", delegate.wtermsig(status)); } - @ExportMessage - final int wstopsig(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int wstopsig(int status) { logEnter("wstopsig", "%d", status); - return logExit("wstopsig", "%d", lib.wstopsig(delegate, status)); + return logExit("wstopsig", "%d", delegate.wstopsig(status)); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 05cdd8d855..0ec6e87d74 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1779,42 +1779,50 @@ public long[] waitpid(Node node, long pid, int options) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wcoredump(int status) { return posixNativeFunctionInvoker.call_wcoredump(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifcontinued(int status) { return posixNativeFunctionInvoker.call_wifcontinued(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifstopped(int status) { return posixNativeFunctionInvoker.call_wifstopped(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifsignaled(int status) { return posixNativeFunctionInvoker.call_wifsignaled(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifexited(int status) { return posixNativeFunctionInvoker.call_wifexited(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public int wexitstatus(int status) { return posixNativeFunctionInvoker.call_wexitstatus(status); } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public int wtermsig(int status) { return posixNativeFunctionInvoker.call_wtermsig(status); } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public int wstopsig(int status) { return posixNativeFunctionInvoker.call_wstopsig(status); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 4e4502eeb0..92ab893b37 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -80,6 +80,22 @@ public static PosixSupport get(Node node) { public abstract long[] waitpid(Node location, long pid, int options) throws PosixException; + public abstract boolean wcoredump(int status); + + public abstract boolean wifcontinued(int status); + + public abstract boolean wifstopped(int status); + + public abstract boolean wifsignaled(int status); + + public abstract boolean wifexited(int status); + + public abstract int wexitstatus(int status); + + public abstract int wtermsig(int status); + + public abstract int wstopsig(int status); + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index b0bf28747e..2fc8b8fdc6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,22 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract boolean wcoredump(Object receiver, int status); - - public abstract boolean wifcontinued(Object receiver, int status); - - public abstract boolean wifstopped(Object receiver, int status); - - public abstract boolean wifsignaled(Object receiver, int status); - - public abstract boolean wifexited(Object receiver, int status); - - public abstract int wexitstatus(Object receiver, int status); - - public abstract int wtermsig(Object receiver, int status); - - public abstract int wstopsig(Object receiver, int status); - public abstract long getuid(Object receiver); public abstract long geteuid(Object receiver) throws UnsupportedPosixFeatureException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 72c845c849..f87049178a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -675,60 +675,60 @@ public final long[] waitpid(Node location, long pid, int options) throws PosixEx return nativePosixSupport.waitpid(location, pid, options); } - @ExportMessage - final boolean wcoredump(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wcoredump(int status) { checkNotInPreInitialization(); - return nativeLib.wcoredump(nativePosixSupport, status); + return nativePosixSupport.wcoredump(status); } - @ExportMessage - final boolean wifcontinued(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifcontinued(int status) { checkNotInPreInitialization(); - return nativeLib.wifcontinued(nativePosixSupport, status); + return nativePosixSupport.wifcontinued(status); } - @ExportMessage - final boolean wifstopped(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifstopped(int status) { checkNotInPreInitialization(); - return nativeLib.wifstopped(nativePosixSupport, status); + return nativePosixSupport.wifstopped(status); } - @ExportMessage - final boolean wifsignaled(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifsignaled(int status) { checkNotInPreInitialization(); - return nativeLib.wifsignaled(nativePosixSupport, status); + return nativePosixSupport.wifsignaled(status); } - @ExportMessage - final boolean wifexited(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifexited(int status) { checkNotInPreInitialization(); - return nativeLib.wifexited(nativePosixSupport, status); + return nativePosixSupport.wifexited(status); } - @ExportMessage - final int wexitstatus(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int wexitstatus(int status) { checkNotInPreInitialization(); - return nativeLib.wexitstatus(nativePosixSupport, status); + return nativePosixSupport.wexitstatus(status); } - @ExportMessage - final int wtermsig(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int wtermsig(int status) { checkNotInPreInitialization(); - return nativeLib.wtermsig(nativePosixSupport, status); + return nativePosixSupport.wtermsig(status); } - @ExportMessage - final int wstopsig(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int wstopsig(int status) { checkNotInPreInitialization(); - return nativeLib.wstopsig(nativePosixSupport, status); + return nativePosixSupport.wstopsig(status); } @ExportMessage From 374efaa0eb639cb112696ee9d46e96194f1a804b Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:29:10 +0200 Subject: [PATCH 042/129] Convert PosixSupportLibrary user and group identity (cherry picked from commit 0b2121879a841d07a128fd8fe5074451ccbbabcb) --- .../builtins/modules/PosixModuleBuiltins.java | 19 ++++----- .../python/runtime/EmulatedPosixSupport.java | 10 ++--- .../python/runtime/LoggingPosixSupport.java | 40 +++++++++---------- .../python/runtime/NativePosixSupport.java | 15 ++++--- .../graal/python/runtime/PosixSupport.java | 10 +++++ .../python/runtime/PosixSupportLibrary.java | 10 ----- .../python/runtime/PreInitPosixSupport.java | 36 +++++++++-------- 7 files changed, 72 insertions(+), 68 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 127027c33d..d451d6bf75 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -627,9 +627,8 @@ static long getPid(@Bind PythonContext context) { @GenerateNodeFactory public abstract static class GetUidNode extends PythonBuiltinNode { @Specialization - static long getUid(@Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getuid(context.getPosixSupport()); + static long getUid(@Bind PythonContext context) { + return context.getPosixSupport().getuid(); } } @@ -639,10 +638,9 @@ public abstract static class GetEUidNode extends PythonBuiltinNode { @Specialization static long getUid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.geteuid(context.getPosixSupport()); + return context.getPosixSupport().geteuid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -653,9 +651,8 @@ static long getUid(@Bind Node inliningTarget, @GenerateNodeFactory public abstract static class GetGidNode extends PythonBuiltinNode { @Specialization - static long getGid(@Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getgid(context.getPosixSupport()); + static long getGid(@Bind PythonContext context) { + return context.getPosixSupport().getgid(); } } @@ -665,10 +662,9 @@ public abstract static class GetEGidNode extends PythonBuiltinNode { @Specialization static long getGid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getegid(context.getPosixSupport()); + return context.getPosixSupport().getegid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -849,10 +845,9 @@ abstract static class GetGroupsNode extends PythonBuiltinNode { static Object getgroups(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - long[] groups = posixLib.getgroups(context.getPosixSupport()); + long[] groups = context.getPosixSupport().getgroups(); return PFactory.createList(context.getLanguage(inliningTarget), new LongSequenceStorage(groups)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 9369d566ca..0403991a75 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2204,7 +2204,7 @@ public int wstopsig(int status) { return 0; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long getuid() { @@ -2220,14 +2220,14 @@ public long getuid() { return 1000; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long geteuid() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("geteuid"); } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long getgid() { @@ -2243,7 +2243,7 @@ public long getgid() { return 1000; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long getegid() throws UnsupportedPosixFeatureException { @@ -2286,7 +2286,7 @@ public long setsid() throws PosixException { throw createUnsupportedFeature("getsid"); } - @ExportMessage + @Override @TruffleBoundary public long[] getgroups() throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 4f1bdc716e..34d1122a7c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -977,37 +977,37 @@ public final int wstopsig(int status) { return logExit("wstopsig", "%d", delegate.wstopsig(status)); } - @ExportMessage - final long getuid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final long getuid() { logEnter("getuid", ""); - return logExit("getuid", "%d", lib.getuid(delegate)); + return logExit("getuid", "%d", delegate.getuid()); } - @ExportMessage - final long geteuid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long geteuid() throws UnsupportedPosixFeatureException { logEnter("geteuid", ""); try { - return logExit("geteuid", "%d", lib.geteuid(delegate)); + return logExit("geteuid", "%d", delegate.geteuid()); } catch (UnsupportedPosixFeatureException e) { throw logException("geteuid", e); } } - @ExportMessage - final long getgid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final long getgid() { logEnter("getgid", ""); - return logExit("getgid", "%d", lib.getgid(delegate)); + return logExit("getgid", "%d", delegate.getgid()); } - @ExportMessage - final long getegid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getegid() throws UnsupportedPosixFeatureException { logEnter("getegid", ""); try { - return logExit("getegid", "%d", lib.getegid(delegate)); + return logExit("getegid", "%d", delegate.getegid()); } catch (UnsupportedPosixFeatureException e) { throw logException("getegid", e); } @@ -1079,12 +1079,12 @@ final long setsid( } } - @ExportMessage - final long[] getgroups( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] getgroups() throws PosixException { logEnter("getgroups", ""); try { - return logExit("getgroups", "%s", lib.getgroups(delegate)); + return logExit("getgroups", "%s", delegate.getgroups()); } catch (PosixException e) { throw logException("getgroups", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 0ec6e87d74..a1b1e9cf3e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1827,22 +1827,26 @@ public int wstopsig(int status) { return posixNativeFunctionInvoker.call_wstopsig(status); } - @ExportMessage + @Override + @TruffleBoundary public long getuid() { return posixNativeFunctionInvoker.call_getuid(); } - @ExportMessage + @Override + @TruffleBoundary public long geteuid() { return posixNativeFunctionInvoker.call_geteuid(); } - @ExportMessage + @Override + @TruffleBoundary public long getgid() { return posixNativeFunctionInvoker.call_getgid(); } - @ExportMessage + @Override + @TruffleBoundary public long getegid() { return posixNativeFunctionInvoker.call_getegid(); } @@ -1892,7 +1896,8 @@ public long setsid() throws PosixException { return res; } - @ExportMessage + @Override + @TruffleBoundary public long[] getgroups() throws PosixException { // The first call gets us the number of groups, so we can allocate the output array int res = posixNativeFunctionInvoker.call_getgroups(0, NULLPTR); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 92ab893b37..7b4f0445b1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -96,6 +96,16 @@ public static PosixSupport get(Node node) { public abstract int wstopsig(int status); + public abstract long getuid(); + + public abstract long geteuid() throws UnsupportedPosixFeatureException; + + public abstract long getgid(); + + public abstract long getegid() throws UnsupportedPosixFeatureException; + + public abstract long[] getgroups() throws PosixException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 2fc8b8fdc6..0cea667bda 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,14 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract long getuid(Object receiver); - - public abstract long geteuid(Object receiver) throws UnsupportedPosixFeatureException; - - public abstract long getgid(Object receiver); - - public abstract long getegid(Object receiver) throws UnsupportedPosixFeatureException; - public abstract long getppid(Object receiver) throws UnsupportedPosixFeatureException; public abstract long getpgid(Object receiver, long pid) throws PosixException; @@ -99,8 +91,6 @@ public abstract class PosixSupportLibrary extends Library { public abstract long setsid(Object receiver) throws PosixException; - public abstract long[] getgroups(Object receiver) throws PosixException; - /** * Equivalent to struct r_usage with the fields expected on macOS and Linux. * diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index f87049178a..f3c31c3ee7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -731,28 +731,32 @@ public final int wstopsig(int status) { return nativePosixSupport.wstopsig(status); } - @ExportMessage - final long getuid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final long getuid() { checkNotInPreInitialization(); - return nativeLib.getuid(nativePosixSupport); + return nativePosixSupport.getuid(); } - @ExportMessage - final long geteuid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long geteuid() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.geteuid(nativePosixSupport); + return nativePosixSupport.geteuid(); } - @ExportMessage - final long getgid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final long getgid() { checkNotInPreInitialization(); - return nativeLib.getgid(nativePosixSupport); + return nativePosixSupport.getgid(); } - @ExportMessage - final long getegid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getegid() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.getegid(nativePosixSupport); + return nativePosixSupport.getegid(); } @ExportMessage @@ -795,11 +799,11 @@ final long setsid( return nativeLib.setsid(nativePosixSupport); } - @ExportMessage - final long[] getgroups( - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] getgroups() throws PosixException { checkNotInPreInitialization(); - return nativeLib.getgroups(nativePosixSupport); + return nativePosixSupport.getgroups(); } @ExportMessage From 03621ec8f125997258a5c17bd3d64be81f00996a Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:34:45 +0200 Subject: [PATCH 043/129] Convert PosixSupportLibrary process groups and usage (cherry picked from commit 896e0a3de79984717e80e5ee43fdcdb73d49f8b0) --- .../builtins/modules/PosixModuleBuiltins.java | 21 +++---- .../modules/ResourceModuleBuiltins.java | 5 +- .../python/runtime/EmulatedPosixSupport.java | 20 ++++--- .../python/runtime/LoggingPosixSupport.java | 56 +++++++++---------- .../python/runtime/NativePosixSupport.java | 21 ++++--- .../graal/python/runtime/PosixSupport.java | 15 +++++ .../python/runtime/PosixSupportLibrary.java | 14 ----- .../python/runtime/PreInitPosixSupport.java | 54 +++++++++--------- 8 files changed, 106 insertions(+), 100 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index d451d6bf75..700567350b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -677,10 +677,9 @@ public abstract static class GetPpidNode extends PythonBuiltinNode { @Specialization static long getPpid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getppid(context.getPosixSupport()); + return context.getPosixSupport().getppid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -727,10 +726,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static long getPgid(VirtualFrame frame, long pid, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getpgid(context.getPosixSupport(), pid); + return context.getPosixSupport().getpgid(pid); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -751,10 +749,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object setPgid(VirtualFrame frame, long pid, long pgid, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setpgid(context.getPosixSupport(), pid, pgid); + context.getPosixSupport().setpgid(pid, pgid); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -769,10 +766,9 @@ public abstract static class SetPgrpdNode extends PythonBuiltinNode { static Object getPpid(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setpgid(context.getPosixSupport(), 0, 0); + context.getPosixSupport().setpgid(0, 0); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -786,10 +782,9 @@ public abstract static class GetPgrpNode extends PythonBuiltinNode { @Specialization static long getPpid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getpgrp(context.getPosixSupport()); + return context.getPosixSupport().getpgrp(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -809,10 +804,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static long getSid(VirtualFrame frame, long pid, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getsid(context.getPosixSupport(), pid); + return context.getPosixSupport().getsid(pid); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -827,10 +821,9 @@ public abstract static class SetSidNode extends PythonBuiltinNode { static Object setsid(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setsid(context.getPosixSupport()); + context.getPosixSupport().setsid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java index 59f59a6a52..8d4258b3ee 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java @@ -60,7 +60,6 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; import com.oracle.graal.python.runtime.PythonContext; @@ -72,7 +71,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(defineModule = "resource") @@ -155,13 +153,12 @@ abstract static class GetRuUsageNode extends PythonBuiltinNode { static PTuple getruusage(VirtualFrame frame, int who, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { PosixSupport posixSupport = context.getPosixSupport(); RusageResult rusage; try { - rusage = posixLib.getrusage(posixSupport, who); + rusage = posixSupport.getrusage(who); } catch (PosixException e) { if (e.hasErrno(OSErrorEnum.EINVAL)) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.RUSAGE_INVALID_WHO); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 0403991a75..0cb35bfb6f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2250,37 +2250,43 @@ public long getegid() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("getegid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getppid() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("getppid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getpgid(long pid) throws PosixException { throw createUnsupportedFeature("getpgid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void setpgid(long pid, long pgid) throws PosixException { throw createUnsupportedFeature("setpgid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getpgrp() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("getpgrp"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getsid(long pid) throws PosixException { throw createUnsupportedFeature("getsid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long setsid() throws PosixException { throw createUnsupportedFeature("getsid"); @@ -2300,7 +2306,7 @@ public long[] getgroups() throws PosixException { throw new UnsupportedPosixFeatureException("getgroups was excluded"); } - @ExportMessage + @Override @TruffleBoundary public RusageResult getrusage(int who) throws PosixException { Runtime runtime = Runtime.getRuntime(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 34d1122a7c..2ba931ddaa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1013,67 +1013,67 @@ public final long getegid() throws UnsupportedPosixFeatureException { } } - @ExportMessage - final long getppid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getppid() throws UnsupportedPosixFeatureException { logEnter("getppid", ""); try { - return logExit("getppid", "%d", lib.getppid(delegate)); + return logExit("getppid", "%d", delegate.getppid()); } catch (UnsupportedPosixFeatureException e) { throw logException("getppid", e); } } - @ExportMessage - final long getpgid(long pid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long getpgid(long pid) throws PosixException { logEnter("getpgid", "%d", pid); try { - return logExit("getpgid", "%d", lib.getpgid(delegate, pid)); + return logExit("getpgid", "%d", delegate.getpgid(pid)); } catch (PosixException e) { throw logException("getpgid", e); } } - @ExportMessage - final void setpgid(long pid, long pgid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setpgid(long pid, long pgid) throws PosixException { logEnter("setpgid", "%d, %d", pid, pgid); try { - lib.setpgid(delegate, pid, pgid); + delegate.setpgid(pid, pgid); } catch (PosixException e) { throw logException("setpgid", e); } } - @ExportMessage - final long getpgrp( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getpgrp() throws UnsupportedPosixFeatureException { logEnter("getpgrp", ""); try { - return logExit("getpgrp", "%d", lib.getpgrp(delegate)); + return logExit("getpgrp", "%d", delegate.getpgrp()); } catch (UnsupportedPosixFeatureException e) { throw logException("getpgrp", e); } } - @ExportMessage - final long getsid(long pid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long getsid(long pid) throws PosixException { logEnter("getsid", "%d", pid); try { - return logExit("getsid", "%d", lib.getsid(delegate, pid)); + return logExit("getsid", "%d", delegate.getsid(pid)); } catch (PosixException e) { throw logException("getsid", e); } } - @ExportMessage - final long setsid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long setsid() throws PosixException { logEnter("setsid", ""); try { - return logExit("getsid", "%d", lib.setsid(delegate)); + return logExit("getsid", "%d", delegate.setsid()); } catch (PosixException e) { throw logException("setsid", e); } @@ -1090,12 +1090,12 @@ public final long[] getgroups() throws PosixException { } } - @ExportMessage - final RusageResult getrusage(int who, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final RusageResult getrusage(int who) throws PosixException { logEnter("getrusage", "%d", who); try { - return logExit("getrusage", "%s", lib.getrusage(delegate, who)); + return logExit("getrusage", "%s", delegate.getrusage(who)); } catch (PosixException e) { throw logException("getrusage", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index a1b1e9cf3e..1c55ec9d05 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1851,12 +1851,14 @@ public long getegid() { return posixNativeFunctionInvoker.call_getegid(); } - @ExportMessage + @Override + @TruffleBoundary public long getppid() { return posixNativeFunctionInvoker.call_getppid(); } - @ExportMessage + @Override + @TruffleBoundary public void setpgid(long pid, long pgid) throws PosixException { int res = posixNativeFunctionInvoker.call_setpgid(pid, pgid); if (res < 0) { @@ -1864,7 +1866,8 @@ public void setpgid(long pid, long pgid) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long getpgid(long pid) throws PosixException { long res = posixNativeFunctionInvoker.call_getpgid(pid); if (res < 0) { @@ -1873,12 +1876,14 @@ public long getpgid(long pid) throws PosixException { return res; } - @ExportMessage + @Override + @TruffleBoundary public long getpgrp() { return posixNativeFunctionInvoker.call_getpgrp(); } - @ExportMessage + @Override + @TruffleBoundary public long getsid(long pid) throws PosixException { long res = posixNativeFunctionInvoker.call_getsid(pid); if (res < 0) { @@ -1887,7 +1892,8 @@ public long getsid(long pid) throws PosixException { return res; } - @ExportMessage + @Override + @TruffleBoundary public long setsid() throws PosixException { long res = posixNativeFunctionInvoker.call_setsid(); if (res < 0) { @@ -1921,7 +1927,8 @@ public long[] getgroups() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public RusageResult getrusage(int who) throws PosixException { long nativeResult = NativeMemory.mallocLongArray(16); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 7b4f0445b1..e71e014dfa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -42,6 +42,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; @@ -104,8 +105,22 @@ public static PosixSupport get(Node node) { public abstract long getegid() throws UnsupportedPosixFeatureException; + public abstract long getppid() throws UnsupportedPosixFeatureException; + + public abstract long getpgid(long pid) throws PosixException; + + public abstract void setpgid(long pid, long pgid) throws PosixException; + + public abstract long getpgrp() throws UnsupportedPosixFeatureException; + + public abstract long getsid(long pid) throws PosixException; + + public abstract long setsid() throws PosixException; + public abstract long[] getgroups() throws PosixException; + public abstract RusageResult getrusage(int who) throws PosixException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 0cea667bda..b9b30744d2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -79,18 +79,6 @@ public abstract class PosixSupportLibrary extends Library { // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants public static final int ST_SIZE = 6; - public abstract long getppid(Object receiver) throws UnsupportedPosixFeatureException; - - public abstract long getpgid(Object receiver, long pid) throws PosixException; - - public abstract void setpgid(Object receiver, long pid, long pgid) throws PosixException; - - public abstract long getpgrp(Object receiver) throws UnsupportedPosixFeatureException; - - public abstract long getsid(Object receiver, long pid) throws PosixException; - - public abstract long setsid(Object receiver) throws PosixException; - /** * Equivalent to struct r_usage with the fields expected on macOS and Linux. * @@ -117,8 +105,6 @@ public record RusageResult(double ru_utime, double ru_stime, long ru_msgsnd, long ru_msgrcv, long ru_nsignals, long ru_nvcsw, long ru_nivcsw) { } - public abstract RusageResult getrusage(Object receiver, int who) throws PosixException; - public record OpenPtyResult(int masterFd, int slaveFd) { } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index f3c31c3ee7..f4f2146c09 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -759,44 +759,46 @@ public final long getegid() throws UnsupportedPosixFeatureException { return nativePosixSupport.getegid(); } - @ExportMessage - final long getppid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getppid() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.getppid(nativePosixSupport); + return nativePosixSupport.getppid(); } - @ExportMessage - final long getpgid(long pid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long getpgid(long pid) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpgid(nativePosixSupport, pid); + return nativePosixSupport.getpgid(pid); } - @ExportMessage - final void setpgid(long pid, long pgid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setpgid(long pid, long pgid) throws PosixException { checkNotInPreInitialization(); - nativeLib.setpgid(nativePosixSupport, pid, pgid); + nativePosixSupport.setpgid(pid, pgid); } - @ExportMessage - final long getpgrp(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getpgrp() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.getpgrp(nativePosixSupport); + return nativePosixSupport.getpgrp(); } - @ExportMessage - final long getsid(long pid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long getsid(long pid) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getsid(nativePosixSupport, pid); + return nativePosixSupport.getsid(pid); } - @ExportMessage - final long setsid( - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long setsid() throws PosixException { checkNotInPreInitialization(); - return nativeLib.setsid(nativePosixSupport); + return nativePosixSupport.setsid(); } @Override @@ -806,11 +808,11 @@ public final long[] getgroups() throws PosixException { return nativePosixSupport.getgroups(); } - @ExportMessage - final RusageResult getrusage(int who, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final RusageResult getrusage(int who) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getrusage(nativePosixSupport, who); + return nativePosixSupport.getrusage(who); } @ExportMessage From 2b0d4fc1795702b478bf19e81b7e592fb834a100 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:37:28 +0200 Subject: [PATCH 044/129] Convert PosixSupportLibrary terminal identifiers (cherry picked from commit 5d09ed08331eece60f08108db34d1c3b179c3675) --- .../builtins/modules/PosixModuleBuiltins.java | 6 ++---- .../graal/python/runtime/EmulatedPosixSupport.java | 6 ++++-- .../graal/python/runtime/LoggingPosixSupport.java | 14 ++++++++------ .../graal/python/runtime/NativePosixSupport.java | 12 ++++++------ .../oracle/graal/python/runtime/PosixSupport.java | 5 +++++ .../graal/python/runtime/PosixSupportLibrary.java | 4 ---- .../graal/python/runtime/PreInitPosixSupport.java | 14 ++++++++------ 7 files changed, 33 insertions(+), 28 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 700567350b..ca9560dfb5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -856,10 +856,9 @@ public abstract static class OpenPtyNode extends PythonBuiltinNode { static Object openpty(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - OpenPtyResult result = posixLib.openpty(context.getPosixSupport()); + OpenPtyResult result = context.getPosixSupport().openpty(); context.getPosixSupport().setInheritable(result.masterFd(), false); context.getPosixSupport().setInheritable(result.slaveFd(), false); return PFactory.createTuple(context.getLanguage(inliningTarget), new int[]{result.masterFd(), result.slaveFd()}); @@ -2989,10 +2988,9 @@ abstract static class CtermId extends PythonBuiltinNode { static TruffleString ctermid(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.ctermid(context.getPosixSupport()); + return context.getPosixSupport().ctermid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 0cb35bfb6f..449c55829d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2369,13 +2369,15 @@ public RusageResult getrusage(int who) throws PosixException { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public OpenPtyResult openpty() throws PosixException { throw createUnsupportedFeature("openpty"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public TruffleString ctermid() { return T_DEV_TTY; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 2ba931ddaa..ca7754b887 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1112,21 +1112,23 @@ public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length, } } - @ExportMessage - final OpenPtyResult openpty(@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final OpenPtyResult openpty() throws PosixException { logEnter("openpty", ""); try { - return logExit("openpty", "%s", lib.openpty(delegate)); + return logExit("openpty", "%s", delegate.openpty()); } catch (PosixException e) { throw logException("openpty", e); } } - @ExportMessage - final TruffleString ctermid(@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final TruffleString ctermid() throws PosixException { logEnter("ctermid", ""); try { - return logExit("ctermid", "%s", lib.ctermid(delegate)); + return logExit("ctermid", "%s", delegate.ctermid()); } catch (PosixException e) { throw logException("ctermid", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 1c55ec9d05..7d4f2a2524 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1958,7 +1958,8 @@ public RusageResult getrusage(int who) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public OpenPtyResult openpty() throws PosixException { long nativeOutvars = NativeMemory.mallocIntArray(2); try { @@ -1974,15 +1975,14 @@ public OpenPtyResult openpty() throws PosixException { } } - @ExportMessage - public TruffleString ctermid( - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) { + @Override + @TruffleBoundary + public TruffleString ctermid() { long nativeBuf = NativeMemory.mallocByteArray(L_ctermid.value); try { posixNativeFunctionInvoker.call_ctermid(nativeBuf); // TODO PyUnicode_DecodeFSDefault - return zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, nativeBuf); + return NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(nativeBuf); } finally { NativeMemory.free(nativeBuf); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index e71e014dfa..6d1a9fd982 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -41,6 +41,7 @@ package com.oracle.graal.python.runtime; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; +import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; @@ -121,6 +122,10 @@ public static PosixSupport get(Node node) { public abstract RusageResult getrusage(int who) throws PosixException; + public abstract OpenPtyResult openpty() throws PosixException; + + public abstract TruffleString ctermid() throws PosixException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index b9b30744d2..c67f6ef374 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -108,10 +108,6 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - public abstract OpenPtyResult openpty(Object receiver) throws PosixException; - - public abstract TruffleString ctermid(Object receiver) throws PosixException; - // note: this leaks memory in native backend and is not synchronized // TODO is it worth synchronizing at least all accesses made through PosixSupportLibrary? public abstract void setenv(Object receiver, Object name, Object value, boolean overwrite) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index f4f2146c09..0c3f7193f2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -815,16 +815,18 @@ public final RusageResult getrusage(int who) throws PosixException { return nativePosixSupport.getrusage(who); } - @ExportMessage - final OpenPtyResult openpty(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final OpenPtyResult openpty() throws PosixException { checkNotInPreInitialization(); - return nativeLib.openpty(nativePosixSupport); + return nativePosixSupport.openpty(); } - @ExportMessage - final TruffleString ctermid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final TruffleString ctermid() throws PosixException { checkNotInPreInitialization(); - return nativeLib.ctermid(nativePosixSupport); + return nativePosixSupport.ctermid(); } @ExportMessage From 83eee63a60b05cfdb9b8092e6adb5c4c4d6c8dad Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:40:08 +0200 Subject: [PATCH 045/129] Convert PosixSupportLibrary environment operations (cherry picked from commit b6a6b01560876060fdd20885a00d4355325f8288) --- .../builtins/modules/PosixModuleBuiltins.java | 6 +++--- .../python/runtime/EmulatedPosixSupport.java | 4 ++-- .../python/runtime/LoggingPosixSupport.java | 16 ++++++++-------- .../graal/python/runtime/NativePosixSupport.java | 6 ++++-- .../graal/python/runtime/PosixSupport.java | 5 +++++ .../python/runtime/PosixSupportLibrary.java | 6 ------ .../python/runtime/PreInitPosixSupport.java | 16 ++++++++-------- 7 files changed, 30 insertions(+), 29 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index ca9560dfb5..f01619eca7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -384,7 +384,7 @@ private void populateEnviron(Python3Core core) { k = posixLib.createPathFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); v = posixLib.createPathFromString(posixSupport, value); } - posixLib.setenv(posixSupport, k, v, true); + posixSupport.setenv(k, v, true); } catch (PosixException ignored) { } val = toEnv(language, value); @@ -470,7 +470,7 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object valueObject, } auditNode.audit(frame, inliningTarget, T_OS_PUTENV, nameObject, valueObject); try { - posixLib.setenv(posixSupport, nameOpaque, valueOpaque, true); + posixSupport.setenv(nameOpaque, valueOpaque, true); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -537,7 +537,7 @@ static PNone putenv(VirtualFrame frame, Object nameObject, } auditNode.audit(frame, inliningTarget, T_OS_UNSETENV, nameObject); try { - posixLib.unsetenv(context.getPosixSupport(), nameOpaque); + context.getPosixSupport().unsetenv(nameOpaque); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 449c55829d..371f3628a6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2383,7 +2383,7 @@ public TruffleString ctermid() { return T_DEV_TTY; } - @ExportMessage + @Override @TruffleBoundary public void setenv(Object name, Object value, boolean overwrite) { String nameStr = pathToJavaString(name); @@ -2395,7 +2395,7 @@ public void setenv(Object name, Object value, boolean overwrite) { } } - @ExportMessage + @Override @TruffleBoundary public void unsetenv(Object name) { String nameStr = pathToJavaString(name); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index ca7754b887..f60a82cdfe 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1134,23 +1134,23 @@ public final TruffleString ctermid() throws PosixException { } } - @ExportMessage - final void setenv(Object name, Object value, boolean overwrite, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setenv(Object name, Object value, boolean overwrite) throws PosixException { logEnter("setenv", "%s, %s, %b", name, value, overwrite); try { - lib.setenv(delegate, name, value, overwrite); + delegate.setenv(name, value, overwrite); } catch (PosixException e) { throw logException("setenv", e); } } - @ExportMessage - final void unsetenv(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void unsetenv(Object name) throws PosixException { logEnter("unsetenv", "%s", name); try { - lib.unsetenv(delegate, name); + delegate.unsetenv(name); } catch (PosixException e) { throw logException("unsetenv", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 7d4f2a2524..98d719f0b3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -1988,7 +1988,8 @@ public TruffleString ctermid() { } } - @ExportMessage + @Override + @TruffleBoundary public void setenv(Object name, Object value, boolean overwrite) throws PosixException { long namePtr = NULLPTR; long valuePtr = NULLPTR; @@ -2005,7 +2006,8 @@ public void setenv(Object name, Object value, boolean overwrite) throws PosixExc } } - @ExportMessage + @Override + @TruffleBoundary public void unsetenv(Object name) throws PosixException { long namePtr = opaqueStringToNative(name); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 6d1a9fd982..192801965b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -126,6 +126,11 @@ public static PosixSupport get(Node node) { public abstract TruffleString ctermid() throws PosixException; + // note: this leaks memory in native backend and is not synchronized + public abstract void setenv(Object name, Object value, boolean overwrite) throws PosixException; + + public abstract void unsetenv(Object name) throws PosixException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index c67f6ef374..28991a872b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -108,12 +108,6 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - // note: this leaks memory in native backend and is not synchronized - // TODO is it worth synchronizing at least all accesses made through PosixSupportLibrary? - public abstract void setenv(Object receiver, Object name, Object value, boolean overwrite) throws PosixException; - - public abstract void unsetenv(Object receiver, Object name) throws PosixException; - public abstract int forkExec(Object receiver, Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 0c3f7193f2..8b0b65636a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -829,18 +829,18 @@ public final TruffleString ctermid() throws PosixException { return nativePosixSupport.ctermid(); } - @ExportMessage - final void setenv(Object name, Object value, boolean overwrite, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setenv(Object name, Object value, boolean overwrite) throws PosixException { checkNotInPreInitialization(); - nativeLib.setenv(nativePosixSupport, name, value, overwrite); + nativePosixSupport.setenv(name, value, overwrite); } - @ExportMessage - final void unsetenv(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void unsetenv(Object name) throws PosixException { checkNotInPreInitialization(); - nativeLib.unsetenv(nativePosixSupport, name); + nativePosixSupport.unsetenv(name); } @ExportMessage From c4c9b4454e8f6622b4b88d1451466756899dec79 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:44:24 +0200 Subject: [PATCH 046/129] Convert PosixSupportLibrary process execution (cherry picked from commit 5361def3af266797cdec2c77989eb342b79ab9cf) --- .../builtins/modules/PosixModuleBuiltins.java | 4 +-- .../PosixSubprocessModuleBuiltins.java | 2 +- .../python/runtime/EmulatedPosixSupport.java | 7 ++--- .../python/runtime/LoggingPosixSupport.java | 26 +++++++++---------- .../python/runtime/NativePosixSupport.java | 9 ++++--- .../graal/python/runtime/PosixSupport.java | 10 +++++++ .../python/runtime/PosixSupportLibrary.java | 10 ------- .../python/runtime/PreInitPosixSupport.java | 26 +++++++++---------- 8 files changed, 49 insertions(+), 45 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index f01619eca7..97201d1a10 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -603,7 +603,7 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, gil.release(true); try { - posixLib.execv(context.getPosixSupport(), path.value, opaqueArgs); + context.getPosixSupport().execv(path.value, opaqueArgs); } catch (PosixException e) { gil.acquire(); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2868,7 +2868,7 @@ static int system(VirtualFrame frame, Object command, } else { cmdOpaque = posixLib.createCStringFromBytes(context.getPosixSupport(), toBytesNode.execute((PBytes) command)); } - return posixLib.system(context.getPosixSupport(), cmdOpaque); + return context.getPosixSupport().system(cmdOpaque); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java index b5bdd3491d..c17ecf6c32 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java @@ -314,7 +314,7 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo gil.release(true); try { - return posixLib.forkExec(context.getPosixSupport(), executables, processArgs, cwd, env == null ? null : (Object[]) env, stdinRead, stdinWrite, stdoutRead, stdoutWrite, stderrRead, + return context.getPosixSupport().forkExec(executables, processArgs, cwd, env == null ? null : (Object[]) env, stdinRead, stdinWrite, stdoutRead, stdoutWrite, stderrRead, stderrWrite, errPipeRead, errPipeWrite, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork); } catch (PosixException e) { gil.acquire(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 371f3628a6..8c71452721 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2402,7 +2402,7 @@ public void unsetenv(Object name) { environ.remove(nameStr); } - @ExportMessage + @Override @TruffleBoundary public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { @@ -2568,7 +2568,8 @@ private void handleIOError(int errpipe_write, IOException e) { } } - @ExportMessage + @Override + @TruffleBoundary public void execv(Object pathname, Object[] args) throws PosixException { assert args.length > 0; String[] cmd = new String[args.length]; @@ -2617,7 +2618,7 @@ private void execvInternal(String[] cmd) throws IOException { throw new PythonExitException(null, pr.exitValue()); } - @ExportMessage + @Override @TruffleBoundary public int system(Object commandObj) { if (PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index f60a82cdfe..b565215f29 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1167,15 +1167,15 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, } } - @ExportMessage - final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { logEnter("forkExec", "%s, %s, %s, %s, %d, %d, %d, %d, %d, %d, %d, %d, %b, %b, %b, %d, %s, %b", executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork); try { - return logExit("forkExec", "%d", lib.forkExec(delegate, executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, + return logExit("forkExec", "%d", delegate.forkExec(executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork)); } catch (PosixException e) { throw logException("forkExec", e); @@ -1204,12 +1204,12 @@ public long mmapGetPointer(Object mmap, } } - @ExportMessage - final void execv(Object pathname, Object[] args, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void execv(Object pathname, Object[] args) throws PosixException { logEnter("execv", "%s, %s", pathname, args); try { - lib.execv(delegate, pathname, args); + delegate.execv(pathname, args); } catch (PosixException e) { throw logException("execv", e); } @@ -1287,11 +1287,11 @@ final int ioctlInt(int fd, long request, int arg, } } - @ExportMessage - final int system(Object command, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int system(Object command) { logEnter("system", "%s", command); - return logExit("system", "%d", lib.system(delegate, command)); + return logExit("system", "%d", delegate.system(command)); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 98d719f0b3..b5061d7b76 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -2020,7 +2020,8 @@ public void unsetenv(Object name) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { @@ -2134,7 +2135,8 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en } } - @ExportMessage + @Override + @TruffleBoundary public void execv(Object pathname, Object[] args) throws PosixException { if (WINDOWS) { @@ -2195,7 +2197,8 @@ public void execv(Object pathname, Object[] args) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int system(Object command) { long commandPtr = opaqueStringToNative(command); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 192801965b..98f495e184 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -131,6 +131,16 @@ public static PosixSupport get(Node node) { public abstract void unsetenv(Object name) throws PosixException; + public abstract int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, + int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, + boolean allowVFork) throws PosixException; + + // args.length must be > 0 + public abstract void execv(Object pathname, Object[] args) throws PosixException; + + // does not throw, because posix does not exactly define the return value + public abstract int system(Object command); + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 28991a872b..39b31b06bb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -108,16 +108,6 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - public abstract int forkExec(Object receiver, Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, - int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, - boolean allowVFork) throws PosixException; - - // args.length must be > 0 - public abstract void execv(Object receiver, Object pathname, Object[] args) throws PosixException; - - // does not throw, because posix does not exactly define the return value - public abstract int system(Object receiver, Object command); - public abstract Object mmap(Object receiver, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException; public abstract byte mmapReadByte(Object receiver, Object mmap, long index) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 8b0b65636a..4a9877399f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -843,27 +843,27 @@ public final void unsetenv(Object name) throws PosixException { nativePosixSupport.unsetenv(name); } - @ExportMessage - final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { checkNotInPreInitialization(); - return nativeLib.forkExec(nativePosixSupport, executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, + return nativePosixSupport.forkExec(executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork); } - @ExportMessage - final void execv(Object pathname, Object[] args, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void execv(Object pathname, Object[] args) throws PosixException { checkNotInPreInitialization(); - nativeLib.execv(nativePosixSupport, pathname, args); + nativePosixSupport.execv(pathname, args); } - @ExportMessage - final int system(Object command, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int system(Object command) { checkNotInPreInitialization(); - return nativeLib.system(nativePosixSupport, command); + return nativePosixSupport.system(command); } @ExportMessage From 5096a7d6582a0a3adda636ae211cee9b70052931 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:55:08 +0200 Subject: [PATCH 047/129] Convert PosixSupportLibrary mapping and byte access (cherry picked from commit 6c899bffe57e70969d9dc00562e7895c865ff1f8) --- .../builtins/objects/mmap/MMapBuiltins.java | 50 +++++++----------- .../python/builtins/objects/mmap/PMMap.java | 8 ++- .../python/runtime/EmulatedPosixSupport.java | 52 +++++++------------ .../python/runtime/LoggingPosixSupport.java | 40 +++++++------- .../python/runtime/NativePosixSupport.java | 26 +++++----- .../graal/python/runtime/PosixSupport.java | 10 ++++ .../python/runtime/PosixSupportLibrary.java | 10 ---- .../python/runtime/PreInitPosixSupport.java | 40 +++++++------- 8 files changed, 106 insertions(+), 130 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index 1625269443..0825683507 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -171,13 +171,13 @@ protected List> getNodeFa return MMapBuiltinsFactory.getFactories(); } - private static byte[] readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupportLibrary posixLib, Object posixSupport, long pos, int len, + private static byte[] readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupport posixSupport, long pos, int len, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { assert len > 0; assert pos + len <= self.getLength(); byte[] buffer = new byte[len]; - posixLib.mmapReadBytes(posixSupport, self.getPosixSupportHandle(), pos, buffer, buffer.length); + posixSupport.mmapReadBytes(self.getPosixSupportHandle(), pos, buffer, buffer.length); return buffer; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -215,7 +215,6 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj Object tagname, Object trackFdArg, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Exclusive @Cached CastToTruffleStringNode castTagnameNode, @@ -312,7 +311,7 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj Object mmapHandle; try { - mmapHandle = posixSupportLib.mmap(posixSupport, length, prot, flags, fd, offset, mmapTagname); + mmapHandle = posixSupport.mmap(inliningTarget, length, prot, flags, fd, offset, mmapTagname); } catch (PosixException e) { if (trackedFd != ANONYMOUS_FD) { try { @@ -380,12 +379,11 @@ static PBytes doInt(VirtualFrame frame, PMMap self, int index, @Bind Node inliningTarget, @Bind PythonContext context, @Cached PRaiseNode raiseNode, - @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib) { + @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long len = self.getLength(); checkBounds(inliningTarget, raiseNode, MMAP_INDEX_OUT_OF_RANGE, index, len); try { - byte b = posixSupportLib.mmapReadByte(context.getPosixSupport(), self.getPosixSupportHandle(), index); + byte b = context.getPosixSupport().mmapReadByte(self.getPosixSupportHandle(), index); // CPython indeed returns bytes object from sq_item, although it returns single byte // value as integer from mp_subscript, see, e.g.: `for i in mmap_object: print(i)` return PFactory.createBytes(context.getLanguage(inliningTarget), new byte[]{b}); @@ -404,7 +402,6 @@ static int doSingle(VirtualFrame frame, PMMap self, Object idxObj, @Bind Node inliningTarget, @Bind PythonContext context, @Exclusive @Cached InlinedConditionProfile negativeIndexProfile, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PyLongAsLongNode asLongNode, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Exclusive @Cached PRaiseNode raiseNode) { @@ -413,7 +410,7 @@ static int doSingle(VirtualFrame frame, PMMap self, Object idxObj, long idx = negativeIndexProfile.profile(inliningTarget, i < 0) ? i + len : i; checkBounds(inliningTarget, raiseNode, MMAP_INDEX_OUT_OF_RANGE, idx, len); try { - return posixSupportLib.mmapReadByte(context.getPosixSupport(), self.getPosixSupportHandle(), idx) & 0xFF; + return context.getPosixSupport().mmapReadByte(self.getPosixSupportHandle(), idx) & 0xFF; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -423,7 +420,6 @@ static int doSingle(VirtualFrame frame, PMMap self, Object idxObj, static Object doSlice(VirtualFrame frame, PMMap self, PSlice idx, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Exclusive @Cached InlinedConditionProfile emptyProfile, @Cached CoerceToIntSlice sliceCast, @Cached ComputeIndices compute, @@ -436,7 +432,7 @@ static Object doSlice(VirtualFrame frame, PMMap self, PSlice idx, if (emptyProfile.profile(inliningTarget, len == 0)) { return PFactory.createEmptyBytes(context.getLanguage(inliningTarget)); } - byte[] result = readBytes(frame, inliningTarget, self, posixSupportLib, context.getPosixSupport(), info.start, len, constructAndRaiseNode); + byte[] result = readBytes(frame, inliningTarget, self, context.getPosixSupport(), info.start, len, constructAndRaiseNode); return PFactory.createBytes(context.getLanguage(inliningTarget), result); } catch (OverflowException e) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.OverflowError, e); @@ -452,7 +448,6 @@ public abstract static class SetItemNode extends SqAssItemBuiltinNode { static void doSingle(VirtualFrame frame, PMMap self, int index, Object val, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Cached PyBytesCheckNode checkNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -475,7 +470,7 @@ static void doSingle(VirtualFrame frame, PMMap self, int index, Object val, } byte b = bufferLib.readByte(val, 0); try { - posixSupportLib.mmapWriteByte(context.getPosixSupport(), self.getPosixSupportHandle(), index, b); + context.getPosixSupport().mmapWriteByte(self.getPosixSupportHandle(), index, b); } catch (PosixException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, ex); } @@ -490,7 +485,6 @@ public abstract static class SetSubscriptNode extends MpAssSubscriptBuiltinNode static void doSingle(VirtualFrame frame, PMMap self, Object idxObj, Object valueObj, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PyIndexCheckNode checkNode, @Cached PyNumberAsSizeNode asSizeNode, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -523,7 +517,7 @@ static void doSingle(VirtualFrame frame, PMMap self, Object idxObj, Object value throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, MMAP_ITEM_VALUE_MUST_BE_IN_RANGE); } try { - posixSupportLib.mmapWriteByte(context.getPosixSupport(), self.getPosixSupportHandle(), idx, (byte) value); + context.getPosixSupport().mmapWriteByte(self.getPosixSupportHandle(), idx, (byte) value); } catch (PosixException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, ex); } @@ -534,7 +528,6 @@ static void doSingle(VirtualFrame frame, PMMap self, Object idxObj, Object value static void doSlice(VirtualFrame frame, PMMap self, PSlice slice, Object valueObj, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @CachedLibrary(limit = "3") PythonBufferAcquireLibrary acquireLib, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Cached SliceNodes.SliceUnpack sliceUnpack, @@ -567,11 +560,11 @@ static void doSlice(VirtualFrame frame, PMMap self, PSlice slice, Object valueOb if (info.sliceLength > 0) { try { if (step1Profile.profile(inliningTarget, info.step == 1)) { - posixSupportLib.mmapWriteBytes(context.getPosixSupport(), self.getPosixSupportHandle(), + context.getPosixSupport().mmapWriteBytes(self.getPosixSupportHandle(), info.start, bufferLib.getInternalOrCopiedByteArray(buffer), bufferLen); } else { for (int cur = info.start, i = 0; i < info.sliceLength; cur += info.step, i++) { - posixSupportLib.mmapWriteByte(context.getPosixSupport(), self.getPosixSupportHandle(), cur, bufferLib.readByte(buffer, i)); + context.getPosixSupport().mmapWriteByte(self.getPosixSupportHandle(), cur, bufferLib.readByte(buffer, i)); } LoopNode.reportLoopCount(inliningTarget, info.sliceLength); } @@ -705,14 +698,13 @@ abstract static class ReadByteNode extends PythonUnaryBuiltinNode { static int readByte(VirtualFrame frame, PMMap self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { if (self.getPos() >= self.getLength()) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, READ_BYTE_OUT_OF_RANGE); } try { - byte res = posixSupportLib.mmapReadByte(context.getPosixSupport(), self.getPosixSupportHandle(), self.getPos()); + byte res = context.getPosixSupport().mmapReadByte(self.getPosixSupportHandle(), self.getPos()); self.setPos(self.getPos() + 1); return res & 0xFF; } catch (PosixException e) { @@ -731,7 +723,6 @@ static PBytes read(VirtualFrame frame, PMMap self, Object n, @Bind PythonContext context, @Cached InlinedConditionProfile noneProfile, @Cached InlinedConditionProfile emptyProfile, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PyIndexCheckNode indexCheckNode, @Cached PyNumberAsSizeNode asSizeNode, @Cached InlinedConditionProfile negativeProfile, @@ -758,7 +749,7 @@ static PBytes read(VirtualFrame frame, PMMap self, Object n, return PFactory.createEmptyBytes(context.getLanguage(inliningTarget)); } try { - byte[] buffer = MMapBuiltins.readBytes(frame, inliningTarget, self, posixLib, context.getPosixSupport(), self.getPos(), PythonUtils.toIntExact(nread), constructAndRaiseNode); + byte[] buffer = MMapBuiltins.readBytes(frame, inliningTarget, self, context.getPosixSupport(), self.getPos(), PythonUtils.toIntExact(nread), constructAndRaiseNode); self.setPos(self.getPos() + buffer.length); return PFactory.createBytes(context.getLanguage(inliningTarget), buffer); } catch (OverflowException e) { @@ -776,7 +767,6 @@ abstract static class ReadlineNode extends PythonUnaryBuiltinNode { static Object readline(VirtualFrame frame, PMMap self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SequenceStorageNodes.AppendNode appendNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // Posix abstraction is leaking here a bit: with read mmapped memory, we'd just read @@ -787,7 +777,7 @@ static Object readline(VirtualFrame frame, PMMap self, int nread; outer: while (self.getPos() < self.getLength()) { try { - nread = posixLib.mmapReadBytes(context.getPosixSupport(), self.getPosixSupportHandle(), self.getPos(), buffer, (int) Math.min(self.getRemaining(), buffer.length)); + nread = context.getPosixSupport().mmapReadBytes(self.getPosixSupportHandle(), self.getPos(), buffer, (int) Math.min(self.getRemaining(), buffer.length)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -821,7 +811,6 @@ static int doIt(VirtualFrame frame, PMMap self, Object dataBuffer, @Bind PythonContext context, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("dataBuffer") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { @@ -833,7 +822,7 @@ static int doIt(VirtualFrame frame, PMMap self, Object dataBuffer, if (self.getPos() > self.getLength() || self.getLength() - self.getPos() < dataLen) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.DATA_OUT_OF_RANGE); } - posixLib.mmapWriteBytes(context.getPosixSupport(), self.getPosixSupportHandle(), self.getPos(), dataBytes, dataLen); + context.getPosixSupport().mmapWriteBytes(self.getPosixSupportHandle(), self.getPos(), dataBytes, dataLen); self.setPos(self.getPos() + dataLen); return dataLen; } catch (PosixException e) { @@ -910,7 +899,6 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI @CachedLibrary("subBuffer") PythonBufferAccessLibrary bufferLib, @Cached LongIndexConverterNode startConverter, @Cached LongIndexConverterNode endConverter, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { @@ -931,7 +919,7 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI byte[] firstBuffer = new byte[bufferSize]; byte[] secondBuffer = new byte[bufferSize]; - readBytes(frame, inliningTarget, self, posixLib, context.getPosixSupport(), start, secondBuffer, constructAndRaiseNode, raiseNode); + readBytes(frame, inliningTarget, self, context.getPosixSupport(), start, secondBuffer, constructAndRaiseNode, raiseNode); for (long selfIdx = start; selfIdx <= end - subLen; selfIdx++, buffersIndex++) { // Make sure that the buffers have enough room for the search if (buffersIndex + subLen > bufferSize * 2) { @@ -940,7 +928,7 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI secondBuffer = tmp; buffersIndex -= bufferSize; // move to the tail of the first buffer now long readIndex = selfIdx + subLen - 1; - readBytes(frame, inliningTarget, self, posixLib, context.getPosixSupport(), readIndex, secondBuffer, constructAndRaiseNode, raiseNode); + readBytes(frame, inliningTarget, self, context.getPosixSupport(), readIndex, secondBuffer, constructAndRaiseNode, raiseNode); // It's OK if we read less than buffer size, the outer loop condition // 'selfIdx <= end' and the check in readBytes should cover that we don't // read @@ -970,12 +958,12 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI } } - private static void readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupportLibrary posixLib, PosixSupport posixSupport, long index, byte[] buffer, + private static void readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupport posixSupport, long index, byte[] buffer, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PRaiseNode raiseNode) { try { long remaining = self.getLength() - index; int toReadLen = remaining > buffer.length ? buffer.length : (int) remaining; - int nread = posixLib.mmapReadBytes(posixSupport, self.getPosixSupportHandle(), index, buffer, toReadLen); + int nread = posixSupport.mmapReadBytes(self.getPosixSupportHandle(), index, buffer, toReadLen); if (toReadLen != nread) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.SystemError, MMAP_CHANGED_LENGTH); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java index d3956fa112..534e6c33d1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java @@ -147,10 +147,9 @@ int getBufferLength( @ExportMessage byte readByte(int byteOffset, @Bind Node inliningTarget, - @Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Shared("raiseNode") @Cached PConstructAndRaiseNode.Lazy raiseNode) { try { - return posixLib.mmapReadByte(PythonContext.get(raiseNode).getPosixSupport(), getPosixSupportHandle(), byteOffset); + return PythonContext.get(inliningTarget).getPosixSupport().mmapReadByte(getPosixSupportHandle(), byteOffset); } catch (PosixException e) { throw raiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -159,10 +158,9 @@ byte readByte(int byteOffset, @ExportMessage void writeByte(int byteOffset, byte value, @Bind Node inliningTarget, - @Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Shared("raiseNode") @Cached PConstructAndRaiseNode.Lazy raiseNode) { try { - posixLib.mmapWriteByte(PythonContext.get(raiseNode).getPosixSupport(), getPosixSupportHandle(), byteOffset, value); + PythonContext.get(inliningTarget).getPosixSupport().mmapWriteByte(getPosixSupportHandle(), byteOffset, value); } catch (PosixException e) { throw raiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -227,7 +225,7 @@ boolean isNative( @ExportMessage long getNativePointer( @Bind Node inliningTarget, - @Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { + @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { try { return posixLib.mmapGetPointer(PythonContext.get(inliningTarget).getPosixSupport(), getPosixSupportHandle()); } catch (PosixSupportLibrary.UnsupportedPosixFeatureException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 8c71452721..377b55f5c3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2785,17 +2785,15 @@ public SeekableByteChannel truncate(long size) throws IOException { } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @SuppressWarnings("unused") Object tagname, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile isAnonymousProfile) throws PosixException { + public MMapHandle mmap(@SuppressWarnings("unused") Node location, long length, int prot, int flags, int fd, long offset, @SuppressWarnings("unused") Object tagname) throws PosixException { if (prot == PROT_NONE.value) { return MMapHandle.NONE; } - // Note: the profile is not really defaultDirProfile, but it's good to share... - if (isAnonymousProfile.profile(inliningTarget, (flags & MAP_ANONYMOUS.value) != 0)) { + if ((flags & MAP_ANONYMOUS.value) != 0) { try { return new MMapHandle(new AnonymousMap(PythonUtils.toIntExact(length)), 0); } catch (OverflowException e) { @@ -2837,39 +2835,34 @@ private static SeekableByteChannel newByteChannel(TruffleFile file, Set 0) { getByteBufferArray(readingBuffer, bytes, readSize); } return readSize; } - private static int readBytes(Node inliningTarget, MMapHandle handle, long index, ByteBuffer readingBuffer, InlinedBranchProfile errBranch) throws PosixException { + private static int readBytes(MMapHandle handle, long index, ByteBuffer readingBuffer) throws PosixException { try { position(handle.channel, index + handle.offset); return readChannel(handle.channel, readingBuffer); } catch (IOException e) { - errBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch) throws PosixException { + public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { if (mmap == MMapHandle.NONE) { - errBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EACCES); } MMapHandle handle = (MMapHandle) mmap; @@ -2917,7 +2906,6 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, } } catch (Exception e) { // Catching generic Exception to also cover NonWritableChannelException - errBranch.enter(inliningTarget); throw posixException(OSErrorEnum.fromException(e)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index b565215f29..b5913da349 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -877,12 +877,12 @@ public final void killpg(long pgid, int signal) throws PosixException { } } - @ExportMessage - public Object mmap(long length, int prot, int flags, int fd, long offset, Object tagname, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public Object mmap(Node location, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException { logEnter("mmap", "%d, %d, %d, %d, %d, %s", length, prot, flags, fd, offset, tagname); try { - return logExit("mmap", "%s", lib.mmap(delegate, length, prot, flags, fd, offset, tagname)); + return logExit("mmap", "%s", delegate.mmap(location, length, prot, flags, fd, offset, tagname)); } catch (PosixException e) { throw logException("mmap", e); } @@ -899,23 +899,23 @@ public final long[] waitpid(Node location, long pid, int options) throws PosixEx } } - @ExportMessage - public byte mmapReadByte(Object mmap, long index, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public byte mmapReadByte(Object mmap, long index) throws PosixException { logEnter("mmapReadByte", "%s, %d", mmap, index); try { - return logExit("mmapReadByte", "%s", lib.mmapReadByte(delegate, mmap, index)); + return logExit("mmapReadByte", "%s", delegate.mmapReadByte(mmap, index)); } catch (PosixException e) { throw logException("mmapReadByte", e); } } - @ExportMessage - public void mmapWriteByte(Object mmap, long index, byte value, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapWriteByte(Object mmap, long index, byte value) throws PosixException { logEnter("mmapWriteByte", "%s, %d, %d", mmap, index, value); try { - lib.mmapWriteByte(delegate, mmap, index, value); + delegate.mmapWriteByte(mmap, index, value); } catch (PosixException e) { throw logException("mmapWriteByte", e); } @@ -1101,12 +1101,12 @@ public final RusageResult getrusage(int who) throws PosixException { } } - @ExportMessage - public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { logEnter("mmapReadBytes", "%s, %d, %d", mmap, index, length); try { - return logExit("mmapReadBytes", "%s", lib.mmapReadBytes(delegate, mmap, index, bytes, length)); + return logExit("mmapReadBytes", "%s", delegate.mmapReadBytes(mmap, index, bytes, length)); } catch (PosixException e) { throw logException("mmapReadBytes", e); } @@ -1156,12 +1156,12 @@ public final void unsetenv(Object name) throws PosixException { } } - @ExportMessage - public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { logEnter("mmapWriteBytes", "%s, %d, %d", mmap, index, length); try { - lib.mmapWriteBytes(delegate, mmap, index, bytes, length); + delegate.mmapWriteBytes(mmap, index, bytes, length); } catch (PosixException e) { throw logException("mmapWriteBytes", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index b5061d7b76..42d0d2589b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -2247,18 +2247,16 @@ public MMapHandle(long pointer, long length) { } } - @ExportMessage - public Object mmap(long length, int prot, int flags, int fd, long offset, Object tagname, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.IsValidNode isValidNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) throws PosixException { + @Override + @TruffleBoundary + public Object mmap(Node inliningTarget, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException { long tagnamePtr = NULLPTR; try { if (tagname instanceof TruffleString tagnameString) { tagnamePtr = WINDOWS - ? stringToNativeUTF16CString(tagnameString, switchEncodingNode, copyToByteArrayNode) - : stringToNativeUTF8CString(inliningTarget, tagnameString, switchEncodingNode, isValidNode, copyToByteArrayNode); + ? stringToNativeUTF16CString(tagnameString, TruffleString.SwitchEncodingNode.getUncached(), TruffleString.CopyToByteArrayNode.getUncached()) + : stringToNativeUTF8CString(inliningTarget, tagnameString, TruffleString.SwitchEncodingNode.getUncached(), TruffleString.IsValidNode.getUncached(), + TruffleString.CopyToByteArrayNode.getUncached()); } long address = posixNativeFunctionInvoker.call_mmap(length, prot, flags, fd, offset, tagnamePtr); if (address == 0) { @@ -2270,7 +2268,8 @@ public Object mmap(long length, int prot, int flags, int fd, long offset, Object } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public byte mmapReadByte(Object mmap, long index) { MMapHandle handle = (MMapHandle) mmap; @@ -2281,7 +2280,8 @@ public byte mmapReadByte(Object mmap, long index) { return UNSAFE.getByte(handle.pointer + index); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void mmapWriteByte(Object mmap, long index, byte value) { MMapHandle handle = (MMapHandle) mmap; @@ -2289,7 +2289,8 @@ public void mmapWriteByte(Object mmap, long index, byte value) { UNSAFE.putByte(handle.pointer + index, value); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) { MMapHandle handle = (MMapHandle) mmap; @@ -2298,7 +2299,8 @@ public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) { return length; } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) { MMapHandle handle = (MMapHandle) mmap; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 98f495e184..77593f55c2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -141,6 +141,16 @@ public abstract int forkExec(Object[] executables, Object[] args, Object cwd, Ob // does not throw, because posix does not exactly define the return value public abstract int system(Object command); + public abstract Object mmap(Node location, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException; + + public abstract byte mmapReadByte(Object mmap, long index) throws PosixException; + + public abstract void mmapWriteByte(Object mmap, long index, byte value) throws PosixException; + + public abstract int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException; + + public abstract void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 39b31b06bb..f43d4fc939 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -108,16 +108,6 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - public abstract Object mmap(Object receiver, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException; - - public abstract byte mmapReadByte(Object receiver, Object mmap, long index) throws PosixException; - - public abstract void mmapWriteByte(Object receiver, Object mmap, long index, byte value) throws PosixException; - - public abstract int mmapReadBytes(Object receiver, Object mmap, long index, byte[] bytes, int length) throws PosixException; - - public abstract void mmapWriteBytes(Object receiver, Object mmap, long index, byte[] bytes, int length) throws PosixException; - public abstract void mmapFlush(Object receiver, Object mmap, long offset, long length) throws PosixException; public abstract void mmapUnmap(Object receiver, Object mmap, long length) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 4a9877399f..9c127cb2a0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -866,39 +866,39 @@ public final int system(Object command) { return nativePosixSupport.system(command); } - @ExportMessage - final Object mmap(long length, int prot, int flags, int fd, long offset, Object tagname, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object mmap(Node location, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException { checkNotInPreInitialization(); - return nativeLib.mmap(nativePosixSupport, length, prot, flags, fd, offset, tagname); + return nativePosixSupport.mmap(location, length, prot, flags, fd, offset, tagname); } - @ExportMessage - final byte mmapReadByte(Object mmap, long index, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final byte mmapReadByte(Object mmap, long index) throws PosixException { checkNotInPreInitialization(); - return nativeLib.mmapReadByte(nativePosixSupport, mmap, index); + return nativePosixSupport.mmapReadByte(mmap, index); } - @ExportMessage - final void mmapWriteByte(Object mmap, long index, byte value, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapWriteByte(Object mmap, long index, byte value) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapWriteByte(nativePosixSupport, mmap, index, value); + nativePosixSupport.mmapWriteByte(mmap, index, value); } - @ExportMessage - final int mmapReadBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { checkNotInPreInitialization(); - return nativeLib.mmapReadBytes(nativePosixSupport, mmap, index, bytes, length); + return nativePosixSupport.mmapReadBytes(mmap, index, bytes, length); } - @ExportMessage - final void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapWriteBytes(nativePosixSupport, mmap, index, bytes, length); + nativePosixSupport.mmapWriteBytes(mmap, index, bytes, length); } @ExportMessage From 38aeb8911153c1e222489460f0cfc9fd6f4edce3 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 17:59:12 +0200 Subject: [PATCH 048/129] Convert PosixSupportLibrary mapping completion (cherry picked from commit 8a4a22087f72c3152f9a18d32fcf62db8bed8ea8) --- .../modules/cext/PythonCextBuiltins.java | 2 +- .../builtins/objects/mmap/MMapBuiltins.java | 13 +++------- .../python/builtins/objects/mmap/PMMap.java | 15 +++++------ .../python/runtime/EmulatedPosixSupport.java | 9 ++++--- .../python/runtime/LoggingPosixSupport.java | 24 +++++++++--------- .../python/runtime/NativePosixSupport.java | 9 ++++--- .../graal/python/runtime/PosixSupport.java | 6 +++++ .../python/runtime/PosixSupportLibrary.java | 6 ----- .../python/runtime/PreInitPosixSupport.java | 25 +++++++++---------- 9 files changed, 53 insertions(+), 56 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java index ef89e1b0d5..a3c3eafdf5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java @@ -1587,7 +1587,7 @@ static long GraalPyPrivate_GetMMapData(long objectPtr) { PMMap object = (PMMap) NativeToPythonInternalNode.executeUncached(objectPtr, false); PythonContext context = PythonContext.get(null); try { - return PosixSupportLibrary.getUncached().mmapGetPointer(context.getPosixSupport(), object.getPosixSupportHandle()); + return context.getPosixSupport().mmapGetPointer(object.getPosixSupportHandle()); } catch (PosixSupportLibrary.UnsupportedPosixFeatureException e) { throw PConstructAndRaiseNode.getUncached().raiseOSErrorUnsupported(null, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index 0825683507..50ad524b15 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -134,7 +134,6 @@ import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.nativeaccess.NativeAccessSupport; @@ -618,9 +617,8 @@ abstract static class CloseNode extends PythonUnaryBuiltinNode { @Specialization static PNone close(PMMap self, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib) { - self.close(posixSupportLib, context.getPosixSupport()); + @Bind PythonContext context) { + self.close(context.getPosixSupport()); return PNone.NONE; } } @@ -1004,7 +1002,6 @@ static Object flush(VirtualFrame frame, PMMap self, long offset, Object sizeObj, @Bind Node inliningTarget, @Bind PythonContext context, @Cached LongIndexConverterNode sizeConversion, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { long size; @@ -1022,7 +1019,7 @@ static Object flush(VirtualFrame frame, PMMap self, long offset, Object sizeObj, } try { - posixLib.mmapFlush(context.getPosixSupport(), self.getPosixSupportHandle(), offset, self.getLength()); + context.getPosixSupport().mmapFlush(self.getPosixSupportHandle(), offset, self.getLength()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1050,8 +1047,6 @@ public void execute(PythonContext context, Access access) { } private static class ReleaserRootNode extends RootNode { - @Child private PosixSupportLibrary posixSupportLibrary = PosixSupportLibrary.getFactory().createDispatched(1); - ReleaserRootNode(TruffleLanguage language) { super(language); } @@ -1059,7 +1054,7 @@ private static class ReleaserRootNode extends RootNode { @Override public Object execute(VirtualFrame frame) { PMMap.MMapRef ref = (PMMap.MMapRef) frame.getArguments()[0]; - ref.close(posixSupportLibrary, PythonContext.get(this).getPosixSupport()); + ref.close(PythonContext.get(this).getPosixSupport()); return null; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java index 534e6c33d1..990483a1d1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java @@ -57,7 +57,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; @@ -86,8 +85,8 @@ public Object getPosixSupportHandle() { return ref.getReference(); } - void close(PosixSupportLibrary lib, PosixSupport posix) { - ref.close(lib, posix); + void close(PosixSupport posix) { + ref.close(posix); } boolean isClosed() { @@ -195,7 +194,7 @@ public AsyncHandler.AsyncAction release() { return new MMapBuiltins.ReleaseCallback(this); } - void close(PosixSupportLibrary posixLib, PosixSupport posixSupport) { + void close(PosixSupport posixSupport) { if (!markReleased()) { return; } @@ -209,7 +208,7 @@ void close(PosixSupportLibrary posixLib, PosixSupport posixSupport) { } } try { - posixLib.mmapUnmap(posixSupport, handle, length); + posixSupport.mmapUnmap(handle, length); } catch (PosixException e) { // ignored (CPython does not check the return value) } @@ -223,11 +222,9 @@ boolean isNative( } @ExportMessage - long getNativePointer( - @Bind Node inliningTarget, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { + long getNativePointer(@Bind Node inliningTarget) { try { - return posixLib.mmapGetPointer(PythonContext.get(inliningTarget).getPosixSupport(), getPosixSupportHandle()); + return PythonContext.get(inliningTarget).getPosixSupport().mmapGetPointer(getPosixSupportHandle()); } catch (PosixSupportLibrary.UnsupportedPosixFeatureException e) { return NULLPTR; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 377b55f5c3..aba18b13f2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2915,7 +2915,8 @@ private static int writeChannel(SeekableByteChannel channel, byte[] bytes, int l return channel.write(ByteBuffer.wrap(bytes, 0, length)); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings({"static-method", "unused"}) public void mmapFlush(Object mmap, long offset, long length) { // Intentionally noop @@ -2925,7 +2926,8 @@ public void mmapFlush(Object mmap, long offset, long length) { // different implementation of mmap in emulated posix) } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length) throws PosixException { if (mmap == MMapHandle.NONE) { @@ -2942,7 +2944,8 @@ public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length) thro } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long mmapGetPointer(@SuppressWarnings("unused") Object mmap) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("obtaining mmap pointer"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index b5913da349..a5b92858d4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1182,23 +1182,23 @@ public final int forkExec(Object[] executables, Object[] args, Object cwd, Objec } } - @ExportMessage - public void mmapFlush(Object mmap, long offset, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapFlush(Object mmap, long offset, long length) throws PosixException { logEnter("mmapFlush", "%s, %d, %d", mmap, offset, length); try { - lib.mmapFlush(delegate, mmap, offset, length); + delegate.mmapFlush(mmap, offset, length); } catch (PosixException e) { throw logException("mmapFlush", e); } } - @ExportMessage - public long mmapGetPointer(Object mmap, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureException { logEnter("mmapGetPointer", "%s", mmap); try { - return lib.mmapGetPointer(delegate, mmap); + return delegate.mmapGetPointer(mmap); } catch (UnsupportedPosixFeatureException e) { throw logException("mmapGetPointer", e); } @@ -1215,12 +1215,12 @@ public final void execv(Object pathname, Object[] args) throws PosixException { } } - @ExportMessage - public void mmapUnmap(Object mmap, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapUnmap(Object mmap, long length) throws PosixException { logEnter("mmapUnmap", "%s %d", mmap, length); try { - lib.mmapUnmap(delegate, mmap, length); + delegate.mmapUnmap(mmap, length); } catch (PosixException e) { throw logException("mmapUnmap", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 42d0d2589b..bc008e55a7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -2308,14 +2308,16 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) { UNSAFE.copyMemory(bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, handle.pointer + index, length); } - @ExportMessage + @Override + @TruffleBoundary public void mmapFlush(Object mmap, long offset, long length) { MMapHandle handle = (MMapHandle) mmap; checkIndexAndLen(handle, offset, length); posixNativeFunctionInvoker.call_msync(handle.pointer, offset, length); } - @ExportMessage + @Override + @TruffleBoundary public void mmapUnmap(Object mmap, long length) throws PosixException { MMapHandle handle = (MMapHandle) mmap; if (length != handle.length) { @@ -2328,7 +2330,8 @@ public void mmapUnmap(Object mmap, long length) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long mmapGetPointer(Object mmap) { MMapHandle handle = (MMapHandle) mmap; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 77593f55c2..cf4142ffc4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -151,6 +151,12 @@ public abstract int forkExec(Object[] executables, Object[] args, Object cwd, Ob public abstract void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException; + public abstract void mmapFlush(Object mmap, long offset, long length) throws PosixException; + + public abstract void mmapUnmap(Object mmap, long length) throws PosixException; + + public abstract long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureException; + public abstract TruffleString getBackend(); public abstract TruffleString strerror(int errorCode); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index f43d4fc939..98f54ededb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -108,12 +108,6 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - public abstract void mmapFlush(Object receiver, Object mmap, long offset, long length) throws PosixException; - - public abstract void mmapUnmap(Object receiver, Object mmap, long length) throws PosixException; - - public abstract long mmapGetPointer(Object receiver, Object mmap) throws UnsupportedPosixFeatureException; - public abstract long semOpen(Object receiver, Object name, int openFlags, int mode, int value) throws PosixException; public final long semOpen(Object receiver, Object name) throws PosixException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 9c127cb2a0..bb1d51594b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -901,26 +901,25 @@ public final void mmapWriteBytes(Object mmap, long index, byte[] bytes, int leng nativePosixSupport.mmapWriteBytes(mmap, index, bytes, length); } - @ExportMessage - final void mmapFlush(Object mmap, long offset, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapFlush(Object mmap, long offset, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapFlush(nativePosixSupport, mmap, offset, length); + nativePosixSupport.mmapFlush(mmap, offset, length); } - @ExportMessage - final void mmapUnmap(Object mmap, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapUnmap(Object mmap, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapUnmap(nativePosixSupport, mmap, length); + nativePosixSupport.mmapUnmap(mmap, length); } - @ExportMessage - @SuppressWarnings("static-method") - final long mmapGetPointer(Object mmap, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.mmapGetPointer(nativePosixSupport, mmap); + return nativePosixSupport.mmapGetPointer(mmap); } @ExportMessage From ba3264e2dbb941d6f39bcf3f3d27a594db5b7636 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 18:49:04 +0200 Subject: [PATCH 049/129] Convert PosixSupportLibrary semaphore and shared-memory lifetime operations (cherry picked from commit 478331c27233553ef1922f796d82e6c495a5fe4f) --- .../modules/PosixShMemModuleBuiltins.java | 4 +- .../MultiprocessingModuleBuiltins.java | 2 +- .../multiprocessing/SemLockBuiltins.java | 8 ++-- .../python/runtime/EmulatedPosixSupport.java | 25 +++++++----- .../python/runtime/LoggingPosixSupport.java | 40 +++++++++---------- .../python/runtime/NativePosixSupport.java | 25 +++++++----- .../graal/python/runtime/PosixSupport.java | 14 +++++++ .../python/runtime/PosixSupportLibrary.java | 14 ------- .../python/runtime/PreInitPosixSupport.java | 40 +++++++++---------- 9 files changed, 91 insertions(+), 81 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java index e5e4fae2e9..a6d685a543 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java @@ -94,7 +94,7 @@ static int shmOpen(VirtualFrame frame, TruffleString path, int flags, int mode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object name = posixLib.createCStringFromString(context.getPosixSupport(), path); - return posixLib.shmOpen(context.getPosixSupport(), name, flags, mode); + return context.getPosixSupport().shmOpen(name, flags, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); } @@ -119,7 +119,7 @@ static PNone shmUnlink(VirtualFrame frame, TruffleString path, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object name = posixLib.createCStringFromString(context.getPosixSupport(), path); - posixLib.shmUnlink(context.getPosixSupport(), name); + context.getPosixSupport().shmUnlink(name); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java index 7a2c4fea2a..b5323e467b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java @@ -174,7 +174,7 @@ PNone doit(VirtualFrame frame, TruffleString name, @Bind Node inliningTarget, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.semUnlink(posixSupport, posixLib.createCStringFromString(posixSupport, name)); + posixSupport.semUnlink(posixLib.createCStringFromString(posixSupport, name)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java index c730e88971..6fc59e916e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java @@ -130,16 +130,16 @@ static PSemLock construct(VirtualFrame frame, Object cls, int kind, int value, i Object posixName = posixLib.createCStringFromString(posixSupport, name); long handle; try { - handle = posixLib.semOpen(posixSupport, posixName, O_CREAT.value | O_EXCL.value, 0600, value); + handle = posixSupport.semOpen(posixName, O_CREAT.value | O_EXCL.value, 0600, value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } if (unlink) { try { - posixLib.semUnlink(posixSupport, posixName); + posixSupport.semUnlink(posixName); } catch (PosixException e) { try { - posixLib.semClose(posixSupport, handle); + posixSupport.semClose(handle); } catch (PosixException ex) { // Ignore, we're already on an error path } @@ -432,7 +432,7 @@ static Object rebuild(VirtualFrame frame, Object cls, long origHandle, int kind, Object posixName = posixLib.createCStringFromString(posixSupport, posixNameString); long handle; try { - handle = posixLib.semOpen(posixSupport, posixName); + handle = posixSupport.semOpen(posixName); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index aba18b13f2..96b6ddb8d9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -2983,33 +2983,38 @@ private static int readChannel(Object readableChannel, ByteBuffer dst) throws IO return ((ReadableByteChannel) readableChannel).read(dst); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { + public long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semClose(long handle) throws PosixException { + public void semClose(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semUnlink(Object name) throws PosixException { + public void semUnlink(Object name) throws PosixException { throw posixException(OSErrorEnum.ENOENT); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - int shmOpen(Object name, int openFlags, int mode) throws PosixException { + public int shmOpen(Object name, int openFlags, int mode) throws PosixException { throw createUnsupportedFeature("shm_open"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void shmUnlink(Object name) throws PosixException { + public void shmUnlink(Object name) throws PosixException { throw createUnsupportedFeature("shm_unlink"); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index a5b92858d4..d2940c180c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1533,56 +1533,56 @@ final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int so } } - @ExportMessage - final long semOpen(Object name, int openFlags, int mode, int value, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { logEnter("semOpen", "%s %d %d %d", name, openFlags, mode, value); try { - return logExit("semOpen", "0x%x", lib.semOpen(delegate, name, openFlags, mode, value)); + return logExit("semOpen", "0x%x", delegate.semOpen(name, openFlags, mode, value)); } catch (PosixException e) { throw logException("semOpen", e); } } - @ExportMessage - final void semClose(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semClose(long handle) throws PosixException { logEnter("semClose", "0x%x", handle); try { - lib.semClose(delegate, handle); + delegate.semClose(handle); } catch (PosixException e) { throw logException("semClose", e); } } - @ExportMessage - final void semUnlink(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semUnlink(Object name) throws PosixException { logEnter("semUnlink", "%s", name); try { - lib.semUnlink(delegate, name); + delegate.semUnlink(name); } catch (PosixException e) { throw logException("semUnlink", e); } } - @ExportMessage - final int shmOpen(Object name, int openFlags, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int shmOpen(Object name, int openFlags, int mode) throws PosixException { logEnter("shmOpen", "%s %d %d", name, openFlags, mode); try { - return logExit("shmOpen", "%d", lib.shmOpen(delegate, name, openFlags, mode)); + return logExit("shmOpen", "%d", delegate.shmOpen(name, openFlags, mode)); } catch (PosixException e) { throw logException("shmOpen", e); } } - @ExportMessage - final void shmUnlink(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void shmUnlink(Object name) throws PosixException { logEnter("shmUnlink", "%s", name); try { - lib.shmUnlink(delegate, name); + delegate.shmUnlink(name); } catch (PosixException e) { throw logException("shmUnlink", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index bc008e55a7..36a860ddd5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -3098,8 +3098,9 @@ void setLen(int len) { } - @ExportMessage - long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { + @Override + @TruffleBoundary + public long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { long ptr = posixNativeFunctionInvoker.call_sem_open(namePtr, openFlags, mode, value); @@ -3112,16 +3113,18 @@ long semOpen(Object name, int openFlags, int mode, int value) throws PosixExcept } } - @ExportMessage - void semClose(long handle) throws PosixException { + @Override + @TruffleBoundary + public void semClose(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_close(handle); if (res < 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage - void semUnlink(Object name) throws PosixException { + @Override + @TruffleBoundary + public void semUnlink(Object name) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { int res = posixNativeFunctionInvoker.call_sem_unlink(namePtr); @@ -3133,8 +3136,9 @@ void semUnlink(Object name) throws PosixException { } } - @ExportMessage - int shmOpen(Object name, int openFlags, int mode) throws PosixException { + @Override + @TruffleBoundary + public int shmOpen(Object name, int openFlags, int mode) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { int fd = posixNativeFunctionInvoker.call_shm_open(namePtr, openFlags, mode); @@ -3147,8 +3151,9 @@ int shmOpen(Object name, int openFlags, int mode) throws PosixException { } } - @ExportMessage - void shmUnlink(Object name) throws PosixException { + @Override + @TruffleBoundary + public void shmUnlink(Object name) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { int res = posixNativeFunctionInvoker.call_shm_unlink(namePtr); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index cf4142ffc4..078aaa7947 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -66,6 +66,20 @@ public static PosixSupport get(Node node) { return PythonContext.get(node).getPosixSupport(); } + public abstract long semOpen(Object name, int openFlags, int mode, int value) throws PosixException; + + public final long semOpen(Object name) throws PosixException { + return semOpen(name, 0, 0, 0); + } + + public abstract void semClose(long handle) throws PosixException; + + public abstract void semUnlink(Object name) throws PosixException; + + public abstract int shmOpen(Object name, int openFlags, int mode) throws PosixException; + + public abstract void shmUnlink(Object name) throws PosixException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 98f54ededb..552a309809 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -108,20 +108,6 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - public abstract long semOpen(Object receiver, Object name, int openFlags, int mode, int value) throws PosixException; - - public final long semOpen(Object receiver, Object name) throws PosixException { - return semOpen(receiver, name, 0, 0, 0); - } - - public abstract void semClose(Object receiver, long handle) throws PosixException; - - public abstract void semUnlink(Object receiver, Object name) throws PosixException; - - public abstract int shmOpen(Object receiver, Object name, int openFlags, int mode) throws PosixException; - - public abstract void shmUnlink(Object receiver, Object name) throws PosixException; - public abstract int semGetValue(Object receiver, long handle) throws PosixException; public abstract void semPost(Object receiver, long handle) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index bb1d51594b..3746d7b365 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -1114,39 +1114,39 @@ final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int so return nativeLib.getaddrinfo(nativePosixSupport, node, service, family, sockType, protocol, flags); } - @ExportMessage - final long semOpen(Object name, int openFlags, int mode, int value, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { checkNotInPreInitialization(); - return lib.semOpen(nativePosixSupport, name, openFlags, mode, value); + return nativePosixSupport.semOpen(name, openFlags, mode, value); } - @ExportMessage - final void semClose(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semClose(long handle) throws PosixException { checkNotInPreInitialization(); - lib.semClose(nativePosixSupport, handle); + nativePosixSupport.semClose(handle); } - @ExportMessage - final void semUnlink(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semUnlink(Object name) throws PosixException { checkNotInPreInitialization(); - lib.semUnlink(nativePosixSupport, name); + nativePosixSupport.semUnlink(name); } - @ExportMessage - final int shmOpen(Object name, int openFlags, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int shmOpen(Object name, int openFlags, int mode) throws PosixException { checkNotInPreInitialization(); - return lib.shmOpen(nativePosixSupport, name, openFlags, mode); + return nativePosixSupport.shmOpen(name, openFlags, mode); } - @ExportMessage - final void shmUnlink(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void shmUnlink(Object name) throws PosixException { checkNotInPreInitialization(); - lib.shmUnlink(nativePosixSupport, name); + nativePosixSupport.shmUnlink(name); } @ExportMessage From 1a106f4b6f2622aa05646f33e5e87969fc4957bd Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 18:52:51 +0200 Subject: [PATCH 050/129] Convert PosixSupportLibrary semaphore operations (cherry picked from commit 5f98d0798a79a61ae28b2ab78f8df864a9d516e8) --- .../multiprocessing/SemLockBuiltins.java | 26 +++++------- .../python/runtime/EmulatedPosixSupport.java | 25 +++++++----- .../python/runtime/LoggingPosixSupport.java | 40 +++++++++---------- .../python/runtime/NativePosixSupport.java | 31 +++++++------- .../graal/python/runtime/PosixSupport.java | 10 +++++ .../python/runtime/PosixSupportLibrary.java | 10 ----- .../python/runtime/PreInitPosixSupport.java | 40 +++++++++---------- 7 files changed, 93 insertions(+), 89 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java index 6fc59e916e..7faa7252e5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java @@ -201,7 +201,6 @@ abstract static class AcquireNode extends PythonTernaryClinicBuiltinNode { static boolean acquire(VirtualFrame frame, PSemLock self, boolean blocking, Object timeoutObj, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PyFloatAsDoubleNode asDoubleNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -223,7 +222,7 @@ static boolean acquire(VirtualFrame frame, PSemLock self, boolean blocking, Obje /* Check whether we can acquire without releasing the GIL and blocking */ boolean acquired; try { - acquired = posixLib.semTryWait(posixSupport, self.getHandle()); + acquired = posixSupport.semTryWait(self.getHandle()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -232,9 +231,9 @@ static boolean acquire(VirtualFrame frame, PSemLock self, boolean blocking, Obje gil.release(true); try { if (hasDeadline) { - acquired = posixLib.semTimedWait(posixSupport, self.getHandle(), deadlineNs); + acquired = posixSupport.semTimedWait(inliningTarget, self.getHandle(), deadlineNs); } else { - posixLib.semWait(posixSupport, self.getHandle()); + posixSupport.semWait(self.getHandle()); acquired = true; } } finally { @@ -266,7 +265,6 @@ abstract static class ReleaseNode extends PythonUnaryBuiltinNode { static PNone release(VirtualFrame frame, PSemLock self, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (self.getKind() == PSemLock.RECURSIVE_MUTEX) { @@ -281,16 +279,16 @@ static PNone release(VirtualFrame frame, PSemLock self, int sval; try { try { - sval = posixLib.semGetValue(posixSupport, self.getHandle()); + sval = posixSupport.semGetValue(self.getHandle()); if (sval >= self.getMaxValue()) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.SEMAPHORE_RELEASED_TOO_MANY_TIMES); } } catch (UnsupportedPosixFeatureException e) { /* We will only check properly the maxvalue == 1 case */ if (self.getMaxValue() == 1) { - if (posixLib.semTryWait(posixSupport, self.getHandle())) { + if (posixSupport.semTryWait(self.getHandle())) { /* it was not locked so undo wait and raise */ - posixLib.semPost(posixSupport, self.getHandle()); + posixSupport.semPost(self.getHandle()); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.SEMAPHORE_RELEASED_TOO_MANY_TIMES); } } @@ -300,7 +298,7 @@ static PNone release(VirtualFrame frame, PSemLock self, } } try { - posixLib.semPost(posixSupport, self.getHandle()); + posixSupport.semPost(self.getHandle()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -354,11 +352,10 @@ abstract static class GetValueNode extends PythonUnaryBuiltinNode { int get(VirtualFrame frame, PSemLock self, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { - int sval = posixLib.semGetValue(posixSupport, self.getHandle()); + int sval = posixSupport.semGetValue(self.getHandle()); /* * some posix implementations use negative numbers to indicate the number of waiting * threads @@ -383,14 +380,13 @@ abstract static class IsZeroNode extends PythonUnaryBuiltinNode { static boolean get(VirtualFrame frame, PSemLock self, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { try { - return posixLib.semGetValue(posixSupport, self.getHandle()) == 0; + return posixSupport.semGetValue(self.getHandle()) == 0; } catch (UnsupportedPosixFeatureException e) { - if (posixLib.semTryWait(posixSupport, self.getHandle())) { - posixLib.semPost(posixSupport, self.getHandle()); + if (posixSupport.semTryWait(self.getHandle())) { + posixSupport.semPost(self.getHandle()); return false; } else { return true; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 96b6ddb8d9..56d80d1477 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -3018,33 +3018,38 @@ public void shmUnlink(Object name) throws PosixException { throw createUnsupportedFeature("shm_unlink"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - int semGetValue(long handle) throws PosixException { + public int semGetValue(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semPost(long handle) throws PosixException { + public void semPost(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semWait(long handle) throws PosixException { + public void semWait(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - boolean semTryWait(long handle) throws PosixException { + public boolean semTryWait(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - boolean semTimedWait(long handle, long deadlineNs) throws PosixException { + public boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index d2940c180c..73582befe4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1588,56 +1588,56 @@ public final void shmUnlink(Object name) throws PosixException { } } - @ExportMessage - final int semGetValue(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int semGetValue(long handle) throws PosixException { logEnter("semGetValue", "0x%x", handle); try { - return logExit("semGetValue", "%d", lib.semGetValue(delegate, handle)); + return logExit("semGetValue", "%d", delegate.semGetValue(handle)); } catch (PosixException e) { throw logException("semGetValue", e); } } - @ExportMessage - final void semPost(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semPost(long handle) throws PosixException { logEnter("semPost", "0x%x", handle); try { - lib.semPost(delegate, handle); + delegate.semPost(handle); } catch (PosixException e) { throw logException("semPost", e); } } - @ExportMessage - final void semWait(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semWait(long handle) throws PosixException { logEnter("semWait", "0x%x", handle); try { - lib.semWait(delegate, handle); + delegate.semWait(handle); } catch (PosixException e) { throw logException("semWait", e); } } - @ExportMessage - final boolean semTryWait(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTryWait(long handle) throws PosixException { logEnter("semTryWait", "0x%x", handle); try { - return logExit("semTryWait", "%b", lib.semTryWait(delegate, handle)); + return logExit("semTryWait", "%b", delegate.semTryWait(handle)); } catch (PosixException e) { throw logException("semTryWait", e); } } - @ExportMessage - final boolean semTimedWait(long handle, long deadlineNs, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { logEnter("semTimedWait", "0x%x %d", handle, deadlineNs); try { - return logExit("semTimedWait", "%b", lib.semTimedWait(delegate, handle, deadlineNs)); + return logExit("semTimedWait", "%b", delegate.semTimedWait(location, handle, deadlineNs)); } catch (PosixException e) { throw logException("semTimedWait", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 36a860ddd5..d1132a2aca 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -3167,8 +3167,9 @@ public void shmUnlink(Object name) throws PosixException { private static final UnsupportedPosixFeatureException NO_SEM_GETVALUE_EXCEPTION = new UnsupportedPosixFeatureException("sem_getvalue is not available on the current platform"); - @ExportMessage - int semGetValue(long handle) throws PosixException { + @Override + @TruffleBoundary + public int semGetValue(long handle) throws PosixException { /* * This works on Linux and is emulated with Windows semaphore APIs as on CPython. It * doesn't work on Darwin. It might work on some other Unix-likes, but it's hard to check, @@ -3189,24 +3190,27 @@ int semGetValue(long handle) throws PosixException { } } - @ExportMessage - void semPost(long handle) throws PosixException { + @Override + @TruffleBoundary + public void semPost(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_post(handle); if (res < 0) { throw getSemPostErrnoAndThrowPosixException(); } } - @ExportMessage - void semWait(long handle) throws PosixException { + @Override + @TruffleBoundary + public void semWait(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_wait(handle); if (res < 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage - boolean semTryWait(long handle) throws PosixException { + @Override + @TruffleBoundary + public boolean semTryWait(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_trywait(handle); if (res < 0) { int errno = getErrno(); @@ -3218,10 +3222,9 @@ boolean semTryWait(long handle) throws PosixException { return true; } - @ExportMessage - boolean semTimedWait(long handle, long deadlineNs, - @Bind Node node, - @CachedLibrary("this") PosixSupportLibrary thisLib) throws PosixException { + @Override + @TruffleBoundary + public boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_LINUX) { int res = posixNativeFunctionInvoker.call_sem_timedwait(handle, deadlineNs); if (res < 0) { @@ -3235,7 +3238,7 @@ boolean semTimedWait(long handle, long deadlineNs, } else { long deadlineMs = deadlineNs / 1_000_000; while (true) { - if (thisLib.semTryWait(this, handle)) { + if (semTryWait(handle)) { return true; } long currentMs = System.currentTimeMillis(); @@ -3243,7 +3246,7 @@ boolean semTimedWait(long handle, long deadlineNs, return false; } long delayMs = Math.min(deadlineMs - currentMs, 20); - TruffleSafepoint.setBlockedThreadInterruptible(node, Thread::sleep, delayMs); + TruffleSafepoint.setBlockedThreadInterruptible(location, Thread::sleep, delayMs); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 078aaa7947..04091c570c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -80,6 +80,16 @@ public final long semOpen(Object name) throws PosixException { public abstract void shmUnlink(Object name) throws PosixException; + public abstract int semGetValue(long handle) throws PosixException; + + public abstract void semPost(long handle) throws PosixException; + + public abstract void semWait(long handle) throws PosixException; + + public abstract boolean semTryWait(long handle) throws PosixException; + + public abstract boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 552a309809..ff9f01d45a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -108,16 +108,6 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - public abstract int semGetValue(Object receiver, long handle) throws PosixException; - - public abstract void semPost(Object receiver, long handle) throws PosixException; - - public abstract void semWait(Object receiver, long handle) throws PosixException; - - public abstract boolean semTryWait(Object receiver, long handle) throws PosixException; - - public abstract boolean semTimedWait(Object receiver, long handle, long deadlineNs) throws PosixException; - public static final class PwdResult { public final TruffleString name; /** diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 3746d7b365..b56b7f22a4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -1149,39 +1149,39 @@ public final void shmUnlink(Object name) throws PosixException { nativePosixSupport.shmUnlink(name); } - @ExportMessage - final int semGetValue(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int semGetValue(long handle) throws PosixException { checkNotInPreInitialization(); - return lib.semGetValue(nativePosixSupport, handle); + return nativePosixSupport.semGetValue(handle); } - @ExportMessage - final void semPost(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semPost(long handle) throws PosixException { checkNotInPreInitialization(); - lib.semPost(nativePosixSupport, handle); + nativePosixSupport.semPost(handle); } - @ExportMessage - final void semWait(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semWait(long handle) throws PosixException { checkNotInPreInitialization(); - lib.semWait(nativePosixSupport, handle); + nativePosixSupport.semWait(handle); } - @ExportMessage - final boolean semTryWait(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTryWait(long handle) throws PosixException { checkNotInPreInitialization(); - return lib.semTryWait(nativePosixSupport, handle); + return nativePosixSupport.semTryWait(handle); } - @ExportMessage - final boolean semTimedWait(long handle, long deadlineNs, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { checkNotInPreInitialization(); - return lib.semTimedWait(nativePosixSupport, handle, deadlineNs); + return nativePosixSupport.semTimedWait(location, handle, deadlineNs); } @ExportMessage From 269e42b1779ff6c9cedc51db49661473c91ff388 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 18:57:06 +0200 Subject: [PATCH 051/129] Convert PosixSupportLibrary password database operations (cherry picked from commit 4497d512a9a2ad3dcf7f2c3b5d8c770815e708af) --- .../builtins/modules/PwdModuleBuiltins.java | 11 +++---- .../python/runtime/EmulatedPosixSupport.java | 10 +++--- .../python/runtime/LoggingPosixSupport.java | 32 +++++++++---------- .../python/runtime/NativePosixSupport.java | 30 ++++++++--------- .../graal/python/runtime/PosixSupport.java | 27 ++++++++++++++++ .../python/runtime/PosixSupportLibrary.java | 27 ---------------- .../python/runtime/PreInitPosixSupport.java | 30 +++++++++-------- 7 files changed, 84 insertions(+), 83 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java index b503d3aaee..6b0d4221da 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java @@ -106,8 +106,7 @@ public final class PwdModuleBuiltins extends PythonBuiltins { @Override protected List> getNodeFactories() { - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - boolean hasGetpwentries = posixLib.hasGetpwentries(PythonContext.get(null).getPosixSupport()); + boolean hasGetpwentries = PythonContext.get(null).getPosixSupport().hasGetpwentries(); if (hasGetpwentries) { return PwdModuleBuiltinsFactory.getFactories(); } else { @@ -145,7 +144,6 @@ static Object doGetpwuid(VirtualFrame frame, Object uidObj, @Cached UidConversionNode uidConversionNode, @Cached IsBuiltinObjectProfile classProfile, @Cached GilNode gil, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile unsignedConversionProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -162,7 +160,7 @@ static Object doGetpwuid(VirtualFrame frame, Object uidObj, try { gil.release(true); try { - pwd = posixLib.getpwuid(context.getPosixSupport(), uid); + pwd = context.getPosixSupport().getpwuid(uid); } finally { gil.acquire(context); } @@ -211,7 +209,7 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, try { gil.release(true); try { - pwd = posixLib.getpwnam(context.getPosixSupport(), nameEncoded); + pwd = context.getPosixSupport().getpwnam(nameEncoded); } finally { gil.acquire(context); } @@ -232,13 +230,12 @@ public abstract static class GetpwallNode extends PythonBuiltinNode { static Object doGetpall(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile unsignedConversionProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // We cannot release the GIL, because the underlying POSIX calls are not thread safe PwdResult[] entries; try { - entries = posixLib.getpwentries(context.getPosixSupport()); + entries = context.getPosixSupport().getpwentries(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 56d80d1477..4bd09bfae2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -3053,7 +3053,7 @@ public boolean semTimedWait(Node location, long handle, long deadlineNs) throws throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override @TruffleBoundary @SuppressWarnings("static-method") public PwdResult getpwuid(long uid) throws PosixException { @@ -3074,7 +3074,7 @@ public PwdResult getpwuid(long uid) throws PosixException { throw new UnsupportedPosixFeatureException("getpwuid was excluded"); } - @ExportMessage + @Override @TruffleBoundary @SuppressWarnings("static-method") public PwdResult getpwnam(Object name) throws PosixException { @@ -3095,13 +3095,15 @@ public PwdResult getpwnam(Object name) throws PosixException { throw new UnsupportedPosixFeatureException("getpwnam was excluded"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public boolean hasGetpwentries() { return false; } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public PwdResult[] getpwentries() throws PosixException { throw createUnsupportedFeature("getpwent"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 73582befe4..1fef1e8fea 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1226,40 +1226,40 @@ public void mmapUnmap(Object mmap, long length) throws PosixException { } } - @ExportMessage - public PwdResult getpwuid(long uid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwuid(long uid) throws PosixException { logEnter("getpwuid", "%d", uid); try { - return logExit("getpwuid", "%s", lib.getpwuid(delegate, uid)); + return logExit("getpwuid", "%s", delegate.getpwuid(uid)); } catch (PosixException e) { throw logException("getpwuid", e); } } - @ExportMessage - public PwdResult getpwnam(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwnam(Object name) throws PosixException { logEnter("getpwnam", "%s", name); try { - return logExit("getpwnam", "%s", lib.getpwnam(delegate, name)); + return logExit("getpwnam", "%s", delegate.getpwnam(name)); } catch (PosixException e) { throw logException("getpwnam", e); } } - @SuppressWarnings("static-method") - @ExportMessage - public boolean hasGetpwentries(@CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return logExit("hasGetpwentries", "%b", lib.hasGetpwentries(delegate)); + @Override + @TruffleBoundary + public boolean hasGetpwentries() { + return logExit("hasGetpwentries", "%b", delegate.hasGetpwentries()); } - @ExportMessage - public PwdResult[] getpwentries( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult[] getpwentries() throws PosixException { logEnter("getpwentries", ""); try { - return logExit("getpwentries", "%s", lib.getpwentries(delegate)); + return logExit("getpwentries", "%s", delegate.getpwentries()); } catch (PosixException e) { throw logException("getpwentries", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index d1132a2aca..70bb8a708d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -3251,38 +3251,38 @@ public boolean semTimedWait(Node location, long handle, long deadlineNs) throws } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult getpwuid(long uid, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - return getpw(uid, NULLPTR, fromByteArrayNode, switchEncodingFromUtf8Node); + public PwdResult getpwuid(long uid) throws PosixException { + return getpw(uid, NULLPTR, TruffleString.FromByteArrayNode.getUncached(), TruffleString.SwitchEncodingNode.getUncached()); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult getpwnam(Object name, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + public PwdResult getpwnam(Object name) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { - return getpw(-1, namePtr, fromByteArrayNode, switchEncodingFromUtf8Node); + return getpw(-1, namePtr, TruffleString.FromByteArrayNode.getUncached(), TruffleString.SwitchEncodingNode.getUncached()); } finally { NativeMemory.free(namePtr); } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public boolean hasGetpwentries() { return true; } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult[] getpwentries( - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + public PwdResult[] getpwentries() throws PosixException { + TruffleString.FromByteArrayNode fromByteArrayNode = TruffleString.FromByteArrayNode.getUncached(); + TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node = TruffleString.SwitchEncodingNode.getUncached(); // Note: this is not thread safe, so potentially problematic while running multiple contexts // within one VM int sysConfMax = getSysConfPwdSizeMax(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 04091c570c..619a577368 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -43,6 +43,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; @@ -90,6 +91,32 @@ public final long semOpen(Object name) throws PosixException { public abstract boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException; + /** + * Equivalent of POSIX {@code getpwuid_r}. On top of the error codes defined by POSIX, this may + * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. + */ + public abstract PwdResult getpwuid(long uid) throws PosixException; + + /** + * Equivalent of POSIX {@code getpwnam_r}. On top of the error codes defined by POSIX, this may + * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. + * + * @param name the name encoded the same way as paths + */ + public abstract PwdResult getpwnam(Object name) throws PosixException; + + /** + * Availability of {@link #getpwentries()}. If {@code false}, then {@link #getpwentries()} will + * throw {@link UnsupportedPosixFeatureException}. + */ + public abstract boolean hasGetpwentries(); + + /** + * Returns a list of all entries in the password database. Equivalent of using POSIX functions + * {@code setpwent}, {@code getpwent}, and {@code endpwent}. + */ + public abstract PwdResult[] getpwentries() throws PosixException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index ff9f01d45a..230d7d6243 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -139,33 +139,6 @@ public String toString() { } } - /** - * Equivalent of POSIX {@code getpwuid_r}. On top of the error codes defined by POSIX, this may - * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. - */ - public abstract PwdResult getpwuid(Object receiver, long uid) throws PosixException; - - /** - * Equivalent of POSIX {@code getpwnam_r}. On top of the error codes defined by POSIX, this may - * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. - * - * @param receiver the receiver of the message - * @param name the name encoded the same way as paths - */ - public abstract PwdResult getpwnam(Object receiver, Object name) throws PosixException; - - /** - * Availability of {@link #getpwentries(Object)}. If {@code false}, then - * {@link #getpwentries(Object)} will throw {@link UnsupportedPosixFeatureException}. - */ - public abstract boolean hasGetpwentries(Object receiver); - - /** - * Returns a list of all entries in the password database. Equivalent of using POSIX functions - * {@code setpwent}, {@code getpwent}, and {@code endpwent}. - */ - public abstract PwdResult[] getpwentries(Object receiver) throws PosixException; - /** * Converts a {@code TruffleString} into the internal representation of paths used by the * library implementation. The implementation should return {@code null} if the path after any diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index b56b7f22a4..7a3d8459d5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -922,29 +922,31 @@ public final long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureExce return nativePosixSupport.mmapGetPointer(mmap); } - @ExportMessage - public PwdResult getpwuid(long uid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwuid(long uid) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpwuid(nativePosixSupport, uid); + return nativePosixSupport.getpwuid(uid); } - @ExportMessage - public PwdResult getpwnam(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwnam(Object name) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpwnam(nativePosixSupport, name); + return nativePosixSupport.getpwnam(name); } - @ExportMessage - public boolean hasGetpwentries(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - return nativeLib.hasGetpwentries(nativePosixSupport); + @Override + @TruffleBoundary + public boolean hasGetpwentries() { + return nativePosixSupport.hasGetpwentries(); } - @ExportMessage - public PwdResult[] getpwentries(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult[] getpwentries() throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpwentries(nativePosixSupport); + return nativePosixSupport.getpwentries(); } @ExportMessage From b35397b7cacf6a872b79269c54d50a0a8841654f Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 19:07:08 +0200 Subject: [PATCH 052/129] Convert PosixSupportLibrary path conversions (cherry picked from commit 3926ec2860232bef23715b2839c5db7e81807d69) --- .../modules/PathConversionNodeTests.java | 7 ++- .../builtins/modules/NtModuleBuiltins.java | 2 +- .../builtins/modules/PosixModuleBuiltins.java | 36 ++++++------- .../PosixSubprocessModuleBuiltins.java | 2 +- .../builtins/modules/PwdModuleBuiltins.java | 2 +- .../builtins/modules/io/FileIOBuiltins.java | 2 +- .../objects/posix/DirEntryBuiltins.java | 8 +-- .../python/runtime/EmulatedPosixSupport.java | 30 +++++------ .../python/runtime/LoggingPosixSupport.java | 32 +++++------ .../python/runtime/NativePosixSupport.java | 53 ++++++++----------- .../graal/python/runtime/PosixSupport.java | 10 ++++ .../python/runtime/PosixSupportLibrary.java | 28 ---------- .../python/runtime/PreInitPosixSupport.java | 40 +++++++------- 13 files changed, 113 insertions(+), 139 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java index a71acd9aad..43cc571c31 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java @@ -67,7 +67,7 @@ import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.tuple.PTuple; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.test.PythonTests; @@ -91,9 +91,8 @@ public static String[] params() { public void setUp() { org.junit.Assume.assumeTrue(backendName.equals("java") || !IS_WINDOWS); PythonTests.enterContext(Collections.singletonMap("python.PosixModuleBackend", backendName), new String[0]); - Object posixSupport = PythonContext.get(null).getPosixSupport(); - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - pathToString = p -> posixLib.getPathAsString(posixSupport, p.value).toJavaStringUncached(); + PosixSupport posixSupport = PythonContext.get(null).getPosixSupport(); + pathToString = p -> posixSupport.getPathAsString(p.value).toJavaStringUncached(); } @After diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java index 237185e05a..48363313f8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java @@ -125,7 +125,7 @@ Object splitroot(PosixPath path) { // TODO should call WINAPI PathCchSkipRoot PythonLanguage language = PythonLanguage.get(null); - TruffleString pathString = PosixSupportLibrary.getUncached().getPathAsString(getPosixSupport(), path.value); + TruffleString pathString = getPosixSupport().getPathAsString(path.value); int len = pathString.codePointLengthUncached(TS_ENCODING); int index = pathString.indexOfCodePointUncached(':', 0, len, TS_ENCODING); if (index <= 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 97201d1a10..101f1de8f5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -381,8 +381,8 @@ private void populateEnviron(Python3Core core) { k = posixLib.createWideStringFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); v = posixLib.createWideStringFromString(posixSupport, value); } else { - k = posixLib.createPathFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); - v = posixLib.createPathFromString(posixSupport, value); + k = posixSupport.createPathFromString(toTruffleStringUncached(pyenvLauncherKey)); + v = posixSupport.createPathFromString(value); } posixSupport.setenv(k, v, true); } catch (PosixException ignored) { @@ -593,7 +593,7 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, Object[] opaqueArgs = new Object[args.length]; for (int i = 0; i < args.length; ++i) { Object opaquePath = toOpaquePathNode.execute(frame, inliningTarget, args[i], i == 0); - Buffer bytes = posixLib.getPathAsBytes(context.getPosixSupport(), opaquePath); + Buffer bytes = context.getPosixSupport().getPathAsBytes(opaquePath); opaqueArgs[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); } LoopNode.reportLoopCount(inliningTarget, args.length); @@ -1779,7 +1779,7 @@ static TruffleString getcwd(VirtualFrame frame, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getPathAsString(context.getPosixSupport(), context.getPosixSupport().getcwd()); + return context.getPosixSupport().getPathAsString(context.getPosixSupport().getcwd()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1797,7 +1797,7 @@ static PBytes getcwdb(VirtualFrame frame, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object path = context.getPosixSupport().getcwd(); - return opaquePathToBytes(path, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytes(path, context.getPosixSupport(), context.getLanguage(inliningTarget)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1981,9 +1981,9 @@ private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dir } Object name = posixSupport.dirEntryGetName(dirEntry); if (produceBytes) { - addToList(list, opaquePathToBytes(name, posixLib, posixSupport, language)); + addToList(list, opaquePathToBytes(name, posixSupport, language)); } else { - addToList(list, posixLib.getPathAsString(posixSupport, name)); + addToList(list, posixSupport.getPathAsString(name)); } } } catch (PosixException e) { @@ -2573,9 +2573,9 @@ static Object readlinkAsBytes(VirtualFrame frame, PosixPath path, int dirFd, try { Object link = context.getPosixSupport().readlinkat(dirFd, path.value); if (wasBufferLikeProfile.profile(inliningTarget, path.wasBufferLike)) { - return opaquePathToBytes(link, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytes(link, context.getPosixSupport(), context.getLanguage(inliningTarget)); } else { - return posixLib.getPathAsString(context.getPosixSupport(), link); + return context.getPosixSupport().getPathAsString(link); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -3093,7 +3093,7 @@ static Object doString(Node inliningTarget, Object strObj, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, strObj); - return checkPath(inliningTarget, posixLib.createPathFromString(context.getPosixSupport(), str), raiseNode); + return checkPath(inliningTarget, context.getPosixSupport().createPathFromString(str), raiseNode); } @Specialization @@ -3102,7 +3102,7 @@ static Object doBytes(Node inliningTarget, PBytes bytes, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { - return checkPath(inliningTarget, posixLib.createPathFromBytes(context.getPosixSupport(), toBytesNode.execute(bytes)), raiseNode); + return checkPath(inliningTarget, context.getPosixSupport().createPathFromBytes(toBytesNode.execute(bytes)), raiseNode); } private static Object checkPath(Node inliningTarget, Object path, PRaiseNode raiseNode) { @@ -3284,8 +3284,8 @@ private static BigInteger convertToNanoseconds(long sec, long ns) { return r.add(BigInteger.valueOf(ns)); } - public static PBytes opaquePathToBytes(Object opaquePath, PosixSupportLibrary posixLib, Object posixSupport, PythonLanguage language) { - Buffer buf = posixLib.getPathAsBytes(posixSupport, opaquePath); + public static PBytes opaquePathToBytes(Object opaquePath, PosixSupport posixSupport, PythonLanguage language) { + Buffer buf = posixSupport.getPathAsBytes(opaquePath); if (buf.length > Integer.MAX_VALUE) { // sanity check that it is safe to cast result.length to int, to be removed once // we support large arrays @@ -3436,7 +3436,7 @@ PosixFileHandle doNone(@SuppressWarnings("unused") PNone value, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { - Object path = posixLib.createPathFromString(context.getPosixSupport(), T_DOT); + Object path = context.getPosixSupport().createPathFromString(T_DOT); return new PosixPath(null, checkPath(inliningTarget, path, raiseNode), false); } @@ -3476,7 +3476,7 @@ PosixFileHandle doUnicode(Object value, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, value); - Object path = posixLib.createPathFromString(context.getPosixSupport(), str); + Object path = context.getPosixSupport().createPathFromString(str); return new PosixPath(value, checkPath(inliningTarget, path, raiseNode), false); } @@ -3488,7 +3488,7 @@ PosixFileHandle doBytes(PBytes value, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { - Object path = posixLib.createPathFromBytes(context.getPosixSupport(), toByteArrayNode.execute(value)); + Object path = context.getPosixSupport().createPathFromBytes(toByteArrayNode.execute(value)); return new PosixPath(value, checkPath(inliningTarget, path, raiseNode), true); } @@ -3748,8 +3748,8 @@ protected PosixFileHandle(Object originalObject) { * Contains the path converted to the representation used by the {@code PosixSupportLibrary} * implementation * - * @see PosixSupportLibrary#createPathFromString(Object, TruffleString) - * @see PosixSupportLibrary#createPathFromBytes(Object, byte[]) + * @see PosixSupport#createPathFromString(TruffleString) + * @see PosixSupport#createPathFromBytes(byte[]) */ public static class PosixPath extends PosixFileHandle { public final Object value; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java index c17ecf6c32..84708bc868 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java @@ -151,7 +151,7 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, } Object o = getItemNode.execute(argsStorage, i); Object path = objectToOpaquePathNode.execute(frame, inliningTarget, o, false); - Buffer bytes = posixLib.getPathAsBytes(context.getPosixSupport(), path); + Buffer bytes = context.getPosixSupport().getPathAsBytes(path); argsArray[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); } LoopNode.reportLoopCount(inliningTarget, len); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java index 6b0d4221da..2d5b64dc5a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java @@ -203,7 +203,7 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, // Note: CPython also takes only Strings, not bytes, and then encodes the String // StringOrBytesToOpaquePathNode already checks for embedded '\0' Object pathEncoded = encodeFSDefault.execute(inliningTarget, name); - Buffer nameBytes = posixLib.getPathAsBytes(context.getPosixSupport(), pathEncoded); + Buffer nameBytes = context.getPosixSupport().getPathAsBytes(pathEncoded); Object nameEncoded = posixLib.createCStringFromBytes(context.getPosixSupport(), nameBytes.data); PwdResult pwd; try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index 75721e6bcb..05715262c0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -241,7 +241,7 @@ private static int open(VirtualFrame frame, TruffleString name, int flags, int m InlinedBranchProfile errorProfile, PRaiseNode raiseNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - Object path = posixLib.createPathFromString(ctxt.getPosixSupport(), name); + Object path = ctxt.getPosixSupport().createPathFromString(name); if (path == null) { throw raiseNode.raise(inliningTarget, ValueError, EMBEDDED_NULL_BYTE); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java index f166ace632..9a513ee0f0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java @@ -121,9 +121,9 @@ static Object nameAsBytes(VirtualFrame frame, PDirEntry self, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { if (produceBytesProfile.profile(inliningTarget, self.produceBytes())) { - return opaquePathToBytes(context.getPosixSupport().dirEntryGetName(self.dirEntryData), posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytes(context.getPosixSupport().dirEntryGetName(self.dirEntryData), context.getPosixSupport(), context.getLanguage(inliningTarget)); } else { - return posixLib.getPathAsString(context.getPosixSupport(), context.getPosixSupport().dirEntryGetName(self.dirEntryData)); + return context.getPosixSupport().getPathAsString(context.getPosixSupport().dirEntryGetName(self.dirEntryData)); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -173,9 +173,9 @@ static PosixPath createBytes(VirtualFrame frame, Node inliningTarget, PDirEntry throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } if (produceBytesProfile.profile(inliningTarget, self.produceBytes())) { - self.pathCache = new PosixPath(opaquePathToBytes(opaquePath, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)), opaquePath, true); + self.pathCache = new PosixPath(opaquePathToBytes(opaquePath, context.getPosixSupport(), context.getLanguage(inliningTarget)), opaquePath, true); } else { - self.pathCache = new PosixPath(posixLib.getPathAsString(context.getPosixSupport(), opaquePath), opaquePath, false); + self.pathCache = new PosixPath(context.getPosixSupport().getPathAsString(opaquePath), opaquePath, false); } return self.pathCache; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 4bd09bfae2..0e408c826f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -227,7 +227,7 @@ import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.ErrorAndMessagePair; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.OperationWouldBlockException; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; +import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNodeGen; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; @@ -4438,32 +4438,32 @@ private static byte[] mapIPv4toIPv6(byte[] ipv4) { // ------------------ // Path conversions - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public Object createPathFromString(TruffleString path, - @Bind Node inliningTarget, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Exclusive @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { + public Object createPathFromString(TruffleString path) { String javaPath = getPythonOS() == PLATFORM_WIN32 - ? toJavaStringNode.execute(path) - : createUTF8String(encodeFSDefaultNode.execute(null, inliningTarget, path)); + ? TruffleString.ToJavaStringNode.getUncached().execute(path) + : createUTF8String(PyUnicodeEncodeFSDefaultNodeGen.getUncached().execute(null, null, path)); return checkEmbeddedNulls(javaPath); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public Object createPathFromBytes(byte[] path) { return checkEmbeddedNulls(createUTF8String(path)); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public TruffleString getPathAsString(Object path, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { - return fromJavaStringNode.execute((String) path, TS_ENCODING); + public TruffleString getPathAsString(Object path) { + return TruffleString.FromJavaStringNode.getUncached().execute((String) path, TS_ENCODING); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public Buffer getPathAsBytes(Object path) { return Buffer.wrap(utf8StringToBytes((String) path)); @@ -4488,7 +4488,7 @@ public Object createWideStringFromString(TruffleString string, @ExportMessage public TruffleString getCStringAsString(Object string, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { return fromJavaStringNode.execute((String) string, TS_ENCODING); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 1fef1e8fea..6b98f7b0bf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1670,32 +1670,32 @@ final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src, } } - @ExportMessage - final Object createPathFromString(TruffleString path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final Object createPathFromString(TruffleString path) { logEnter(Level.FINEST, "createPathFromString", "%s", path); - return logExit(Level.FINEST, "createPathFromString", "%s", lib.createPathFromString(delegate, path)); + return logExit(Level.FINEST, "createPathFromString", "%s", delegate.createPathFromString(path)); } - @ExportMessage - final Object createPathFromBytes(byte[] path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final Object createPathFromBytes(byte[] path) { logEnter(Level.FINEST, "createPathFromBytes", "%s", path); - return logExit(Level.FINEST, "createPathFromBytes", "%s", lib.createPathFromBytes(delegate, path)); + return logExit(Level.FINEST, "createPathFromBytes", "%s", delegate.createPathFromBytes(path)); } - @ExportMessage - final TruffleString getPathAsString(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final TruffleString getPathAsString(Object path) { logEnter(Level.FINEST, "getPathAsString", "%s", path); - return logExit(Level.FINEST, "getPathAsString", "%s", lib.getPathAsString(delegate, path)); + return logExit(Level.FINEST, "getPathAsString", "%s", delegate.getPathAsString(path)); } - @ExportMessage - final Buffer getPathAsBytes(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final Buffer getPathAsBytes(Object path) { logEnter(Level.FINEST, "getPathAsBytes", "%s", path); - return logExit(Level.FINEST, "getPathAsBytes", "%s", lib.getPathAsBytes(delegate, path)); + return logExit(Level.FINEST, "getPathAsBytes", "%s", delegate.getPathAsBytes(path)); } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 70bb8a708d..9e01f1f080 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -99,7 +99,7 @@ import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; +import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNodeGen; import com.oracle.graal.python.lib.PyUnicodeFSDecoderNode; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.call.CallNode; @@ -3446,57 +3446,50 @@ private int getSysConfPwdSizeMax() throws PosixException { // ------------------ // Path conversions - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public Object createPathFromString(TruffleString path, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode, - @Exclusive @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { + public Object createPathFromString(TruffleString path) { if (WINDOWS) { - TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); + TruffleString utf16 = TruffleString.SwitchEncodingNode.getUncached().execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return checkWidePath(TruffleString.CopyToByteArrayNode.getUncached().execute(utf16, UTF_16LE)); } - return checkNarrowPath(encodeFSDefaultNode.execute(null, inliningTarget, path)); + return checkNarrowPath(PyUnicodeEncodeFSDefaultNodeGen.getUncached().execute(null, null, path)); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public Object createPathFromBytes(byte[] path, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + public Object createPathFromBytes(byte[] path) { if (WINDOWS) { - TruffleString utf8 = fromByteArrayNode.execute(path, UTF_8, true); - TruffleString utf16 = switchEncodingNode.execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(inliningTarget, path)); - return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); + TruffleString utf8 = TruffleString.FromByteArrayNode.getUncached().execute(path, UTF_8, true); + TruffleString utf16 = TruffleString.SwitchEncodingNode.getUncached().execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(null, path)); + return checkWidePath(TruffleString.CopyToByteArrayNode.getUncached().execute(utf16, UTF_16LE)); } return checkNarrowPath(path); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public TruffleString getPathAsString(Object path, - @Exclusive @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Exclusive @Cached TruffleString.IsValidNode isValidNode, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { + public TruffleString getPathAsString(Object path) { NativePath result = (NativePath) path; - TruffleString encoded = fromByteArrayNode.execute(result.data, 0, result.data.length, result.encoding(), true); + TruffleString encoded = TruffleString.FromByteArrayNode.getUncached().execute(result.data, 0, result.data.length, result.encoding(), true); if (result instanceof WidePath) { - return switchEncodingNode.execute(encoded, TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return TruffleString.SwitchEncodingNode.getUncached().execute(encoded, TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); } TruffleString utf8 = encoded; - if (isValidNode.execute(utf8, UTF_8)) { - return switchEncodingNode.execute(utf8, TS_ENCODING); + if (TruffleString.IsValidNode.getUncached().execute(utf8, UTF_8)) { + return TruffleString.SwitchEncodingNode.getUncached().execute(utf8, TS_ENCODING); } TranscodingErrorHandler errorHandler = PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 ? TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8 : PyUnicodeFSDecoderNode.SURROGATE_ESCAPE_FROM_UTF8_TRANSCODING_ERROR_HANDLER; - return switchEncodingNode.execute(utf8, TS_ENCODING, errorHandler); + return TruffleString.SwitchEncodingNode.getUncached().execute(utf8, TS_ENCODING, errorHandler); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public Buffer getPathAsBytes(Object path) { NativePath nativePath = (NativePath) path; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 619a577368..0a666f4ba5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -117,6 +117,16 @@ public final long semOpen(Object name) throws PosixException { */ public abstract PwdResult[] getpwentries() throws PosixException; + /** Returns null if the converted path contains embedded null characters. */ + public abstract Object createPathFromString(TruffleString path); + + /** Returns null if the converted path contains embedded null characters. */ + public abstract Object createPathFromBytes(byte[] path); + + public abstract TruffleString getPathAsString(Object path); + + public abstract Buffer getPathAsBytes(Object path); + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 230d7d6243..8b8863ae00 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -139,34 +139,6 @@ public String toString() { } } - /** - * Converts a {@code TruffleString} into the internal representation of paths used by the - * library implementation. The implementation should return {@code null} if the path after any - * necessary conversion contains embedded null characters. - * - * @param receiver the receiver of the message - * @param path the path as a {@code TruffleString} - * @return an opaque object representing the path or {@code null} if the path contains null - * characters - */ - public abstract Object createPathFromString(Object receiver, TruffleString path); - - /** - * Converts a {@code byte} array into the internal representation of paths used by the library - * implementation. The implementation should return {@code null} if the path after any necessary - * conversion contains embedded null characters. - * - * @param receiver the receiver of the message - * @param path the path as a a {@code byte[]} array - * @return an opaque object representing the path or {@code null} if the path contains null - * characters - */ - public abstract Object createPathFromBytes(Object receiver, byte[] path); - - public abstract TruffleString getPathAsString(Object receiver, Object path); - - public abstract Buffer getPathAsBytes(Object receiver, Object path); - /** Converts a string to strict UTF-8 for non-filesystem APIs that use CPython's {@code s} conversion. */ public abstract Object createCStringFromString(Object receiver, TruffleString string); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 7a3d8459d5..56e90862f1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -1207,40 +1207,40 @@ final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src, return nativeLib.createUniversalSockAddrUnix(nativePosixSupport, src); } - @ExportMessage - final Object createPathFromString(TruffleString path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Object createPathFromString(TruffleString path) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createPathFromString(emulatedPosixSupport, path); + return emulatedPosixSupport.createPathFromString(path); } - return nativeLib.createPathFromString(nativePosixSupport, path); + return nativePosixSupport.createPathFromString(path); } - @ExportMessage - final Object createPathFromBytes(byte[] path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Object createPathFromBytes(byte[] path) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createPathFromBytes(emulatedPosixSupport, path); + return emulatedPosixSupport.createPathFromBytes(path); } - return nativeLib.createPathFromBytes(nativePosixSupport, path); + return nativePosixSupport.createPathFromBytes(path); } - @ExportMessage - final TruffleString getPathAsString(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final TruffleString getPathAsString(Object path) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getPathAsString(emulatedPosixSupport, path); + return emulatedPosixSupport.getPathAsString(path); } - return nativeLib.getPathAsString(nativePosixSupport, path); + return nativePosixSupport.getPathAsString(path); } - @ExportMessage - final Buffer getPathAsBytes(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Buffer getPathAsBytes(Object path) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getPathAsBytes(emulatedPosixSupport, path); + return emulatedPosixSupport.getPathAsBytes(path); } - return nativeLib.getPathAsBytes(nativePosixSupport, path); + return nativePosixSupport.getPathAsBytes(path); } @ExportMessage From a5a6dd1b1f2e2a49034da7d9edd87859c33589ea Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 19:14:36 +0200 Subject: [PATCH 053/129] Convert PosixSupportLibrary narrow and wide strings (cherry picked from commit 98210d8f30a33c677922dc86dd7b2d6077de2f25) --- .../builtins/modules/PosixModuleBuiltins.java | 22 ++++---- .../modules/PosixShMemModuleBuiltins.java | 4 +- .../PosixSubprocessModuleBuiltins.java | 12 ++--- .../builtins/modules/PwdModuleBuiltins.java | 2 +- .../modules/SocketModuleBuiltins.java | 44 ++++++++-------- .../MultiprocessingModuleBuiltins.java | 2 +- .../multiprocessing/SemLockBuiltins.java | 4 +- .../builtins/objects/socket/SocketNodes.java | 33 ++++++------ .../python/runtime/EmulatedPosixSupport.java | 30 +++++------ .../python/runtime/LoggingPosixSupport.java | 40 +++++++-------- .../python/runtime/NativePosixSupport.java | 38 +++++++------- .../graal/python/runtime/PosixSupport.java | 13 +++++ .../python/runtime/PosixSupportLibrary.java | 13 ----- .../python/runtime/PreInitPosixSupport.java | 50 +++++++++---------- 14 files changed, 155 insertions(+), 152 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 101f1de8f5..17cf3a54ae 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -378,8 +378,8 @@ private void populateEnviron(Python3Core core) { Object k; Object v; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { - k = posixLib.createWideStringFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); - v = posixLib.createWideStringFromString(posixSupport, value); + k = posixSupport.createWideStringFromString(toTruffleStringUncached(pyenvLauncherKey)); + v = posixSupport.createWideStringFromString(value); } else { k = posixSupport.createPathFromString(toTruffleStringUncached(pyenvLauncherKey)); v = posixSupport.createPathFromString(value); @@ -458,14 +458,14 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object valueObject, if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { TruffleString name = (TruffleString) nameObject; TruffleString value = (TruffleString) valueObject; - nameOpaque = checkNull(inliningTarget, posixLib.createWideStringFromString(posixSupport, name), raiseNode); - valueOpaque = checkNull(inliningTarget, posixLib.createWideStringFromString(posixSupport, value), raiseNode); + nameOpaque = checkNull(inliningTarget, posixSupport.createWideStringFromString(name), raiseNode); + valueOpaque = checkNull(inliningTarget, posixSupport.createWideStringFromString(value), raiseNode); checkWindowsEnvName(inliningTarget, name, codePointLengthNode, indexOfCodePointNode, raiseNode); } else { byte[] name = toBytesNode.execute((PBytes) nameObject); byte[] value = toBytesNode.execute((PBytes) valueObject); - nameOpaque = checkNull(inliningTarget, posixLib.createCStringFromBytes(posixSupport, name), raiseNode); - valueOpaque = checkNull(inliningTarget, posixLib.createCStringFromBytes(posixSupport, value), raiseNode); + nameOpaque = checkNull(inliningTarget, posixSupport.createCStringFromBytes(name), raiseNode); + valueOpaque = checkNull(inliningTarget, posixSupport.createCStringFromBytes(value), raiseNode); checkEqualSign(inliningTarget, name, raiseNode); } auditNode.audit(frame, inliningTarget, T_OS_PUTENV, nameObject, valueObject); @@ -529,11 +529,11 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object nameOpaque; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { TruffleString name = (TruffleString) nameObject; - nameOpaque = checkNull(inliningTarget, posixLib.createWideStringFromString(context.getPosixSupport(), name), raiseNode); + nameOpaque = checkNull(inliningTarget, context.getPosixSupport().createWideStringFromString(name), raiseNode); PutenvNode.checkWindowsEnvName(inliningTarget, name, codePointLengthNode, indexOfCodePointNode, raiseNode); } else { byte[] name = toBytesNode.execute((PBytes) nameObject); - nameOpaque = checkNull(inliningTarget, posixLib.createCStringFromBytes(context.getPosixSupport(), name), raiseNode); + nameOpaque = checkNull(inliningTarget, context.getPosixSupport().createCStringFromBytes(name), raiseNode); } auditNode.audit(frame, inliningTarget, T_OS_UNSETENV, nameObject); try { @@ -594,7 +594,7 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, for (int i = 0; i < args.length; ++i) { Object opaquePath = toOpaquePathNode.execute(frame, inliningTarget, args[i], i == 0); Buffer bytes = context.getPosixSupport().getPathAsBytes(opaquePath); - opaqueArgs[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); + opaqueArgs[i] = context.getPosixSupport().createCStringFromBytes(bytes.data); } LoopNode.reportLoopCount(inliningTarget, args.length); // TODO ValueError "execv() arg 2 first element cannot be empty" @@ -2864,9 +2864,9 @@ static int system(VirtualFrame frame, Object command, try { Object cmdOpaque; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { - cmdOpaque = posixLib.createWideStringFromString(context.getPosixSupport(), (TruffleString) command); + cmdOpaque = context.getPosixSupport().createWideStringFromString((TruffleString) command); } else { - cmdOpaque = posixLib.createCStringFromBytes(context.getPosixSupport(), toBytesNode.execute((PBytes) command)); + cmdOpaque = context.getPosixSupport().createCStringFromBytes(toBytesNode.execute((PBytes) command)); } return context.getPosixSupport().system(cmdOpaque); } finally { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java index a6d685a543..9e43933540 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java @@ -93,7 +93,7 @@ static int shmOpen(VirtualFrame frame, TruffleString path, int flags, int mode, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object name = posixLib.createCStringFromString(context.getPosixSupport(), path); + Object name = context.getPosixSupport().createCStringFromString(path); return context.getPosixSupport().shmOpen(name, flags, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); @@ -118,7 +118,7 @@ static PNone shmUnlink(VirtualFrame frame, TruffleString path, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object name = posixLib.createCStringFromString(context.getPosixSupport(), path); + Object name = context.getPosixSupport().createCStringFromString(path); context.getPosixSupport().shmUnlink(name); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java index 84708bc868..0766f8f4b7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java @@ -152,7 +152,7 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, Object o = getItemNode.execute(argsStorage, i); Object path = objectToOpaquePathNode.execute(frame, inliningTarget, o, false); Buffer bytes = context.getPosixSupport().getPathAsBytes(path); - argsArray[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); + argsArray[i] = context.getPosixSupport().createCStringFromBytes(bytes.data); } LoopNode.reportLoopCount(inliningTarget, len); return argsArray; @@ -186,7 +186,7 @@ static Object doSequence(VirtualFrame frame, Object env, for (int i = 0; i < length; ++i) { Object o = getItem.execute(frame, inliningTarget, env, i); byte[] bytes = toBytesNode.execute(frame, o); - Object o1 = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes); + Object o1 = context.getPosixSupport().createCStringFromBytes(bytes); if (o1 == null) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.EMBEDDED_NULL_BYTE); } @@ -239,8 +239,8 @@ private static byte[] fsEncode(String s) { return s.getBytes(); } - private static Object createCStringFromBytes(Node inliningTarget, byte[] bytes, PosixSupportLibrary posixLib, PRaiseNode raiseNode) { - Object o = posixLib.createCStringFromBytes(PosixSupport.get(inliningTarget), bytes); + private static Object createCStringFromBytes(Node inliningTarget, byte[] bytes, PRaiseNode raiseNode) { + Object o = PosixSupport.get(inliningTarget).createCStringFromBytes(bytes); if (o == null) { // TODO reconsider the contract of PosixSupportLibrary#createCStringFromBytes w.r.t. // embedded null checks (we need to review that anyway since PosixSupportLibrary @@ -299,7 +299,7 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo } Object[] extendedArgs = new Object[additionalArgs.length + (processArgs.length == 0 ? 0 : processArgs.length - 1)]; for (int j = 0; j < additionalArgs.length; ++j) { - extendedArgs[j] = createCStringFromBytes(inliningTarget, fsEncode(additionalArgs[j].toJavaStringUncached()), posixLib, raiseNode); + extendedArgs[j] = createCStringFromBytes(inliningTarget, fsEncode(additionalArgs[j].toJavaStringUncached()), raiseNode); } if (processArgs.length > 1) { PythonUtils.arraycopy(processArgs, 1, extendedArgs, additionalArgs.length, processArgs.length - 1); @@ -307,7 +307,7 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo processArgs = extendedArgs; executables[i] = extendedArgs[0]; } else { - executables[i] = createCStringFromBytes(inliningTarget, bytes, posixLib, raiseNode); + executables[i] = createCStringFromBytes(inliningTarget, bytes, raiseNode); } } LoopNode.reportLoopCount(inliningTarget, length); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java index 2d5b64dc5a..6e9027b582 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java @@ -204,7 +204,7 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, // StringOrBytesToOpaquePathNode already checks for embedded '\0' Object pathEncoded = encodeFSDefault.execute(inliningTarget, name); Buffer nameBytes = context.getPosixSupport().getPathAsBytes(pathEncoded); - Object nameEncoded = posixLib.createCStringFromBytes(context.getPosixSupport(), nameBytes.data); + Object nameEncoded = context.getPosixSupport().createCStringFromBytes(nameBytes.data); PwdResult pwd; try { gil.release(true); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index 08df641bd3..05ac586e71 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -256,7 +256,7 @@ static TruffleString doGeneric(VirtualFrame frame, try { gil.release(true); try { - return posixLib.getCStringAsString(context.getPosixSupport(), posixLib.gethostname(context.getPosixSupport())); + return context.getPosixSupport().getCStringAsString(posixLib.gethostname(context.getPosixSupport())); } finally { gil.acquire(); } @@ -292,7 +292,7 @@ static Object doGeneric(VirtualFrame frame, Object ip, int family = sockAddrLibrary.getFamily(addr); try { Object[] getnameinfoResult = posixLib.getnameinfo(context.getPosixSupport(), addr, NI_NAMEREQD.value); - TruffleString hostname = posixLib.getCStringAsString(context.getPosixSupport(), getnameinfoResult[0]); + TruffleString hostname = context.getPosixSupport().getCStringAsString(getnameinfoResult[0]); SequenceStorage storage = new ObjectSequenceStorage(5); @@ -300,7 +300,7 @@ static Object doGeneric(VirtualFrame frame, Object ip, AddrInfoCursor cursor; gil.release(true); try { - cursor = posixLib.getaddrinfo(context.getPosixSupport(), getnameinfoResult[0], posixLib.createCStringFromString(context.getPosixSupport(), T_ZERO), + cursor = posixLib.getaddrinfo(context.getPosixSupport(), getnameinfoResult[0], context.getPosixSupport().createCStringFromString(T_ZERO), family, 0, 0, 0); } finally { gil.acquire(); @@ -351,7 +351,7 @@ static TruffleString getHostByName(VirtualFrame frame, Object nameObj, UniversalSockAddr addr = setIpAddrNode.execute(frame, name, AF_INET.value); Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); try { - return posixLib.getCStringAsString(context.getPosixSupport(), posixLib.inet_ntop(context.getPosixSupport(), AF_INET.value, inet4SockAddr.getAddressAsBytes())); + return context.getPosixSupport().getCStringAsString(posixLib.inet_ntop(context.getPosixSupport(), AF_INET.value, inet4SockAddr.getAddressAsBytes())); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -386,12 +386,12 @@ static Object get(VirtualFrame frame, Object nameObj, */ try { PosixSupport posixSupport = context.getPosixSupport(); - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixLib.createCStringFromBytes(posixSupport, name), + AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixSupport.createCStringFromBytes(name), null, AF_INET.value, 0, 0, AI_CANONNAME.value); try { - TruffleString canonName = posixLib.getCStringAsString(posixSupport, addrInfoCursorLib.getCanonName(cursor)); + TruffleString canonName = posixSupport.getCStringAsString(addrInfoCursorLib.getCanonName(cursor)); Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addrInfoCursorLib.getSockAddr(cursor)); - TruffleString addr = posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, AF_INET.value, inet4SockAddr.getAddressAsBytes())); + TruffleString addr = posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, AF_INET.value, inet4SockAddr.getAddressAsBytes())); // getaddrinfo doesn't support aliases PList aliases = PFactory.createList(context.getLanguage(inliningTarget)); // we support just one address for now @@ -455,7 +455,7 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec AddrInfoCursor cursor; try { PosixSupport posixSupport = context.getPosixSupport(); - cursor = posixLib.getaddrinfo(posixSupport, null, posixLib.createCStringFromString(posixSupport, serviceName), AF_INET.value, 0, protocol, 0); + cursor = posixLib.getaddrinfo(posixSupport, null, posixSupport.createCStringFromString(serviceName), AF_INET.value, 0, protocol, 0); } finally { gil.acquire(); } @@ -522,7 +522,7 @@ Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, flags |= NI_DGRAM.value; } Object[] result = posixLib.getnameinfo(getPosixSupport(), addr, flags); - TruffleString name = posixLib.getCStringAsString(getPosixSupport(), result[1]); + TruffleString name = getPosixSupport().getCStringAsString(result[1]); checkName(name); return name; } finally { @@ -603,8 +603,8 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, gil.release(true); PosixSupport posixSupport = context.getPosixSupport(); try { - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixLib.createCStringFromString(posixSupport, address), - posixLib.createCStringFromString(posixSupport, fromLongNode.execute(port, TS_ENCODING, false)), + AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixSupport.createCStringFromString(address), + posixSupport.createCStringFromString(fromLongNode.execute(port, TS_ENCODING, false)), AF_UNSPEC.value, SOCK_DGRAM.value, 0, AI_NUMERICHOST.value); try { family = addrInfoCursorLib.getFamily(cursor); @@ -632,8 +632,8 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, } Object[] getnameinfo = posixLib.getnameinfo(posixSupport, queryAddr, flags); - TruffleString host = posixLib.getCStringAsString(posixSupport, getnameinfo[0]); - TruffleString service = posixLib.getCStringAsString(posixSupport, getnameinfo[1]); + TruffleString host = posixSupport.getCStringAsString(getnameinfo[0]); + TruffleString service = posixSupport.getCStringAsString(getnameinfo[1]); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{host, service}); } catch (GetAddrInfoException e) { throw constructAndRaiseNode.get(inliningTarget).executeWithArgsOnly(frame, SocketGAIError, new Object[]{e.getErrorCode(), e.getMessageAsTruffleString()}); @@ -683,17 +683,17 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje Object host = null; PosixSupport posixSupport = context.getPosixSupport(); if (hostObject != PNone.NONE) { - host = posixLib.createCStringFromBytes(posixSupport, idna.execute(frame, hostObject)); + host = posixSupport.createCStringFromBytes(idna.execute(frame, hostObject)); } Object port; Object portObjectProfiled = profile.profile(inliningTarget, portObject); if (PGuards.canBeInteger(portObjectProfiled)) { - port = posixLib.createCStringFromString(posixSupport, fromLongNode.execute(asLongNode.execute(frame, inliningTarget, portObjectProfiled), TS_ENCODING, false)); + port = posixSupport.createCStringFromString(fromLongNode.execute(asLongNode.execute(frame, inliningTarget, portObjectProfiled), TS_ENCODING, false)); } else if (PGuards.isString(portObjectProfiled)) { - port = posixLib.createCStringFromString(posixSupport, castToString.execute(inliningTarget, portObjectProfiled)); + port = posixSupport.createCStringFromString(castToString.execute(inliningTarget, portObjectProfiled)); } else if (PGuards.isBytes(portObjectProfiled)) { - port = posixLib.createCStringFromBytes(posixSupport, toBytes.execute(frame, portObjectProfiled)); + port = posixSupport.createCStringFromBytes(toBytes.execute(frame, portObjectProfiled)); } else if (portObject == PNone.NONE) { port = null; } else { @@ -722,7 +722,7 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje Object addr = makeSockAddrNode.execute(frame, inliningTarget, cursorLib.getSockAddr(cursor)); TruffleString canonName = T_EMPTY_STRING; if (cursorLib.getCanonName(cursor) != null) { - canonName = posixLib.getCStringAsString(posixSupport, cursorLib.getCanonName(cursor)); + canonName = posixSupport.getCStringAsString(cursorLib.getCanonName(cursor)); } PTuple tuple = PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{cursorLib.getFamily(cursor), cursorLib.getSockType(cursor), cursorLib.getProtocol(cursor), canonName, addr}); @@ -820,7 +820,7 @@ static PBytes doConvert(TruffleString addr, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - int converted = posixLib.inet_aton(posixSupport, posixLib.createCStringFromString(posixSupport, addr)); + int converted = posixLib.inet_aton(posixSupport, posixSupport.createCStringFromString(addr)); byte[] bytes = new byte[4]; ByteArraySupport.bigEndian().putInt(bytes, 0, converted); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); @@ -856,7 +856,7 @@ static TruffleString doGeneric(VirtualFrame frame, Object addr, } PosixSupport posixSupport = context.getPosixSupport(); Object result = posixLib.inet_ntoa(posixSupport, ByteArraySupport.bigEndian().getInt(bytes, 0)); - return posixLib.getCStringAsString(posixSupport, result); + return posixSupport.getCStringAsString(result); } finally { bufferLib.release(buffer, frame, callData); } @@ -877,7 +877,7 @@ static PBytes doConvert(VirtualFrame frame, int family, TruffleString addr, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - byte[] bytes = posixLib.inet_pton(posixSupport, family, posixLib.createCStringFromString(posixSupport, addr)); + byte[] bytes = posixLib.inet_pton(posixSupport, family, posixSupport.createCStringFromString(addr)); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -924,7 +924,7 @@ static TruffleString doGeneric(VirtualFrame frame, int family, Object obj, try { PosixSupport posixSupport = context.getPosixSupport(); Object result = posixLib.inet_ntop(posixSupport, family, bytes); - return posixLib.getCStringAsString(posixSupport, result); + return posixSupport.getCStringAsString(result); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java index b5323e467b..64bd8411e9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java @@ -174,7 +174,7 @@ PNone doit(VirtualFrame frame, TruffleString name, @Bind Node inliningTarget, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixSupport.semUnlink(posixLib.createCStringFromString(posixSupport, name)); + posixSupport.semUnlink(posixSupport.createCStringFromString(name)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java index 7faa7252e5..b7a0f8c510 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java @@ -127,7 +127,7 @@ static PSemLock construct(VirtualFrame frame, Object cls, int kind, int value, i if (kind != PSemLock.RECURSIVE_MUTEX && kind != PSemLock.SEMAPHORE) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.UNRECOGNIZED_KIND); } - Object posixName = posixLib.createCStringFromString(posixSupport, name); + Object posixName = posixSupport.createCStringFromString(name); long handle; try { handle = posixSupport.semOpen(posixName, O_CREAT.value | O_EXCL.value, 0600, value); @@ -425,7 +425,7 @@ static Object rebuild(VirtualFrame frame, Object cls, long origHandle, int kind, return PFactory.createSemLock(cls, getInstanceShape.execute(cls), origHandle, kind, maxValue, null); } TruffleString posixNameString = (TruffleString) name; - Object posixName = posixLib.createCStringFromString(posixSupport, posixNameString); + Object posixName = posixSupport.createCStringFromString(posixNameString); long handle; try { handle = posixSupport.semOpen(posixName); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index 540faf870e..efcf853779 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -85,6 +85,7 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; @@ -149,7 +150,7 @@ static UniversalSockAddr doInet(VirtualFrame frame, @SuppressWarnings("unused") byte[] host = idnaConverter.execute(frame, tupleGetItem.execute(inliningTarget, address, 0)); int port = parsePort(frame, caller, asIntNode, inliningTarget, errorProfile, tupleGetItem.execute(inliningTarget, address, 1), raiseNode); UniversalSockAddr addr = setIpAddrNode.execute(frame, host, AF_INET.value); - Object posixSupport = context.getPosixSupport(); + PosixSupport posixSupport = context.getPosixSupport(); return posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(port, sockAddrLib.asInet4SockAddr(addr).getAddress())); } @@ -285,13 +286,13 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @Cached GilNode gil, @Cached PRaiseNode raiseNode) { PythonContext context = PythonContext.get(inliningTarget); - Object posixSupport = context.getPosixSupport(); + PosixSupport posixSupport = context.getPosixSupport(); try { if (name.length == 0) { gil.release(true); try { // TODO getaddrinfo lock? - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, null, posixLib.createCStringFromString(posixSupport, T_ZERO), + AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, null, posixSupport.createCStringFromString(T_ZERO), family, SOCK_DGRAM.value, 0, AI_PASSIVE.value); try { if (addrInfoLib.next(cursor)) { @@ -335,7 +336,7 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, gil.release(true); try { // TODO getaddrinfo lock? - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixLib.createCStringFromBytes(posixSupport, name), null, + AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixSupport.createCStringFromBytes(name), null, family, 0, 0, 0); try { return addrInfoLib.getSockAddr(cursor); @@ -356,11 +357,11 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @GenerateCached(false) @ImportStatic(Arrays.class) abstract static class InetPtoNCachedPNode extends Node { - abstract byte[] execute(Node inliningTarget, PosixSupportLibrary posixLib, Object posixSupport, int family, byte[] string); + abstract byte[] execute(Node inliningTarget, PosixSupportLibrary posixLib, PosixSupport posixSupport, int family, byte[] string); @Specialization(guards = {"family == cachedFamily", "equals(string, cachedString)"}, limit = "3") @SuppressWarnings("unused") - static byte[] cached(PosixSupportLibrary posixLib, Object posixSupport, int family, byte[] string, + static byte[] cached(PosixSupportLibrary posixLib, PosixSupport posixSupport, int family, byte[] string, @Cached("family") int cachedFamily, @Cached(value = "string", dimensions = 1) byte[] cachedString, @Cached(value = "doParse(posixLib, posixSupport, family, string)", dimensions = 1) byte[] cachedResult) { @@ -368,10 +369,10 @@ static byte[] cached(PosixSupportLibrary posixLib, Object posixSupport, int fami } @Specialization(replaces = "cached") - static byte[] doParse(PosixSupportLibrary posixLib, Object posixSupport, int family, byte[] string) { + static byte[] doParse(PosixSupportLibrary posixLib, PosixSupport posixSupport, int family, byte[] string) { assert family == AF_INET.value || family == AF_INET6.value; try { - return posixLib.inet_pton(posixSupport, family, posixLib.createCStringFromBytes(posixSupport, string)); + return posixLib.inet_pton(posixSupport, family, posixSupport.createCStringFromBytes(string)); } catch (PosixException | InvalidAddressException e) { return null; } @@ -412,13 +413,13 @@ static Object makeSockAddr(VirtualFrame frame, Node inliningTarget, UniversalSoc int family = addrLib.getFamily(addr); if (family == AF_INET.value) { Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - TruffleString addressString = posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); + PosixSupport posixSupport = context.getPosixSupport(); + TruffleString addressString = posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); return PFactory.createTuple(language, new Object[]{addressString, inet4SockAddr.getPort()}); } else if (family == AF_INET6.value) { Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - TruffleString addressString = posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); + PosixSupport posixSupport = context.getPosixSupport(); + TruffleString addressString = posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); return PFactory.createTuple(language, new Object[]{addressString, inet6SockAddr.getPort(), inet6SockAddr.getFlowInfo(), inet6SockAddr.getScopeId()}); } else if (family == AF_UNIX.value) { UnixSockAddr unixSockAddr = addrLib.asUnixSockAddr(addr); @@ -469,12 +470,12 @@ static Object makeAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAdd int family = addrLib.getFamily(addr); if (family == AF_INET.value) { Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - return posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); + PosixSupport posixSupport = context.getPosixSupport(); + return posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); } else if (family == AF_INET6.value) { Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - return posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); + PosixSupport posixSupport = context.getPosixSupport(); + return posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); } else { throw raiseNode.raise(inliningTarget, NotImplementedError, toTruffleStringUncached("makesockaddr: unknown address family")); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 0e408c826f..200773a2ca 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -4469,30 +4469,32 @@ public Buffer getPathAsBytes(Object path) { return Buffer.wrap(utf8StringToBytes((String) path)); } - @ExportMessage - public Object createCStringFromString(TruffleString string, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) { - return checkEmbeddedNulls(toJavaStringNode.execute(string)); + @Override + @TruffleBoundary + public Object createCStringFromString(TruffleString string) { + return checkEmbeddedNulls(TruffleString.ToJavaStringNode.getUncached().execute(string)); } - @ExportMessage + @Override + @TruffleBoundary public Object createCStringFromBytes(byte[] bytes) { return checkEmbeddedNulls(createUTF8String(bytes)); } - @ExportMessage - public Object createWideStringFromString(TruffleString string, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) { - return checkEmbeddedNulls(toJavaStringNode.execute(string)); + @Override + @TruffleBoundary + public Object createWideStringFromString(TruffleString string) { + return checkEmbeddedNulls(TruffleString.ToJavaStringNode.getUncached().execute(string)); } - @ExportMessage - public TruffleString getCStringAsString(Object string, - @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { - return fromJavaStringNode.execute((String) string, TS_ENCODING); + @Override + @TruffleBoundary + public TruffleString getCStringAsString(Object string) { + return TruffleString.FromJavaStringNode.getUncached().execute((String) string, TS_ENCODING); } - @ExportMessage + @Override + @TruffleBoundary public Buffer getCStringAsBytes(Object string) { return Buffer.wrap(utf8StringToBytes((String) string)); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 6b98f7b0bf..c05f540dd9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1698,34 +1698,34 @@ public final Buffer getPathAsBytes(Object path) { return logExit(Level.FINEST, "getPathAsBytes", "%s", delegate.getPathAsBytes(path)); } - @ExportMessage - final Object createCStringFromString(TruffleString string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.createCStringFromString(delegate, string); + @Override + @TruffleBoundary + public final Object createCStringFromString(TruffleString string) { + return delegate.createCStringFromString(string); } - @ExportMessage - final Object createCStringFromBytes(byte[] bytes, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.createCStringFromBytes(delegate, bytes); + @Override + @TruffleBoundary + public final Object createCStringFromBytes(byte[] bytes) { + return delegate.createCStringFromBytes(bytes); } - @ExportMessage - final Object createWideStringFromString(TruffleString string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.createWideStringFromString(delegate, string); + @Override + @TruffleBoundary + public final Object createWideStringFromString(TruffleString string) { + return delegate.createWideStringFromString(string); } - @ExportMessage - final TruffleString getCStringAsString(Object string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.getCStringAsString(delegate, string); + @Override + @TruffleBoundary + public final TruffleString getCStringAsString(Object string) { + return delegate.getCStringAsString(string); } - @ExportMessage - final Buffer getCStringAsBytes(Object string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.getCStringAsBytes(delegate, string); + @Override + @TruffleBoundary + public final Buffer getCStringAsBytes(Object string) { + return delegate.getCStringAsBytes(string); } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 9e01f1f080..36bfe3f17e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -3518,33 +3518,32 @@ private static TranscodingErrorHandler windowsPathDecodeErrorHandler(Node inlini }; } - @ExportMessage - public Object createCStringFromString(TruffleString string, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.IsValidNode isValidNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - return checkCString(getUTF8StringBytes(inliningTarget, string, switchEncodingNode, isValidNode, copyToByteArrayNode)); + @Override + @TruffleBoundary + public Object createCStringFromString(TruffleString string) { + return checkCString(getUTF8StringBytes(null, string, TruffleString.SwitchEncodingNode.getUncached(), TruffleString.IsValidNode.getUncached(), + TruffleString.CopyToByteArrayNode.getUncached())); } - @ExportMessage + @Override + @TruffleBoundary public Object createCStringFromBytes(byte[] bytes) { return checkCString(bytes); } - @ExportMessage - public Object createWideStringFromString(TruffleString string, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - TruffleString utf16 = switchEncodingNode.execute(string, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - byte[] bytes = copyToByteArrayNode.execute(utf16, UTF_16LE); + @Override + @TruffleBoundary + public Object createWideStringFromString(TruffleString string) { + TruffleString utf16 = TruffleString.SwitchEncodingNode.getUncached().execute(string, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + byte[] bytes = TruffleString.CopyToByteArrayNode.getUncached().execute(utf16, UTF_16LE); return checkWideString(bytes); } - @ExportMessage - public TruffleString getCStringAsString(Object string, - @Exclusive @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { + @Override + @TruffleBoundary + public TruffleString getCStringAsString(Object string) { + TruffleString.FromByteArrayNode fromByteArrayNode = TruffleString.FromByteArrayNode.getUncached(); + TruffleString.SwitchEncodingNode switchEncodingNode = TruffleString.SwitchEncodingNode.getUncached(); if (string instanceof WideString wideString) { TruffleString utf16 = fromByteArrayNode.execute(wideString.data, UTF_16LE, true); return switchEncodingNode.execute(utf16, TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); @@ -3553,7 +3552,8 @@ public TruffleString getCStringAsString(Object string, return createString(buffer.data, 0, (int) buffer.length, true, fromByteArrayNode, switchEncodingNode); } - @ExportMessage + @Override + @TruffleBoundary public Buffer getCStringAsBytes(Object string) { if (string instanceof WideString wideString) { TruffleString utf16 = TruffleString.fromByteArrayUncached(wideString.data, UTF_16LE); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 0a666f4ba5..364282e959 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -127,6 +127,19 @@ public final long semOpen(Object name) throws PosixException { public abstract Buffer getPathAsBytes(Object path); + /** Converts a string to strict UTF-8 for non-filesystem APIs that use CPython's {@code s} conversion. */ + public abstract Object createCStringFromString(TruffleString string); + + /** Wraps already-encoded bytes for narrow native APIs without applying a filesystem conversion. */ + public abstract Object createCStringFromBytes(byte[] bytes); + + /** Converts a string to the UTF-16 representation used by Windows wide-character APIs. */ + public abstract Object createWideStringFromString(TruffleString string); + + public abstract TruffleString getCStringAsString(Object string); + + public abstract Buffer getCStringAsBytes(Object string); + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 8b8863ae00..de90b8e83e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -139,19 +139,6 @@ public String toString() { } } - /** Converts a string to strict UTF-8 for non-filesystem APIs that use CPython's {@code s} conversion. */ - public abstract Object createCStringFromString(Object receiver, TruffleString string); - - /** Wraps already-encoded bytes for narrow native APIs without applying a filesystem conversion. */ - public abstract Object createCStringFromBytes(Object receiver, byte[] bytes); - - /** Converts a string to the UTF-16 representation used by Windows wide-character APIs. */ - public abstract Object createWideStringFromString(Object receiver, TruffleString string); - - public abstract TruffleString getCStringAsString(Object receiver, Object string); - - public abstract Buffer getCStringAsBytes(Object receiver, Object string); - // region Socket addresses /** diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 56e90862f1..8426cc8d3e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -1243,48 +1243,48 @@ public final Buffer getPathAsBytes(Object path) { return nativePosixSupport.getPathAsBytes(path); } - @ExportMessage - final Object createCStringFromString(TruffleString string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Object createCStringFromString(TruffleString string) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createCStringFromString(emulatedPosixSupport, string); + return emulatedPosixSupport.createCStringFromString(string); } - return nativeLib.createCStringFromString(nativePosixSupport, string); + return nativePosixSupport.createCStringFromString(string); } - @ExportMessage - final Object createCStringFromBytes(byte[] bytes, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Object createCStringFromBytes(byte[] bytes) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createCStringFromBytes(emulatedPosixSupport, bytes); + return emulatedPosixSupport.createCStringFromBytes(bytes); } - return nativeLib.createCStringFromBytes(nativePosixSupport, bytes); + return nativePosixSupport.createCStringFromBytes(bytes); } - @ExportMessage - final Object createWideStringFromString(TruffleString string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Object createWideStringFromString(TruffleString string) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createWideStringFromString(emulatedPosixSupport, string); + return emulatedPosixSupport.createWideStringFromString(string); } - return nativeLib.createWideStringFromString(nativePosixSupport, string); + return nativePosixSupport.createWideStringFromString(string); } - @ExportMessage - final TruffleString getCStringAsString(Object string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final TruffleString getCStringAsString(Object string) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getCStringAsString(emulatedPosixSupport, string); + return emulatedPosixSupport.getCStringAsString(string); } - return nativeLib.getCStringAsString(nativePosixSupport, string); + return nativePosixSupport.getCStringAsString(string); } - @ExportMessage - final Buffer getCStringAsBytes(Object string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Buffer getCStringAsBytes(Object string) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getCStringAsBytes(emulatedPosixSupport, string); + return emulatedPosixSupport.getCStringAsBytes(string); } - return nativeLib.getCStringAsBytes(nativePosixSupport, string); + return nativePosixSupport.getCStringAsBytes(string); } } From 00609fd3256c20f32eb5259b49a56105735a6c63 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 19:20:17 +0200 Subject: [PATCH 054/129] Convert PosixSupportLibrary socket lifecycle and addresses (cherry picked from commit 8bd2dcbcb36309d4c080f88a49e60c8727f86315) --- .../objects/socket/SocketBuiltins.java | 17 +++--- .../python/runtime/EmulatedPosixSupport.java | 15 ++--- .../python/runtime/LoggingPosixSupport.java | 56 +++++++++---------- .../python/runtime/NativePosixSupport.java | 21 ++++--- .../graal/python/runtime/PosixSupport.java | 16 ++++++ .../python/runtime/PosixSupportLibrary.java | 14 ----- .../python/runtime/PreInitPosixSupport.java | 56 +++++++++---------- 7 files changed, 102 insertions(+), 93 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index 3088eaed71..5f70af70fb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -196,7 +196,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i int fd; gil.release(true); try { - fd = posixLib.socket(context.getPosixSupport(), family, type, proto); + fd = context.getPosixSupport().socket(family, type, proto); } finally { gil.acquire(); } @@ -238,7 +238,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i } int family = familyIn; try { - UniversalSockAddr addr = posixLib.getsockname(context.getPosixSupport(), fd); + UniversalSockAddr addr = context.getPosixSupport().getsockname(fd); if (family == -1) { family = addrLib.getFamily(addr); } @@ -322,7 +322,7 @@ static Object accept(VirtualFrame frame, PSocket self, try { PosixSupport posixSupport = context.getPosixSupport(); PosixSupportLibrary.AcceptResult acceptResult = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, self, - (p, s) -> p.accept(s, self.getFd()), + (p, s) -> s.accept(self.getFd()), false, false); try { Object pythonAddr = makeSockAddrNode.execute(frame, inliningTarget, acceptResult.sockAddr); @@ -352,7 +352,6 @@ abstract static class BindNode extends PythonBinaryBuiltinNode { static Object bind(VirtualFrame frame, PSocket self, Object address, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLibrary, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @@ -363,7 +362,7 @@ static Object bind(VirtualFrame frame, PSocket self, Object address, try { gil.release(true); try { - posixLibrary.bind(context.getPosixSupport(), self.getFd(), addr); + context.getPosixSupport().bind(self.getFd(), addr); } finally { gil.acquire(); } @@ -435,7 +434,7 @@ static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.L try { gil.release(true); try { - posixLib.connect(posixSupport, self.getFd(), connectAddr); + posixSupport.connect(self.getFd(), connectAddr); } finally { gil.acquire(); } @@ -511,7 +510,7 @@ static Object get(VirtualFrame frame, PSocket socket, UniversalSockAddr addr; gil.release(true); try { - addr = posixLib.getpeername(context.getPosixSupport(), socket.getFd()); + addr = context.getPosixSupport().getpeername(socket.getFd()); } finally { gil.acquire(); } @@ -538,7 +537,7 @@ static Object get(VirtualFrame frame, PSocket socket, UniversalSockAddr addr; gil.release(true); try { - addr = posixLib.getsockname(context.getPosixSupport(), socket.getFd()); + addr = context.getPosixSupport().getsockname(socket.getFd()); } finally { gil.acquire(); } @@ -592,7 +591,7 @@ static Object listen(VirtualFrame frame, PSocket self, int backlogIn, try { gil.release(true); try { - posixLib.listen(context.getPosixSupport(), self.getFd(), backlog); + context.getPosixSupport().listen(self.getFd(), backlog); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 200773a2ca..526bff41bd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -3126,7 +3126,8 @@ public int ioctlInt(int fd, long request, int arg) throws PosixException { throw createUnsupportedFeature("ioctl"); } - @ExportMessage + @Override + @TruffleBoundary public int socket(int domain, int type, int protocol) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { throw new UnsupportedPosixFeatureException("socket was excluded"); @@ -3150,7 +3151,7 @@ public int socket(int domain, int type, int protocol) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public AcceptResult accept(int sockfd) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3177,7 +3178,7 @@ public AcceptResult accept(int sockfd) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public void bind(int sockfd, UniversalSockAddr addr) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3195,7 +3196,7 @@ public void bind(int sockfd, UniversalSockAddr addr) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public void connect(int sockfd, UniversalSockAddr addr) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3213,7 +3214,7 @@ public void connect(int sockfd, UniversalSockAddr addr) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public void listen(int sockfd, int backlog) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3227,7 +3228,7 @@ public void listen(int sockfd, int backlog) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public UniversalSockAddr getpeername(int sockfd) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3245,7 +3246,7 @@ public UniversalSockAddr getpeername(int sockfd) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public UniversalSockAddr getsockname(int sockfd) throws PosixException { EmulatedSocket socket = getEmulatedSocket(sockfd); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index c05f540dd9..538bbc82e6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1294,78 +1294,78 @@ public final int system(Object command) { return logExit("system", "%d", delegate.system(command)); } - @ExportMessage - final int socket(int domain, int type, int protocol, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int socket(int domain, int type, int protocol) throws PosixException { logEnter("socket", "%d, %d, %d", domain, type, protocol); try { - return logExit("socket", "%d", lib.socket(delegate, domain, type, protocol)); + return logExit("socket", "%d", delegate.socket(domain, type, protocol)); } catch (PosixException e) { throw logException("socket", e); } } - @ExportMessage - final AcceptResult accept(int sockfd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final AcceptResult accept(int sockfd) throws PosixException { logEnter("accept", "%d", sockfd); try { - return logExit("accept", "%s", lib.accept(delegate, sockfd)); + return logExit("accept", "%s", delegate.accept(sockfd)); } catch (PosixException e) { throw logException("accept", e); } } - @ExportMessage - final void bind(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void bind(int sockfd, UniversalSockAddr addr) throws PosixException { logEnter("bind", "%d, %s", sockfd, addr); try { - lib.bind(delegate, sockfd, addr); + delegate.bind(sockfd, addr); } catch (PosixException e) { throw logException("bind", e); } } - @ExportMessage - final void connect(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void connect(int sockfd, UniversalSockAddr addr) throws PosixException { logEnter("connect", "%d, %s", sockfd, addr); try { - lib.connect(delegate, sockfd, addr); + delegate.connect(sockfd, addr); } catch (PosixException e) { throw logException("connect", e); } } - @ExportMessage - final void listen(int sockfd, int backlog, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void listen(int sockfd, int backlog) throws PosixException { logEnter("listen", "%d, %d", sockfd, backlog); try { - lib.listen(delegate, sockfd, backlog); + delegate.listen(sockfd, backlog); } catch (PosixException e) { throw logException("listen", e); } } - @ExportMessage - final UniversalSockAddr getpeername(int sockfd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getpeername(int sockfd) throws PosixException { logEnter("getpeername", "%d", sockfd); try { - return logExit("getpeername", "%s", lib.getpeername(delegate, sockfd)); + return logExit("getpeername", "%s", delegate.getpeername(sockfd)); } catch (PosixException e) { throw logException("getpeername", e); } } - @ExportMessage - final UniversalSockAddr getsockname(int sockfd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getsockname(int sockfd) throws PosixException { logEnter("getsockname", "%d", sockfd); try { - return logExit("getsockname", "%s", lib.getsockname(delegate, sockfd)); + return logExit("getsockname", "%s", delegate.getsockname(sockfd)); } catch (PosixException e) { throw logException("getsockname", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 36bfe3f17e..42ad016737 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -2349,7 +2349,8 @@ private static void checkIndexAndLen(MMapHandle handle, long index, long length) } } - @ExportMessage + @Override + @TruffleBoundary public int socket(int domain, int type, int protocol) throws PosixException { int result = posixNativeFunctionInvoker.call_socket(domain, type, protocol); if (result == -1) { @@ -2358,7 +2359,8 @@ public int socket(int domain, int type, int protocol) throws PosixException { return result; } - @ExportMessage + @Override + @TruffleBoundary public AcceptResult accept(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); long nativeAddr = NULLPTR; @@ -2378,7 +2380,8 @@ public AcceptResult accept(int sockfd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void bind(int sockfd, UniversalSockAddr usa) throws PosixException { UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; int addrLen = addr.getLen(); @@ -2394,7 +2397,8 @@ public void bind(int sockfd, UniversalSockAddr usa) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void connect(int sockfd, UniversalSockAddr usa) throws PosixException { UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; int addrLen = addr.getLen(); @@ -2410,7 +2414,8 @@ public void connect(int sockfd, UniversalSockAddr usa) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void listen(int sockfd, int backlog) throws PosixException { int result = posixNativeFunctionInvoker.call_listen(sockfd, backlog); if (result == -1) { @@ -2418,7 +2423,8 @@ public void listen(int sockfd, int backlog) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public UniversalSockAddr getpeername(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); long nativeAddr = NULLPTR; @@ -2438,7 +2444,8 @@ public UniversalSockAddr getpeername(int sockfd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public UniversalSockAddr getsockname(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); long nativeAddr = NULLPTR; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 364282e959..b117d641c1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -40,6 +40,7 @@ */ package com.oracle.graal.python.runtime; +import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; @@ -48,6 +49,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -140,6 +142,20 @@ public final long semOpen(Object name) throws PosixException { public abstract Buffer getCStringAsBytes(Object string); + public abstract int socket(int domain, int type, int protocol) throws PosixException; + + public abstract AcceptResult accept(int sockfd) throws PosixException; + + public abstract void bind(int sockfd, UniversalSockAddr addr) throws PosixException; + + public abstract void connect(int sockfd, UniversalSockAddr addr) throws PosixException; + + public abstract void listen(int sockfd, int backlog) throws PosixException; + + public abstract UniversalSockAddr getpeername(int sockfd) throws PosixException; + + public abstract UniversalSockAddr getsockname(int sockfd) throws PosixException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index de90b8e83e..9114ccc176 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -306,20 +306,6 @@ public byte[] getPath() { * @see "socket(2) man pages" * @see PosixConstants */ - public abstract int socket(Object receiver, int domain, int type, int protocol) throws PosixException; - - public abstract AcceptResult accept(Object receiver, int sockfd) throws PosixException; - - public abstract void bind(Object receiver, int sockfd, UniversalSockAddr addr) throws PosixException; - - public abstract void connect(Object receiver, int sockfd, UniversalSockAddr addr) throws PosixException; - - public abstract void listen(Object receiver, int sockfd, int backlog) throws PosixException; - - public abstract UniversalSockAddr getpeername(Object receiver, int sockfd) throws PosixException; - - public abstract UniversalSockAddr getsockname(Object receiver, int sockfd) throws PosixException; - public abstract int send(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; // Unlike POSIX sendto(), we don't support destAddr == null. Use plain send instead. diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 8426cc8d3e..f2aaac1bb1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -963,53 +963,53 @@ final int ioctlInt(int fd, long request, int arg, return nativeLib.ioctlInt(nativePosixSupport, fd, request, arg); } - @ExportMessage - final int socket(int domain, int type, int protocol, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int socket(int domain, int type, int protocol) throws PosixException { checkNotInPreInitialization(); - return nativeLib.socket(nativePosixSupport, domain, type, protocol); + return nativePosixSupport.socket(domain, type, protocol); } - @ExportMessage - final AcceptResult accept(int sockfd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final AcceptResult accept(int sockfd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.accept(nativePosixSupport, sockfd); + return nativePosixSupport.accept(sockfd); } - @ExportMessage - final void bind(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void bind(int sockfd, UniversalSockAddr addr) throws PosixException { checkNotInPreInitialization(); - nativeLib.bind(nativePosixSupport, sockfd, addr); + nativePosixSupport.bind(sockfd, addr); } - @ExportMessage - final void connect(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void connect(int sockfd, UniversalSockAddr addr) throws PosixException { checkNotInPreInitialization(); - nativeLib.connect(nativePosixSupport, sockfd, addr); + nativePosixSupport.connect(sockfd, addr); } - @ExportMessage - final void listen(int sockfd, int backlog, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void listen(int sockfd, int backlog) throws PosixException { checkNotInPreInitialization(); - nativeLib.listen(nativePosixSupport, sockfd, backlog); + nativePosixSupport.listen(sockfd, backlog); } - @ExportMessage - final UniversalSockAddr getpeername(int sockfd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getpeername(int sockfd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpeername(nativePosixSupport, sockfd); + return nativePosixSupport.getpeername(sockfd); } - @ExportMessage - final UniversalSockAddr getsockname(int sockfd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getsockname(int sockfd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getsockname(nativePosixSupport, sockfd); + return nativePosixSupport.getsockname(sockfd); } @ExportMessage From 165106493656418e04f9ee7bbc8a453dd1a79060 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 19:28:36 +0200 Subject: [PATCH 055/129] Convert PosixSupportLibrary socket data and options (cherry picked from commit 2af6d4f45425496167669d3ca0f8d37f1784a02d) --- .../MultiprocessingModuleBuiltins.java | 4 +- .../objects/socket/SocketBuiltins.java | 62 +++++++++---------- .../builtins/objects/socket/SocketUtils.java | 15 ++--- .../objects/ssl/SSLOperationNode.java | 8 +-- .../python/runtime/EmulatedPosixSupport.java | 14 ++--- .../python/runtime/LoggingPosixSupport.java | 56 ++++++++--------- .../python/runtime/NativePosixSupport.java | 21 ++++--- .../graal/python/runtime/PosixSupport.java | 17 +++++ .../python/runtime/PosixSupportLibrary.java | 32 ---------- .../python/runtime/PreInitPosixSupport.java | 56 ++++++++--------- 10 files changed, 136 insertions(+), 149 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java index 64bd8411e9..f7b3550d6f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java @@ -94,7 +94,7 @@ PBytes doit(VirtualFrame frame, int handle, int size, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] buffer = new byte[size]; try { - int received = posixLib.recv(context.getPosixSupport(), handle, buffer, 0, size, 0); + int received = context.getPosixSupport().recv(handle, buffer, 0, size, 0); if (received == size) { return PFactory.createBytes(language, buffer); } @@ -127,7 +127,7 @@ static int doit(VirtualFrame frame, int handle, Object buffer, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); - return posixLib.send(context.getPosixSupport(), handle, bytes, 0, bufferLib.getBufferLength(buffer), 0); + return context.getPosixSupport().send(handle, bytes, 0, bufferLib.getBufferLength(buffer), 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } finally { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index 5f70af70fb..08fe982f1c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -202,7 +202,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i } try { context.getPosixSupport().setInheritable(fd, false); - sockInit(context, posixLib, self, fd, family, type, proto); + sockInit(context, self, fd, family, type, proto); } catch (Exception e) { // If we failed before giving the fd to python-land, close it CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -250,24 +250,24 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i try { int type = typeIn; if (type == -1) { - type = getIntSockopt(context.getPosixSupport(), posixLib, fd, SOL_SOCKET.value, SO_TYPE.value); + type = getIntSockopt(context.getPosixSupport(), fd, SOL_SOCKET.value, SO_TYPE.value); } int proto = protoIn; if (SO_PROTOCOL.defined) { if (proto == -1) { - proto = getIntSockopt(context.getPosixSupport(), posixLib, fd, SOL_SOCKET.value, SO_PROTOCOL.getValueIfDefined()); + proto = getIntSockopt(context.getPosixSupport(), fd, SOL_SOCKET.value, SO_PROTOCOL.getValueIfDefined()); } } else { proto = 0; } - sockInit(context, posixLib, self, fd, family, type, proto); + sockInit(context, self, fd, family, type, proto); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } return PNone.NONE; } - private static void sockInit(PythonContext context, PosixSupportLibrary posixLib, + private static void sockInit(PythonContext context, PSocket self, int fd, int family, int type, int proto) throws PosixException { self.setFd(fd); self.setFamily(family); @@ -281,9 +281,9 @@ private static void sockInit(PythonContext context, PosixSupportLibrary posixLib } } - private static int getIntSockopt(PosixSupport posixSupport, PosixSupportLibrary posixLib, int fd, int level, int option) throws PosixException { + private static int getIntSockopt(PosixSupport posixSupport, int fd, int level, int option) throws PosixException { byte[] tmp = new byte[4]; - int len = posixLib.getsockopt(posixSupport, fd, level, option, tmp, tmp.length); + int len = posixSupport.getsockopt(fd, level, option, tmp, tmp.length); assert len == tmp.length; return PythonUtils.ARRAY_ACCESSOR.getInt(tmp, 0); } @@ -321,8 +321,8 @@ static Object accept(VirtualFrame frame, PSocket self, try { PosixSupport posixSupport = context.getPosixSupport(); - PosixSupportLibrary.AcceptResult acceptResult = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, self, - (p, s) -> s.accept(self.getFd()), + PosixSupportLibrary.AcceptResult acceptResult = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, self, + s -> s.accept(self.getFd()), false, false); try { Object pythonAddr = makeSockAddrNode.execute(frame, inliningTarget, acceptResult.sockAddr); @@ -447,10 +447,10 @@ static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.L waitConnect = self.getTimeoutNs() > 0 && e.hasErrno(EINPROGRESS) && isSelectable(self); } if (waitConnect) { - SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, self, - (p, s) -> { + SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, self, + s -> { byte[] tmp = new byte[4]; - p.getsockopt(s, self.getFd(), SOL_SOCKET.value, SO_ERROR.value, tmp, tmp.length); + s.getsockopt(self.getFd(), SOL_SOCKET.value, SO_ERROR.value, tmp, tmp.length); int err = PythonUtils.ARRAY_ACCESSOR.getInt(tmp, 0); if (err != 0 && err != EISCONN.getNumber()) { throw new PosixErrnoException(err, s.strerror(err)); @@ -638,8 +638,8 @@ static Object recv(VirtualFrame frame, PSocket socket, int recvlen, int flags, } try { - int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recv(s, socket.getFd(), bytes, 0, bytes.length, flags), + int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recv(socket.getFd(), bytes, 0, bytes.length, flags), false, false); if (outlen == 0) { return PFactory.createEmptyBytes(language); @@ -685,8 +685,8 @@ static Object recvFrom(VirtualFrame frame, PSocket socket, int recvlen, int flag } try { - RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recvfrom(s, socket.getFd(), bytes, 0, bytes.length, flags), + RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recvfrom(socket.getFd(), bytes, 0, bytes.length, flags), false, false); PBytes resultBytes; PythonLanguage language = context.getLanguage(inliningTarget); @@ -755,8 +755,8 @@ static Object recvInto(VirtualFrame frame, PSocket socket, Object bufferObj, int final int len = recvlen; try { - int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recv(s, socket.getFd(), bytes, 0, len, flags), + int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recv(socket.getFd(), bytes, 0, len, flags), false, false); if (!directWrite) { bufferLib.writeFromByteArray(buffer, 0, bytes, 0, outlen); @@ -823,8 +823,8 @@ static Object recvFromInto(VirtualFrame frame, PSocket socket, Object bufferObj, } try { - RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recvfrom(s, socket.getFd(), bytes, 0, bytes.length, flags), + RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recvfrom(socket.getFd(), bytes, 0, bytes.length, flags), false, false); if (!directWrite) { bufferLib.writeFromByteArray(buffer, 0, bytes, 0, result.readBytes); @@ -868,8 +868,8 @@ static int send(VirtualFrame frame, PSocket socket, Object bufferObj, int flags, byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); try { - return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.send(s, socket.getFd(), bytes, 0, len, flags), + return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.send(socket.getFd(), bytes, 0, len, flags), true, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -919,8 +919,8 @@ static Object sendAll(VirtualFrame frame, PSocket socket, Object bufferObj, int try { final int offset1 = offset; final int len1 = len; - int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.send(s, socket.getFd(), bytes, offset1, len1, flags), + int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.send(socket.getFd(), bytes, offset1, len1, flags), true, false, timeoutHelper); offset += outlen; len -= outlen; @@ -985,8 +985,8 @@ static Object sendTo(VirtualFrame frame, PSocket socket, Object bufferObj, Objec byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); try { - return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.sendto(s, socket.getFd(), bytes, 0, len, flags, addr), + return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.sendto(socket.getFd(), bytes, 0, len, flags, addr), true, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -1054,7 +1054,7 @@ static Object shutdown(VirtualFrame frame, PSocket socket, int how, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.shutdown(context.getPosixSupport(), socket.getFd(), how); + context.getPosixSupport().shutdown(socket.getFd(), how); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1152,7 +1152,7 @@ static Object setInt(VirtualFrame frame, PSocket socket, int level, int option, } try { - posixLib.setsockopt(context.getPosixSupport(), socket.getFd(), level, option, bytes, len); + context.getPosixSupport().setsockopt(socket.getFd(), level, option, bytes, len); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1173,7 +1173,7 @@ static Object setNull(VirtualFrame frame, PSocket socket, int level, int option, throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SETSECKOPT_BUFF_OUT_OFRANGE); } try { - posixLib.setsockopt(context.getPosixSupport(), socket.getFd(), level, option, null, buflen); + context.getPosixSupport().setsockopt(socket.getFd(), level, option, null, buflen); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1209,11 +1209,11 @@ static Object getSockOpt(VirtualFrame frame, PSocket socket, int level, int opti try { if (buflen == 0) { byte[] result = new byte[4]; - posixLib.getsockopt(context.getPosixSupport(), socket.getFd(), level, option, result, result.length); + context.getPosixSupport().getsockopt(socket.getFd(), level, option, result, result.length); return PythonUtils.ARRAY_ACCESSOR.getInt(result, 0); } else if (buflen > 0 && buflen < 1024) { byte[] result = new byte[buflen]; - int len = posixLib.getsockopt(context.getPosixSupport(), socket.getFd(), level, option, result, result.length); + int len = context.getPosixSupport().getsockopt(socket.getFd(), level, option, result, result.length); return PFactory.createBytes(context.getLanguage(inliningTarget), result, len); } else { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.GETSECKOPT_BUFF_OUT_OFRANGE); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java index 0785aedb90..d26dc88a35 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java @@ -51,7 +51,6 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; @@ -64,27 +63,23 @@ public class SocketUtils { @FunctionalInterface public interface SocketFunction { - /* - * NB: The library and support need to be passed as arguments and shouldn't be taken from - * the closure. Otherwise, Truffle has trouble inlining the library call. - */ - T run(PosixSupportLibrary posixLib, PosixSupport posixSupport) throws PosixException; + T run(PosixSupport posixSupport) throws PosixException; } /** * Rough equivalent of CPython's {@code sock_call}. Takes care of calling select for connections * with timeouts and retrying the call on EINTR. Must be called with GIL held. */ - public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, PosixSupport posixSupport, GilNode gil, + public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupport posixSupport, GilNode gil, PSocket socket, SocketFunction function, boolean writing, boolean connect) throws PosixException { - return callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, socket, function, writing, connect, null); + return callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, socket, function, writing, connect, null); } /** * Rough equivalent of CPython's {@code sock_call_ex}. Takes care of calling select for * connections with timeouts and retrying the call on EINTR. Must be called with GIL held. */ - public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, PosixSupport posixSupport, GilNode gil, + public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupport posixSupport, GilNode gil, PSocket socket, SocketFunction function, boolean writing, boolean connect, TimeoutHelper timeoutHelperIn) throws PosixException { TimeoutHelper timeoutHelper = timeoutHelperIn; if (timeoutHelper == null && socket.getTimeoutNs() > 0) { @@ -142,7 +137,7 @@ public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget try { gil.release(true); try { - return function.run(posixLib, posixSupport); + return function.run(posixSupport); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java index 82bd4f07c2..722bbca2b5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java @@ -222,8 +222,8 @@ static void doSocket(VirtualFrame frame, Node inliningTarget, PSSLSocket socket, byte[] bytes1 = networkInboundBIO.getInternalBytes(); int offset1 = networkInboundBIO.getWritePosition(); try { - int recvlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket.getSocket(), - (p, s) -> p.recv(s, socket.getSocket().getFd(), bytes1, offset1, len1, 0), + int recvlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket.getSocket(), + s -> s.recv(socket.getSocket().getFd(), bytes1, offset1, len1, 0), true, false, timeoutHelper); if (recvlen == 0) { // This means EOF @@ -249,8 +249,8 @@ static void doSocket(VirtualFrame frame, Node inliningTarget, PSSLSocket socket, int offset2 = networkOutboundBIO.getReadPosition(); int len2 = networkOutboundBIO.getPending(); try { - int writtenBytes = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket.getSocket(), - (p, s) -> p.send(s, socket.getSocket().getFd(), bytes2, offset2, len2, 0), + int writtenBytes = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket.getSocket(), + s -> s.send(socket.getSocket().getFd(), bytes2, offset2, len2, 0), true, false, timeoutHelper); networkOutboundBIO.advanceReadPosition(writtenBytes); } catch (PosixException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 526bff41bd..317bd1b84d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -3265,7 +3265,7 @@ public UniversalSockAddr getsockname(int sockfd) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3280,7 +3280,7 @@ public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws P } } - @ExportMessage + @Override @TruffleBoundary public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3299,7 +3299,7 @@ public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, Univer } } - @ExportMessage + @Override @TruffleBoundary public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3314,7 +3314,7 @@ public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws P } } - @ExportMessage + @Override @TruffleBoundary public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3330,7 +3330,7 @@ public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int } } - @ExportMessage + @Override @TruffleBoundary public void shutdown(int sockfd, int how) throws PosixException { EmulatedSocket socket = getEmulatedSocket(sockfd); @@ -3341,7 +3341,7 @@ public void shutdown(int sockfd, int how) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3392,7 +3392,7 @@ private static ByteArraySupport nativeByteArraySupport() { return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? ByteArraySupport.littleEndian() : ByteArraySupport.bigEndian(); } - @ExportMessage + @Override @TruffleBoundary public void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 538bbc82e6..c7ab9f66e1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1371,78 +1371,78 @@ public final UniversalSockAddr getsockname(int sockfd) throws PosixException { } } - @ExportMessage - final int send(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { logEnter("send", "%d, %d, %d, %d", sockfd, offset, len, flags); try { - return logExit("send", "%d", lib.send(delegate, sockfd, buf, offset, len, flags)); + return logExit("send", "%d", delegate.send(sockfd, buf, offset, len, flags)); } catch (PosixException e) { throw logException("send", e); } } - @ExportMessage - final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException { logEnter("sendto", "%d, %d, %d, %d, %s", sockfd, offset, len, flags, destAddr); try { - return logExit("sendto", "%d", lib.sendto(delegate, sockfd, buf, offset, len, flags, destAddr)); + return logExit("sendto", "%d", delegate.sendto(sockfd, buf, offset, len, flags, destAddr)); } catch (PosixException e) { throw logException("sendto", e); } } - @ExportMessage - final int recv(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { logEnter("recv", "%d, %d, %d, %d", sockfd, offset, len, flags); try { - return logExit("recv", "%d", lib.recv(delegate, sockfd, buf, offset, len, flags)); + return logExit("recv", "%d", delegate.recv(sockfd, buf, offset, len, flags)); } catch (PosixException e) { throw logException("recv", e); } } - @ExportMessage - final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { logEnter("recvfrom", "%d, %d, %d, %d", sockfd, offset, len, flags); try { - return logExit("recvfrom", "%s", lib.recvfrom(delegate, sockfd, buf, offset, len, flags)); + return logExit("recvfrom", "%s", delegate.recvfrom(sockfd, buf, offset, len, flags)); } catch (PosixException e) { throw logException("recvfrom", e); } } - @ExportMessage - final void shutdown(int sockfd, int how, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void shutdown(int sockfd, int how) throws PosixException { logEnter("shutdown", "%d, %d", sockfd, how); try { - lib.shutdown(delegate, sockfd, how); + delegate.shutdown(sockfd, how); } catch (PosixException e) { throw logException("shutdown", e); } } - @ExportMessage - final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { logEnter("getsockopt", "%d, %d, %d, %s, %d", sockfd, level, optname, optval, optlen); try { - return logExit("getsockopt", "%d", lib.getsockopt(delegate, sockfd, level, optname, optval, optlen)); + return logExit("getsockopt", "%d", delegate.getsockopt(sockfd, level, optname, optval, optlen)); } catch (PosixException e) { throw logException("getsockopt", e); } } - @ExportMessage - final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { logEnter("setsockopt", "%d, %d, %d, %s, %d", sockfd, level, optname, optval, optlen); try { - lib.setsockopt(delegate, sockfd, level, optname, optval, optlen); + delegate.setsockopt(sockfd, level, optname, optval, optlen); } catch (PosixException e) { throw logException("setsockopt", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 42ad016737..53d312c39d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -2465,7 +2465,8 @@ public UniversalSockAddr getsockname(int sockfd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); long nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); @@ -2481,7 +2482,8 @@ public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws P } } - @ExportMessage + @Override + @TruffleBoundary public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr usa) throws PosixException { checkBounds(buf, offset, len); UniversalSockAddrImpl destAddr = (UniversalSockAddrImpl) usa; @@ -2504,7 +2506,8 @@ public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, Univer } } - @ExportMessage + @Override + @TruffleBoundary public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); long nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); @@ -2520,7 +2523,8 @@ public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws P } } - @ExportMessage + @Override + @TruffleBoundary public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); UniversalSockAddrImpl srcAddr = new UniversalSockAddrImpl(this); @@ -2545,7 +2549,8 @@ public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int } } - @ExportMessage + @Override + @TruffleBoundary public void shutdown(int sockfd, int how) throws PosixException { int res = posixNativeFunctionInvoker.call_shutdown(sockfd, how); if (res != 0) { @@ -2553,7 +2558,8 @@ public void shutdown(int sockfd, int how) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { assert optlen >= 0 && optval.length >= optlen; long nativeOptval = NULLPTR; @@ -2580,7 +2586,8 @@ public int getsockopt(int sockfd, int level, int optname, byte[] optval, int opt } } - @ExportMessage + @Override + @TruffleBoundary public void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { assert optlen >= 0 && optval.length >= optlen; long nativeOptval = NULLPTR; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index b117d641c1..467f0bdb1c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -45,6 +45,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; +import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; @@ -156,6 +157,22 @@ public final long semOpen(Object name) throws PosixException { public abstract UniversalSockAddr getsockname(int sockfd) throws PosixException; + public abstract int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; + + // Unlike POSIX sendto(), we don't support destAddr == null. Use plain send instead. + public abstract int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException; + + public abstract int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; + + // For STREAM sockets, the returned address will be AF_UNSPEC + public abstract RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; + + public abstract void shutdown(int sockfd, int how) throws PosixException; + + public abstract int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; + + public abstract void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 9114ccc176..3bc399d5a6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -298,24 +298,6 @@ public byte[] getPath() { // endregion - // region socket messages - - /** - * Creates a new socket. - * - * @see "socket(2) man pages" - * @see PosixConstants - */ - public abstract int send(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; - - // Unlike POSIX sendto(), we don't support destAddr == null. Use plain send instead. - public abstract int sendto(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException; - - public abstract int recv(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; - - // For STREAM sockets, the returned address will be AF_UNSPEC - public abstract RecvfromResult recvfrom(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; - public static final class AcceptResult { public final int socketFd; public final UniversalSockAddr sockAddr; @@ -348,20 +330,6 @@ public String toString() { } } - public abstract void shutdown(Object receiver, int sockfd, int how) throws PosixException; - - /** - * @param optval buffer for the option value - * @param optlen size of the buffer // TODO use optval.length instead? See also recv, - * mmapReadBytes, read and GR-29856 - * @return the actual size of the value returned - */ - public abstract int getsockopt(Object receiver, int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; - - public abstract void setsockopt(Object receiver, int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; - - // endregion - // region Name resolution messages /** diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index f2aaac1bb1..00dd3e1e12 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -1012,53 +1012,53 @@ public final UniversalSockAddr getsockname(int sockfd) throws PosixException { return nativePosixSupport.getsockname(sockfd); } - @ExportMessage - final int send(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.send(nativePosixSupport, sockfd, buf, offset, len, flags); + return nativePosixSupport.send(sockfd, buf, offset, len, flags); } - @ExportMessage - final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException { checkNotInPreInitialization(); - return nativeLib.sendto(nativePosixSupport, sockfd, buf, offset, len, flags, destAddr); + return nativePosixSupport.sendto(sockfd, buf, offset, len, flags, destAddr); } - @ExportMessage - final int recv(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.recv(nativePosixSupport, sockfd, buf, offset, len, flags); + return nativePosixSupport.recv(sockfd, buf, offset, len, flags); } - @ExportMessage - final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.recvfrom(nativePosixSupport, sockfd, buf, offset, len, flags); + return nativePosixSupport.recvfrom(sockfd, buf, offset, len, flags); } - @ExportMessage - final void shutdown(int sockfd, int how, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void shutdown(int sockfd, int how) throws PosixException { checkNotInPreInitialization(); - nativeLib.shutdown(nativePosixSupport, sockfd, how); + nativePosixSupport.shutdown(sockfd, how); } - @ExportMessage - final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getsockopt(nativePosixSupport, sockfd, level, optname, optval, optlen); + return nativePosixSupport.getsockopt(sockfd, level, optname, optval, optlen); } - @ExportMessage - final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { checkNotInPreInitialization(); - nativeLib.setsockopt(nativePosixSupport, sockfd, level, optname, optval, optlen); + nativePosixSupport.setsockopt(sockfd, level, optname, optval, optlen); } @ExportMessage From a13270d59e72f68f83da5ac79344e20470efb963 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 19:33:41 +0200 Subject: [PATCH 056/129] Convert PosixSupportLibrary numeric Internet addresses (cherry picked from commit a93890c8b7ca486dca79a2d65472d30b120c431a) --- .../modules/SocketModuleBuiltins.java | 12 +-- .../builtins/objects/socket/SocketNodes.java | 10 +-- .../python/runtime/EmulatedPosixSupport.java | 11 +-- .../python/runtime/LoggingPosixSupport.java | 40 +++++----- .../python/runtime/NativePosixSupport.java | 15 ++-- .../graal/python/runtime/PosixSupport.java | 11 +++ .../python/runtime/PosixSupportLibrary.java | 73 ------------------- .../python/runtime/PreInitPosixSupport.java | 40 +++++----- 8 files changed, 78 insertions(+), 134 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index 05ac586e71..b26819a308 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -351,7 +351,7 @@ static TruffleString getHostByName(VirtualFrame frame, Object nameObj, UniversalSockAddr addr = setIpAddrNode.execute(frame, name, AF_INET.value); Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); try { - return context.getPosixSupport().getCStringAsString(posixLib.inet_ntop(context.getPosixSupport(), AF_INET.value, inet4SockAddr.getAddressAsBytes())); + return context.getPosixSupport().getCStringAsString(context.getPosixSupport().inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -391,7 +391,7 @@ static Object get(VirtualFrame frame, Object nameObj, try { TruffleString canonName = posixSupport.getCStringAsString(addrInfoCursorLib.getCanonName(cursor)); Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addrInfoCursorLib.getSockAddr(cursor)); - TruffleString addr = posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, AF_INET.value, inet4SockAddr.getAddressAsBytes())); + TruffleString addr = posixSupport.getCStringAsString(posixSupport.inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); // getaddrinfo doesn't support aliases PList aliases = PFactory.createList(context.getLanguage(inliningTarget)); // we support just one address for now @@ -820,7 +820,7 @@ static PBytes doConvert(TruffleString addr, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - int converted = posixLib.inet_aton(posixSupport, posixSupport.createCStringFromString(addr)); + int converted = posixSupport.inet_aton(posixSupport.createCStringFromString(addr)); byte[] bytes = new byte[4]; ByteArraySupport.bigEndian().putInt(bytes, 0, converted); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); @@ -855,7 +855,7 @@ static TruffleString doGeneric(VirtualFrame frame, Object addr, throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.PACKED_IP_WRONG_LENGTH, "inet_ntoa"); } PosixSupport posixSupport = context.getPosixSupport(); - Object result = posixLib.inet_ntoa(posixSupport, ByteArraySupport.bigEndian().getInt(bytes, 0)); + Object result = posixSupport.inet_ntoa(ByteArraySupport.bigEndian().getInt(bytes, 0)); return posixSupport.getCStringAsString(result); } finally { bufferLib.release(buffer, frame, callData); @@ -877,7 +877,7 @@ static PBytes doConvert(VirtualFrame frame, int family, TruffleString addr, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - byte[] bytes = posixLib.inet_pton(posixSupport, family, posixSupport.createCStringFromString(addr)); + byte[] bytes = posixSupport.inet_pton(family, posixSupport.createCStringFromString(addr)); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -923,7 +923,7 @@ static TruffleString doGeneric(VirtualFrame frame, int family, Object obj, } try { PosixSupport posixSupport = context.getPosixSupport(); - Object result = posixLib.inet_ntop(posixSupport, family, bytes); + Object result = posixSupport.inet_ntop(family, bytes); return posixSupport.getCStringAsString(result); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index efcf853779..eb12c86071 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -372,7 +372,7 @@ static byte[] cached(PosixSupportLibrary posixLib, PosixSupport posixSupport, in static byte[] doParse(PosixSupportLibrary posixLib, PosixSupport posixSupport, int family, byte[] string) { assert family == AF_INET.value || family == AF_INET6.value; try { - return posixLib.inet_pton(posixSupport, family, posixSupport.createCStringFromBytes(string)); + return posixSupport.inet_pton(family, posixSupport.createCStringFromBytes(string)); } catch (PosixException | InvalidAddressException e) { return null; } @@ -414,12 +414,12 @@ static Object makeSockAddr(VirtualFrame frame, Node inliningTarget, UniversalSoc if (family == AF_INET.value) { Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); PosixSupport posixSupport = context.getPosixSupport(); - TruffleString addressString = posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); + TruffleString addressString = posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); return PFactory.createTuple(language, new Object[]{addressString, inet4SockAddr.getPort()}); } else if (family == AF_INET6.value) { Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); PosixSupport posixSupport = context.getPosixSupport(); - TruffleString addressString = posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); + TruffleString addressString = posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); return PFactory.createTuple(language, new Object[]{addressString, inet6SockAddr.getPort(), inet6SockAddr.getFlowInfo(), inet6SockAddr.getScopeId()}); } else if (family == AF_UNIX.value) { UnixSockAddr unixSockAddr = addrLib.asUnixSockAddr(addr); @@ -471,11 +471,11 @@ static Object makeAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAdd if (family == AF_INET.value) { Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); PosixSupport posixSupport = context.getPosixSupport(); - return posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); + return posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); } else if (family == AF_INET6.value) { Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); PosixSupport posixSupport = context.getPosixSupport(); - return posixSupport.getCStringAsString(posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); + return posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); } else { throw raiseNode.raise(inliningTarget, NotImplementedError, toTruffleStringUncached("makesockaddr: unknown address family")); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 317bd1b84d..fc78500fe0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -3457,7 +3457,8 @@ private static boolean decodeBooleanOptVal(byte[] optval, int optlen) throws Pos return decodeIntOptVal(optval, optlen) != 0; } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public int inet_addr(Object src) { try { @@ -3467,7 +3468,7 @@ public int inet_addr(Object src) { } } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public int inet_aton(Object src) throws InvalidAddressException { @@ -3487,14 +3488,14 @@ public int inet_aton(Object src) throws InvalidAddressException { }; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public Object inet_ntoa(int address) { return String.format("%d.%d.%d.%d", (address >> 24) & 0xFF, (address >> 16) & 0xFF, (address >> 8) & 0xFF, address & 0xFF); } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { @@ -3527,7 +3528,7 @@ public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAd throw posixException(OSErrorEnum.EAFNOSUPPORT); } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public Object inet_ntop(int family, byte[] src) throws PosixException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index c7ab9f66e1..217a7f177e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1448,37 +1448,37 @@ public final void setsockopt(int sockfd, int level, int optname, byte[] optval, } } - @ExportMessage - final int inet_addr(Object src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int inet_addr(Object src) { logEnter("inet_addr", "%s", src); - return logExit("inet_addr", "%d", lib.inet_addr(delegate, src)); + return logExit("inet_addr", "%d", delegate.inet_addr(src)); } - @ExportMessage - final int inet_aton(Object src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws InvalidAddressException { + @Override + @TruffleBoundary + public final int inet_aton(Object src) throws InvalidAddressException { logEnter("inet_aton", "%s", src); try { - return logExit("inet_aton", "%d", lib.inet_aton(delegate, src)); + return logExit("inet_aton", "%d", delegate.inet_aton(src)); } catch (InvalidAddressException e) { throw logException("inet_aton", e); } } - @ExportMessage - final Object inet_ntoa(int address, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final Object inet_ntoa(int address) { logEnter("inet_ntoa", "%d", address); - return logExit("inet_ntoa", "%s", lib.inet_ntoa(delegate, address)); + return logExit("inet_ntoa", "%s", delegate.inet_ntoa(address)); } - @ExportMessage - final byte[] inet_pton(int family, Object src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException, InvalidAddressException { + @Override + @TruffleBoundary + public final byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { logEnter("inet_pton", "%d, %s", family, src); try { - return logExit("inet_pton", "%s", lib.inet_pton(delegate, family, src)); + return logExit("inet_pton", "%s", delegate.inet_pton(family, src)); } catch (PosixException e) { throw logException("inet_pton", e); } catch (InvalidAddressException e) { @@ -1486,12 +1486,12 @@ final byte[] inet_pton(int family, Object src, } } - @ExportMessage - final Object inet_ntop(int family, byte[] src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object inet_ntop(int family, byte[] src) throws PosixException { logEnter("inet_ntop", "%d, %s", family, src); try { - return logExit("inet_ntop", "%s", lib.inet_ntop(delegate, family, src)); + return logExit("inet_ntop", "%s", delegate.inet_ntop(family, src)); } catch (PosixException e) { throw logException("inet_ntop", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 53d312c39d..2ca52ab316 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -2602,7 +2602,8 @@ public void setsockopt(int sockfd, int level, int optname, byte[] optval, int op } } - @ExportMessage + @Override + @TruffleBoundary public int inet_addr(Object src) { long srcPtr = bufferToNativeCString((Buffer) src); try { @@ -2612,7 +2613,8 @@ public int inet_addr(Object src) { } } - @ExportMessage + @Override + @TruffleBoundary public int inet_aton(Object src) throws InvalidAddressException { long srcPtr = bufferToNativeCString((Buffer) src); try { @@ -2626,7 +2628,8 @@ public int inet_aton(Object src) throws InvalidAddressException { } } - @ExportMessage + @Override + @TruffleBoundary public Object inet_ntoa(int src) { Buffer buf = Buffer.allocate(INET_ADDRSTRLEN.value); long nativeBuf = NativeMemory.mallocByteArray(INET_ADDRSTRLEN.value); @@ -2641,7 +2644,8 @@ public Object inet_ntoa(int src) { } } - @ExportMessage + @Override + @TruffleBoundary public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { byte[] buf = new byte[family == AF_INET.value ? 4 : 16]; long srcPtr = NULLPTR; @@ -2667,7 +2671,8 @@ public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAd } } - @ExportMessage + @Override + @TruffleBoundary public Object inet_ntop(int family, byte[] src) throws PosixException { if ((family == AF_INET.value && src.length < 4) || (family == AF_INET6.value && src.length < 16)) { CompilerDirectives.transferToInterpreterAndInvalidate(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 467f0bdb1c..c1521e9759 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -42,6 +42,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; +import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; @@ -173,6 +174,16 @@ public final long semOpen(Object name) throws PosixException { public abstract void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; + public abstract int inet_addr(Object src); + + public abstract int inet_aton(Object src) throws InvalidAddressException; + + public abstract Object inet_ntoa(int address); + + public abstract byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException; + + public abstract Object inet_ntop(int family, byte[] src) throws PosixException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index 3bc399d5a6..c9426d9498 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -332,79 +332,6 @@ public String toString() { // region Name resolution messages - /** - * Corresponds to POSIX {@code inet_addr} function, but the address is returned in host byte - * order (and is signed) so that it can be used in {@link Inet4SockAddr} directly without any - * further conversions. If the input is invalid, the native function returns - * {@link PosixConstants#INADDR_NONE}, which is also returned when the input is - * {@code 255.255.255.255}. Since it is not possible to tell whether an error occurred, this - * message does not throw exception and leaves the decision to the caller who might have more - * information. - * - * @param src the IPv4 address in numbers-and-dots notation (converted to opaque object using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)}) - * @return address in host byte order or {@link PosixConstants#INADDR_NONE} if the input is - * invalid - * @see "inet(3) man pages" - */ - public abstract int inet_addr(Object receiver, Object src); - - /** - * Corresponds to POSIX {@code inet_aton} function, but the address is returned in host byte - * order (and is signed) so that it can be used in {@link Inet4SockAddr} directly without any - * further conversions. - * - * @param src the IPv4 address in numbers-and-dots notation (converted to opaque object using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)}) - * @return address in host byte order - * @throws InvalidAddressException if {@code cp} is not a valid representation of an IPv4 - * address - * @see "inet(3) man pages" - */ - public abstract int inet_aton(Object receiver, Object src) throws InvalidAddressException; - - /** - * Corresponds to POSIX {@code inet_ntoa} function, but the address is expected in host byte - * order (and is signed) for consistency with other messages. - * - * @param address tha IPv4 address in host byte order - * @return opaque string in IPv4 dotted-decimal notation to be converted using - * {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - * @see "inet(3) man pages" - */ - public abstract Object inet_ntoa(Object receiver, int address); - - /** - * Corresponds to POSIX {@code inet_pton} function. - * - * @param family {@code AF_INET} or {@code AF_INET6} - * @param src opaque string (converted using {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)}) - * @return the binary address in network order (4 bytes for {@code AF_INET}, 16 bytes for - * {@code AF_INET6}) - * @throws PosixException with {@code EAFNOSUPPORT} if the {@code family} is not supported - * @throws InvalidAddressException if {@code src} is not a valid representation of an address of - * given family - */ - public abstract byte[] inet_pton(Object receiver, int family, Object src) throws PosixException, InvalidAddressException; - - /** - * Corresponds to POSIX {@code inet_ntop} function. - * - * @param family {@code AF_INET} or {@code AF_INET6} - * @param src the address in network order, must be at least 4 (for {@code AF_INET}) or 16 (for - * {@code AF_INET6}) bytes long, extra bytes are ignored - * @return an opaque string to be converted using {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - * @throws PosixException with {@code EAFNOSUPPORT} if the {@code family} is not supported - * @throws IllegalArgumentException if {@code src} does not satisfy the requirements stated - * above - */ - public abstract Object inet_ntop(Object receiver, int family, byte[] src) throws PosixException; - /** * @return an opaque string to be converted using {@link #getCStringAsString(Object, Object)} or * {@link #getCStringAsBytes(Object, Object)} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 00dd3e1e12..897a9118a2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -1061,39 +1061,39 @@ public final void setsockopt(int sockfd, int level, int optname, byte[] optval, nativePosixSupport.setsockopt(sockfd, level, optname, optval, optlen); } - @ExportMessage - final int inet_addr(Object src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int inet_addr(Object src) { checkNotInPreInitialization(); - return nativeLib.inet_addr(nativePosixSupport, src); + return nativePosixSupport.inet_addr(src); } - @ExportMessage - final int inet_aton(Object src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws InvalidAddressException { + @Override + @TruffleBoundary + public final int inet_aton(Object src) throws InvalidAddressException { checkNotInPreInitialization(); - return nativeLib.inet_aton(nativePosixSupport, src); + return nativePosixSupport.inet_aton(src); } - @ExportMessage - final Object inet_ntoa(int address, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Object inet_ntoa(int address) { checkNotInPreInitialization(); - return nativeLib.inet_ntoa(nativePosixSupport, address); + return nativePosixSupport.inet_ntoa(address); } - @ExportMessage - final byte[] inet_pton(int family, Object src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException, InvalidAddressException { + @Override + @TruffleBoundary + public final byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { checkNotInPreInitialization(); - return nativeLib.inet_pton(nativePosixSupport, family, src); + return nativePosixSupport.inet_pton(family, src); } - @ExportMessage - final Object inet_ntop(int family, byte[] src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object inet_ntop(int family, byte[] src) throws PosixException { checkNotInPreInitialization(); - return nativeLib.inet_ntop(nativePosixSupport, family, src); + return nativePosixSupport.inet_ntop(family, src); } @ExportMessage From 64f31da074770a9c137b5ab79001550639d84773 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 19:41:21 +0200 Subject: [PATCH 057/129] Convert PosixSupportLibrary name resolution and address-info cursor (cherry picked from commit 969f7dde224e42c8885b7490c25cc844341b77a8) --- .../oracle/graal/python/test/SocketTests.java | 189 +++++++++--------- .../modules/SocketModuleBuiltins.java | 60 +++--- .../builtins/objects/socket/SocketNodes.java | 16 +- .../python/runtime/EmulatedPosixSupport.java | 48 +++-- .../python/runtime/LoggingPosixSupport.java | 23 ++- .../python/runtime/NativePosixSupport.java | 63 +++--- .../graal/python/runtime/PosixSupport.java | 10 + .../python/runtime/PosixSupportLibrary.java | 114 ++--------- .../python/runtime/PreInitPosixSupport.java | 23 ++- 9 files changed, 236 insertions(+), 310 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index de5aa2ed1d..550303d753 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -117,7 +117,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.FamilySpecificSockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; @@ -162,14 +161,12 @@ public static String[] params() { private PosixSupport posixSupport; private PosixSupportLibrary lib; private UniversalSockAddrLibrary usaLib; - private AddrInfoCursorLibrary aicLib; @Before public void setUp() { posixSupport = withPythonContextRule.getPythonContext().getPosixSupport(); lib = PosixSupportLibrary.getUncached(); usaLib = UniversalSockAddrLibrary.getUncached(); - aicLib = AddrInfoCursorLibrary.getUncached(); } @Test @@ -196,21 +193,21 @@ public void fillUniversalSockAddrUnix() throws PosixException { @Test public void dgramUnboundGetsocknameInet4() throws PosixException { int s = createSocket(AF_INET.value, SOCK_DGRAM.value, 0); - checkUsa(new Inet4SockAddr(0, INADDR_ANY.value), lib.getsockname(posixSupport, s)); + checkUsa(new Inet4SockAddr(0, INADDR_ANY.value), posixSupport.getsockname(s)); } @Test public void dgramUnboundGetsocknameInet6() throws PosixException { assumeTrue(isInet6Supported()); int s = createSocket(AF_INET6.value, SOCK_DGRAM.value, 0); - checkUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0), lib.getsockname(posixSupport, s)); + checkUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0), posixSupport.getsockname(s)); } @Test public void dgramUnboundGetsocknameUnix() throws PosixException { assumeTrue("native".equals(backendName)); int s = createSocket(AF_UNIX.value, SOCK_DGRAM.value, 0); - checkUsa(new UnixSockAddr(new byte[0]), lib.getsockname(posixSupport, s)); + checkUsa(new UnixSockAddr(new byte[0]), posixSupport.getsockname(s)); } @Test @@ -507,7 +504,7 @@ public void dgramUnconnectedGetpeername() { @Test public void dgramListen() { - expectErrno(() -> lib.listen(posixSupport, new UdpServer(AF_INET.value).fd, 5), + expectErrno(() -> posixSupport.listen(new UdpServer(AF_INET.value).fd, 5), OSErrorEnum.EOPNOTSUPP, OSErrorEnum.EACCES /* Some CI machines seem to block this with EACCESS */); } @@ -551,7 +548,7 @@ public void streamListeningGetpeername() { @Test public void streamListeningRecv() { expectErrno(() -> { - lib.recv(posixSupport, new TcpServer(AF_INET.value).fd, new byte[10], 0, 10, 0); + posixSupport.recv(new TcpServer(AF_INET.value).fd, new byte[10], 0, 10, 0); }, OSErrorEnum.ENOTCONN); } @@ -559,7 +556,7 @@ public void streamListeningRecv() { public void streamListeningSend() { // From send(2): Linux may return EPIPE instead of ENOTCONN. expectErrno(() -> { - lib.send(posixSupport, new TcpServer(AF_INET.value).fd, DATA, 0, DATA.length, 0); + posixSupport.send(new TcpServer(AF_INET.value).fd, DATA, 0, DATA.length, 0); }, OSErrorEnum.ENOTCONN, OSErrorEnum.EPIPE); } @@ -595,9 +592,9 @@ public void getSocketOptionsAcceptConn() throws PosixException { assumeTrue("native".equals(backendName)); assumeTrue(runsOnLinux()); // darwin defines but does not support SO_ACCEPTCONN int socket = createSocket(AF_INET.value, SOCK_STREAM.value, 0); - lib.bind(posixSupport, socket, createUsa(new Inet4SockAddr(0, INADDR_LOOPBACK.value))); + posixSupport.bind(socket, createUsa(new Inet4SockAddr(0, INADDR_LOOPBACK.value))); assertEquals(0, getIntSockOpt(socket, SOL_SOCKET.value, SO_ACCEPTCONN.value)); - lib.listen(posixSupport, socket, 5); + posixSupport.listen(socket, 5); assertEquals(1, getIntSockOpt(socket, SOL_SOCKET.value, SO_ACCEPTCONN.value)); } @@ -628,7 +625,7 @@ public void nonBlockingDgramRecv() { UdpClient cli = new UdpClient(AF_INET.value); cli.setBlocking(false); assertFalse(cli.getBlocking()); - lib.recv(posixSupport, cli.fd, new byte[10], 0, 10, 0); + posixSupport.recv(cli.fd, new byte[10], 0, 10, 0); }, OSErrorEnum.EWOULDBLOCK); } @@ -638,7 +635,7 @@ public void nonBlockingAccept() throws PosixException { TcpClient cli = new TcpClient(AF_INET.value); srv.setBlocking(false); try { - lib.accept(posixSupport, srv.fd); + posixSupport.accept(srv.fd); fail("Expected accept() to fail with EWOULDBLOCK"); } catch (PosixException e) { assertTrue(e.hasErrno(OSErrorEnum.EWOULDBLOCK)); @@ -715,52 +712,52 @@ public void streamSelect() throws PosixException { assertTrue(cliReadable); assertTrue(cReadable); - assertEquals(0, lib.recv(posixSupport, c.fd, new byte[10], 0, 10, 0)); + assertEquals(0, posixSupport.recv(c.fd, new byte[10], 0, 10, 0)); cli.recv(DATA, 0); } @Test public void getnameinfo() throws PosixException, GetAddrInfoException { - Object[] res = lib.getnameinfo(posixSupport, createUsa(new Inet6SockAddr(443, IN6ADDR_LOOPBACK, 0, 0)), NI_NUMERICSERV.value | NI_NUMERICHOST.value); + Object[] res = posixSupport.getnameinfo(createUsa(new Inet6SockAddr(443, IN6ADDR_LOOPBACK, 0, 0)), NI_NUMERICSERV.value | NI_NUMERICHOST.value); assertThat(p2s(res[0]), anyOf(equalTo("::1"), equalTo("0:0:0:0:0:0:0:1%0"))); assertEquals("443", p2s(res[1])); - res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), 0); + res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), 0); assertEquals("localhost", p2s(res[0])); assertEquals("https", p2s(res[1])); - res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(53535, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); + res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(53535, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); assertEquals("53535", p2s(res[1])); } @Test public void getnameinfoUdp() throws PosixException, GetAddrInfoException { assumeTrue(runsOnLinux()); - Object[] res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); + Object[] res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); assertEquals("exec", p2s(res[1])); - res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_DGRAM.value); + res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_DGRAM.value); assertThat(p2s(res[1]), anyOf(equalTo("biff"), equalTo("comsat"))); } @Test public void getnameinfoErr() { expectGetAddrInfoException(() -> { - lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_NAMEREQD.value); + posixSupport.getnameinfo(createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_NAMEREQD.value); }, EAI_NONAME); } @Test public void getaddrinfoErrNoInput() { expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, null, AF_UNSPEC.value, 0, 0, 0); + posixSupport.getaddrinfo(null, null, AF_UNSPEC.value, 0, 0, 0); }, EAI_NONAME); } @Test public void getaddrinfoErrFamily() { expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("http"), -42, 0, 0, 0); + posixSupport.getaddrinfo(null, s2p("http"), -42, 0, 0, 0); }, EAI_FAMILY); } @@ -768,7 +765,7 @@ public void getaddrinfoErrFamily() { public void getaddrinfoErrSockType() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("http"), AF_UNSPEC.value, -42, 0, 0); + posixSupport.getaddrinfo(null, s2p("http"), AF_UNSPEC.value, -42, 0, 0); }, EAI_SOCKTYPE); } @@ -776,7 +773,7 @@ public void getaddrinfoErrSockType() { public void getaddrinfoErrService() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("invalid service"), AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); + posixSupport.getaddrinfo(null, s2p("invalid service"), AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); }, EAI_SERVICE); } @@ -784,7 +781,7 @@ public void getaddrinfoErrService() { public void getaddrinfoErrAddrFamily() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, s2p("::1"), null, AF_INET.value, 0, 0, 0); + posixSupport.getaddrinfo(s2p("::1"), null, AF_INET.value, 0, 0, 0); }, EAI_ADDRFAMILY); } @@ -792,42 +789,42 @@ public void getaddrinfoErrAddrFamily() { public void getaddrinfoBadFlags() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("https"), AF_INET.value, 0, 0, AI_CANONNAME.value); + posixSupport.getaddrinfo(null, s2p("https"), AF_INET.value, 0, 0, AI_CANONNAME.value); }, EAI_BADFLAGS); } @Test public void getaddrinfoServiceOnly() throws PosixException, GetAddrInfoException { Object service = s2p("https"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, null, service, AF_UNSPEC.value, SOCK_STREAM.value, 0, 0); - cleanup.add(() -> aicLib.release(aic)); + AddrInfoCursor aic = posixSupport.getaddrinfo(null, service, AF_UNSPEC.value, SOCK_STREAM.value, 0, 0); + cleanup.add(() -> aic.release()); do { - int family = aicLib.getFamily(aic); + int family = aic.getFamily(); - assertEquals(SOCK_STREAM.value, aicLib.getSockType(aic)); - assertNull(aicLib.getCanonName(aic)); + assertEquals(SOCK_STREAM.value, aic.getSockType()); + assertNull(aic.getCanonName()); - UniversalSockAddr usa = aicLib.getSockAddr(aic); + UniversalSockAddr usa = aic.getSockAddr(); assertEquals(family, usaLib.getFamily(usa)); if (family == AF_INET.value) { Inet4SockAddr addr2 = usaLib.asInet4SockAddr(usa); assertEquals(INADDR_LOOPBACK.value, addr2.getAddress()); assertEquals(443, addr2.getPort()); } - } while (aicLib.next(aic)); + } while (aic.next()); } @Test public void getaddrinfoPassive() throws PosixException, GetAddrInfoException { Object service = s2p("https"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, null, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_PASSIVE.value); - cleanup.add(() -> aicLib.release(aic)); - assertEquals(AF_INET.value, aicLib.getFamily(aic)); - assertEquals(SOCK_STREAM.value, aicLib.getSockType(aic)); - assertEquals(IPPROTO_TCP.value, aicLib.getProtocol(aic)); - assertNull(aicLib.getCanonName(aic)); - - UniversalSockAddr usa = aicLib.getSockAddr(aic); + AddrInfoCursor aic = posixSupport.getaddrinfo(null, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_PASSIVE.value); + cleanup.add(() -> aic.release()); + assertEquals(AF_INET.value, aic.getFamily()); + assertEquals(SOCK_STREAM.value, aic.getSockType()); + assertEquals(IPPROTO_TCP.value, aic.getProtocol()); + assertNull(aic.getCanonName()); + + UniversalSockAddr usa = aic.getSockAddr(); Inet4SockAddr addr = usaLib.asInet4SockAddr(usa); assertEquals(INADDR_ANY.value, addr.getAddress()); assertEquals(443, addr.getPort()); @@ -836,35 +833,35 @@ public void getaddrinfoPassive() throws PosixException, GetAddrInfoException { @Test public void getaddrinfoServerOnlyNoCanon() throws PosixException, GetAddrInfoException { Object node = s2p("localhost"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, node, null, AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); - cleanup.add(() -> aicLib.release(aic)); + AddrInfoCursor aic = posixSupport.getaddrinfo(node, null, AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); + cleanup.add(() -> aic.release()); do { - assertEquals(SOCK_DGRAM.value, aicLib.getSockType(aic)); - assertEquals(IPPROTO_UDP.value, aicLib.getProtocol(aic)); - assertNull(aicLib.getCanonName(aic)); + assertEquals(SOCK_DGRAM.value, aic.getSockType()); + assertEquals(IPPROTO_UDP.value, aic.getProtocol()); + assertNull(aic.getCanonName()); - if (aicLib.getFamily(aic) == AF_INET.value) { - UniversalSockAddr usa = aicLib.getSockAddr(aic); + if (aic.getFamily() == AF_INET.value) { + UniversalSockAddr usa = aic.getSockAddr(); assertEquals(AF_INET.value, usaLib.getFamily(usa)); Inet4SockAddr addr = usaLib.asInet4SockAddr(usa); assertEquals(INADDR_LOOPBACK.value, addr.getAddress()); assertEquals(0, addr.getPort()); } - } while (aicLib.next(aic)); + } while (aic.next()); } @Test public void getaddrinfo() throws PosixException, GetAddrInfoException { Object node = s2p("localhost"); Object service = s2p("https"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, node, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_CANONNAME.value); - cleanup.add(() -> aicLib.release(aic)); - assertEquals(AF_INET.value, aicLib.getFamily(aic)); - assertEquals(SOCK_STREAM.value, aicLib.getSockType(aic)); - assertEquals(IPPROTO_TCP.value, aicLib.getProtocol(aic)); - assertEquals("localhost", p2s(aicLib.getCanonName(aic))); - - UniversalSockAddr usa = aicLib.getSockAddr(aic); + AddrInfoCursor aic = posixSupport.getaddrinfo(node, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_CANONNAME.value); + cleanup.add(() -> aic.release()); + assertEquals(AF_INET.value, aic.getFamily()); + assertEquals(SOCK_STREAM.value, aic.getSockType()); + assertEquals(IPPROTO_TCP.value, aic.getProtocol()); + assertEquals("localhost", p2s(aic.getCanonName())); + + UniversalSockAddr usa = aic.getSockAddr(); assertEquals(AF_INET.value, usaLib.getFamily(usa)); Inet4SockAddr addr2 = usaLib.asInet4SockAddr(usa); assertEquals(INADDR_LOOPBACK.value, addr2.getAddress()); @@ -917,7 +914,7 @@ public void inet_addr() { for (Map.Entry a : ip4Addresses.entrySet()) { String src = a.getKey(); Integer expected = a.getValue(); - int actual = lib.inet_addr(posixSupport, s2p(src)); + int actual = posixSupport.inet_addr(s2p(src)); assertEquals("inet_addr(\"" + src + "\")", expected == null ? INADDR_NONE.value : expected, actual); } } @@ -929,7 +926,7 @@ public void inet_aton() { Integer expected = a.getValue(); Integer actual; try { - actual = lib.inet_aton(posixSupport, s2p(src)); + actual = posixSupport.inet_aton(s2p(src)); } catch (InvalidAddressException e) { actual = null; } @@ -939,36 +936,36 @@ public void inet_aton() { @Test public void inet_ntoa() { - assertEquals("0.0.0.0", p2s(lib.inet_ntoa(posixSupport, 0x00000000))); - assertEquals("1.2.3.4", p2s(lib.inet_ntoa(posixSupport, 0x01020304))); - assertEquals("18.52.86.120", p2s(lib.inet_ntoa(posixSupport, 0x12345678))); - assertEquals("255.255.255.255", p2s(lib.inet_ntoa(posixSupport, 0xffffffff))); + assertEquals("0.0.0.0", p2s(posixSupport.inet_ntoa(0x00000000))); + assertEquals("1.2.3.4", p2s(posixSupport.inet_ntoa(0x01020304))); + assertEquals("18.52.86.120", p2s(posixSupport.inet_ntoa(0x12345678))); + assertEquals("255.255.255.255", p2s(posixSupport.inet_ntoa(0xffffffff))); } @Test public void inet_pton() throws PosixException, InvalidAddressException { - assertArrayEquals(new byte[]{1, 2, -2, -1}, lib.inet_pton(posixSupport, AF_INET.value, s2p("1.2.254.255"))); - assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, lib.inet_pton(posixSupport, AF_INET6.value, s2p("1::FF"))); - assertArrayEquals(MAPPED_LOOPBACK, lib.inet_pton(posixSupport, AF_INET6.value, s2p("::ffff:127.0.0.1"))); + assertArrayEquals(new byte[]{1, 2, -2, -1}, posixSupport.inet_pton(AF_INET.value, s2p("1.2.254.255"))); + assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, posixSupport.inet_pton(AF_INET6.value, s2p("1::FF"))); + assertArrayEquals(MAPPED_LOOPBACK, posixSupport.inet_pton(AF_INET6.value, s2p("::ffff:127.0.0.1"))); } @Test public void inet_pton_eafnosupport() { expectErrno(() -> { - lib.inet_pton(posixSupport, AF_UNSPEC.value, s2p("")); + posixSupport.inet_pton(AF_UNSPEC.value, s2p("")); }, OSErrorEnum.EAFNOSUPPORT); } @Test public void inet_pton_invalid_inet6() { Assert.assertThrows(InvalidAddressException.class, - () -> lib.inet_pton(posixSupport, AF_INET6.value, s2p(":"))); + () -> posixSupport.inet_pton(AF_INET6.value, s2p(":"))); } @Test public void inet_pton_invalid_inet4_as_inet6() { Assert.assertThrows(InvalidAddressException.class, - () -> lib.inet_pton(posixSupport, AF_INET6.value, s2p("127.0.0.1"))); + () -> posixSupport.inet_pton(AF_INET6.value, s2p("127.0.0.1"))); } @Test @@ -981,7 +978,7 @@ public void inet_pton_invalid_inet4() throws PosixException { }; for (String src : addresses) { try { - lib.inet_pton(posixSupport, AF_INET.value, s2p(src)); + posixSupport.inet_pton(AF_INET.value, s2p(src)); fail("inet_pton(AF_INET, \"" + src + "\") was expected to fail"); } catch (InvalidAddressException e) { // expected @@ -994,33 +991,33 @@ public void inet_pton_inet4_octal() { // native inet_pton on darwin accepts leading zeroes (but handles them as decimal) assumeTrue("java".equals(backendName) || runsOnLinux()); Assert.assertThrows(InvalidAddressException.class, - () -> lib.inet_pton(posixSupport, AF_INET.value, s2p("1.2.010.4"))); + () -> posixSupport.inet_pton(AF_INET.value, s2p("1.2.010.4"))); } @Test public void inet_ntop() throws PosixException { - assertEquals("1.0.255.254", p2s(lib.inet_ntop(posixSupport, AF_INET.value, new byte[]{1, 0, -1, -2, -3}))); - assertThat(p2s(lib.inet_ntop(posixSupport, AF_INET6.value, new byte[]{-3, -2, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4})), + assertEquals("1.0.255.254", p2s(posixSupport.inet_ntop(AF_INET.value, new byte[]{1, 0, -1, -2, -3}))); + assertThat(p2s(posixSupport.inet_ntop(AF_INET6.value, new byte[]{-3, -2, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4})), anyOf(equalTo("fdfe:0:ff00::1:203"), equalTo("fdfe:0:ff00:0:0:0:1:203"))); - assertEquals("::ffff:127.0.0.1", p2s(lib.inet_ntop(posixSupport, AF_INET6.value, MAPPED_LOOPBACK))); + assertEquals("::ffff:127.0.0.1", p2s(posixSupport.inet_ntop(AF_INET6.value, MAPPED_LOOPBACK))); } @Test public void inet_ntop_eafnosupport() { expectErrno(() -> { - lib.inet_ntop(posixSupport, AF_UNSPEC.value, new byte[16]); + posixSupport.inet_ntop(AF_UNSPEC.value, new byte[16]); }, OSErrorEnum.EAFNOSUPPORT); } @Test public void inet_ntop_len() { Assert.assertThrows(IllegalArgumentException.class, - () -> lib.inet_ntop(posixSupport, AF_INET6.value, new byte[15])); + () -> posixSupport.inet_ntop(AF_INET6.value, new byte[15])); } @Test public void gethostname() throws PosixException { - assertTrue(p2s(lib.gethostname(posixSupport)).length() > 0); + assertTrue(p2s(posixSupport.gethostname()).length() > 0); } private static FamilySpecificSockAddr localAddress(int family, int port) { @@ -1081,11 +1078,11 @@ private byte[] getNulTerminatedTempFileName() throws IOException { } private Object s2p(String s) { - return lib.createCStringFromString(posixSupport, toTruffleStringUncached(s)); + return posixSupport.createCStringFromString(toTruffleStringUncached(s)); } private String p2s(Object p) { - return lib.getCStringAsString(posixSupport, p).toJavaStringUncached(); + return posixSupport.getCStringAsString(p).toJavaStringUncached(); } private static void expectErrno(ThrowingRunnable runnable, OSErrorEnum... expectedErrorCodes) { @@ -1104,7 +1101,7 @@ private static void expectGetAddrInfoException(ThrowingRunnable runnable, Mandat } private int createSocket(int family, int type, int protocol) throws PosixException { - int sockfd = lib.socket(posixSupport, family, type, protocol); + int sockfd = posixSupport.socket(family, type, protocol); cleanup.add(() -> posixSupport.close(sockfd)); return sockfd; } @@ -1128,14 +1125,14 @@ private UniversalSockAddr createUsa(FamilySpecificSockAddr src) throws PosixExce private int getIntSockOpt(int socket, int level, int option) throws PosixException { byte[] buf = new byte[4]; - assertEquals(4, lib.getsockopt(posixSupport, socket, level, option, buf, 4)); + assertEquals(4, posixSupport.getsockopt(socket, level, option, buf, 4)); return nativeByteArraySupport().getInt(buf, 0); } private void setIntSockOpt(int socket, int level, int option, int value) throws PosixException { byte[] buf = new byte[4]; nativeByteArraySupport().putInt(buf, 0, value); - lib.setsockopt(posixSupport, socket, level, option, buf, 4); + posixSupport.setsockopt(socket, level, option, buf, 4); } private static ByteArraySupport nativeByteArraySupport() { @@ -1183,55 +1180,55 @@ private class Socket { } void bind(FamilySpecificSockAddr sockAddr) throws PosixException { - lib.bind(posixSupport, fd, createUsa(sockAddr)); + posixSupport.bind(fd, createUsa(sockAddr)); } void bindAny() throws PosixException { if (family == AF_INET.value) { - lib.bind(posixSupport, fd, createUsa(new Inet4SockAddr(0, INADDR_ANY.value))); + posixSupport.bind(fd, createUsa(new Inet4SockAddr(0, INADDR_ANY.value))); } else if (family == AF_INET6.value) { - lib.bind(posixSupport, fd, createUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0))); + posixSupport.bind(fd, createUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0))); } else { throw CompilerDirectives.shouldNotReachHere(); } } void connect(UniversalSockAddr addr) throws PosixException { - lib.connect(posixSupport, fd, addr); + posixSupport.connect(fd, addr); } void listen(int backlog) throws PosixException { - lib.listen(posixSupport, fd, backlog); + posixSupport.listen(fd, backlog); } UniversalSockAddr getpeername() throws PosixException { - return lib.getpeername(posixSupport, fd); + return posixSupport.getpeername(fd); } UniversalSockAddr getsockname() throws PosixException { - return lib.getsockname(posixSupport, fd); + return posixSupport.getsockname(fd); } void recv(byte[] expectedData, int flags) throws PosixException { byte[] buf = new byte[expectedData.length * 2]; - assertEquals(expectedData.length, lib.recv(posixSupport, fd, buf, 0, buf.length, flags)); + assertEquals(expectedData.length, posixSupport.recv(fd, buf, 0, buf.length, flags)); assertArrayEquals(expectedData, Arrays.copyOf(buf, expectedData.length)); } UniversalSockAddr recvfrom(byte[] expectedData, int flags) throws PosixException { byte[] buf = new byte[expectedData.length * 2]; - RecvfromResult recvfromResult = lib.recvfrom(posixSupport, fd, buf, 0, buf.length, flags); + RecvfromResult recvfromResult = posixSupport.recvfrom(fd, buf, 0, buf.length, flags); assertEquals(expectedData.length, recvfromResult.readBytes); assertArrayEquals(expectedData, Arrays.copyOf(buf, expectedData.length)); return recvfromResult.sockAddr; } void send(byte[] data, int flags) throws PosixException { - assertEquals(data.length, lib.send(posixSupport, fd, data, 0, data.length, flags)); + assertEquals(data.length, posixSupport.send(fd, data, 0, data.length, flags)); } void sendto(byte[] data, int flags, UniversalSockAddr destAddr) throws PosixException { - assertEquals(data.length, lib.sendto(posixSupport, fd, data, 0, data.length, flags, destAddr)); + assertEquals(data.length, posixSupport.sendto(fd, data, 0, data.length, flags, destAddr)); } void write(byte[] data) throws PosixException { @@ -1245,7 +1242,7 @@ void read(byte[] expectedData) throws PosixException { } void shutdown(int how) throws PosixException { - lib.shutdown(posixSupport, fd, how); + posixSupport.shutdown(fd, how); } void setBlocking(boolean block) throws PosixException { @@ -1277,7 +1274,7 @@ private class Server extends Socket { } int acceptFd(FamilySpecificSockAddr expectedAddress) throws PosixException { - AcceptResult acceptResult = lib.accept(posixSupport, fd); + AcceptResult acceptResult = posixSupport.accept(fd); cleanup.add(() -> posixSupport.close(acceptResult.socketFd)); checkUsa(expectedAddress, acceptResult.sockAddr); return acceptResult.socketFd; @@ -1293,7 +1290,7 @@ private class InetServer extends Server { if (type == SOCK_STREAM.value) { listen(5); } - UniversalSockAddr boundUsa = lib.getsockname(posixSupport, fd); + UniversalSockAddr boundUsa = posixSupport.getsockname(fd); port = checkBound(family, boundUsa); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index b26819a308..49ac532eb2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -111,7 +111,6 @@ import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; @@ -256,7 +255,7 @@ static TruffleString doGeneric(VirtualFrame frame, try { gil.release(true); try { - return context.getPosixSupport().getCStringAsString(posixLib.gethostname(context.getPosixSupport())); + return context.getPosixSupport().getCStringAsString(context.getPosixSupport().gethostname()); } finally { gil.acquire(); } @@ -273,7 +272,6 @@ public abstract static class GetHostByAddrNode extends PythonUnaryBuiltinNode { static Object doGeneric(VirtualFrame frame, Object ip, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @@ -291,7 +289,7 @@ static Object doGeneric(VirtualFrame frame, Object ip, UniversalSockAddr addr = setIpAddrNode.execute(frame, idnaConverter.execute(frame, ip), AF_UNSPEC.value); int family = sockAddrLibrary.getFamily(addr); try { - Object[] getnameinfoResult = posixLib.getnameinfo(context.getPosixSupport(), addr, NI_NAMEREQD.value); + Object[] getnameinfoResult = context.getPosixSupport().getnameinfo(addr, NI_NAMEREQD.value); TruffleString hostname = context.getPosixSupport().getCStringAsString(getnameinfoResult[0]); SequenceStorage storage = new ObjectSequenceStorage(5); @@ -300,19 +298,19 @@ static Object doGeneric(VirtualFrame frame, Object ip, AddrInfoCursor cursor; gil.release(true); try { - cursor = posixLib.getaddrinfo(context.getPosixSupport(), getnameinfoResult[0], context.getPosixSupport().createCStringFromString(T_ZERO), + cursor = context.getPosixSupport().getaddrinfo(getnameinfoResult[0], context.getPosixSupport().createCStringFromString(T_ZERO), family, 0, 0, 0); } finally { gil.acquire(); } try { do { - UniversalSockAddr forwardAddr = addrInfoCursorLib.getSockAddr(cursor); + UniversalSockAddr forwardAddr = cursor.getSockAddr(); storage = appendNode.execute(inliningTarget, storage, makeIpAddrNode.execute(frame, inliningTarget, forwardAddr), SequenceStorageNodes.ListGeneralizationNode.SUPPLIER); - } while (addrInfoCursorLib.next(cursor)); + } while (cursor.next()); LoopNode.reportLoopCount(inliningTarget, storage.length()); } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } catch (GetAddrInfoException e1) { // Ignore failing forward lookup and return at least the hostname @@ -371,7 +369,6 @@ static Object get(VirtualFrame frame, Object nameObj, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @CachedLibrary(limit = "1") UniversalSockAddrLibrary addrLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, @@ -386,11 +383,11 @@ static Object get(VirtualFrame frame, Object nameObj, */ try { PosixSupport posixSupport = context.getPosixSupport(); - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixSupport.createCStringFromBytes(name), + AddrInfoCursor cursor = posixSupport.getaddrinfo(posixSupport.createCStringFromBytes(name), null, AF_INET.value, 0, 0, AI_CANONNAME.value); try { - TruffleString canonName = posixSupport.getCStringAsString(addrInfoCursorLib.getCanonName(cursor)); - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addrInfoCursorLib.getSockAddr(cursor)); + TruffleString canonName = posixSupport.getCStringAsString(cursor.getCanonName()); + Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(cursor.getSockAddr()); TruffleString addr = posixSupport.getCStringAsString(posixSupport.inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); // getaddrinfo doesn't support aliases PList aliases = PFactory.createList(context.getLanguage(inliningTarget)); @@ -398,7 +395,7 @@ static Object get(VirtualFrame frame, Object nameObj, PList addrs = PFactory.createList(context.getLanguage(inliningTarget), new Object[]{addr}); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{canonName, aliases, addrs}); } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } catch (GetAddrInfoException e) { throw constructAndRaiseNode.get(inliningTarget).executeWithArgsOnly(frame, SocketGAIError, new Object[]{e.getErrorCode(), e.getMessageAsTruffleString()}); @@ -424,7 +421,6 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec @Cached InlinedConditionProfile noneProtocol, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Cached TruffleString.ToJavaStringNode toJavaStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @@ -455,15 +451,15 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec AddrInfoCursor cursor; try { PosixSupport posixSupport = context.getPosixSupport(); - cursor = posixLib.getaddrinfo(posixSupport, null, posixSupport.createCStringFromString(serviceName), AF_INET.value, 0, protocol, 0); + cursor = posixSupport.getaddrinfo(null, posixSupport.createCStringFromString(serviceName), AF_INET.value, 0, protocol, 0); } finally { gil.acquire(); } try { - UniversalSockAddr addr = addrInfoCursorLib.getSockAddr(cursor); + UniversalSockAddr addr = cursor.getSockAddr(); return sockAddrLibrary.asInet4SockAddr(addr).getPort(); } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } catch (GetAddrInfoException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SERVICE_PROTO_NOT_FOUND); @@ -521,7 +517,7 @@ Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, if (protocolName != null && equalNode.execute(protocolName, T_UDP, TS_ENCODING)) { flags |= NI_DGRAM.value; } - Object[] result = posixLib.getnameinfo(getPosixSupport(), addr, flags); + Object[] result = getPosixSupport().getnameinfo(addr, flags); TruffleString name = getPosixSupport().getCStringAsString(result[1]); checkName(name); return name; @@ -560,7 +556,6 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, @SuppressWarnings("unused") @Cached PyTupleCheckNode tupleCheckNode, @Cached GetTupleStorage getTupleStorage, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Cached GilNode gil, @Cached SequenceStorageNodes.GetItemScalarNode getItem, @@ -603,17 +598,17 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, gil.release(true); PosixSupport posixSupport = context.getPosixSupport(); try { - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixSupport.createCStringFromString(address), + AddrInfoCursor cursor = posixSupport.getaddrinfo(posixSupport.createCStringFromString(address), posixSupport.createCStringFromString(fromLongNode.execute(port, TS_ENCODING, false)), AF_UNSPEC.value, SOCK_DGRAM.value, 0, AI_NUMERICHOST.value); try { - family = addrInfoCursorLib.getFamily(cursor); - resolvedAddr = addrInfoCursorLib.getSockAddr(cursor); - if (addrInfoCursorLib.next(cursor)) { + family = cursor.getFamily(); + resolvedAddr = cursor.getSockAddr(); + if (cursor.next()) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SOCKADDR_RESOLVED_TO_MULTIPLE_ADDRESSES); } } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } finally { gil.acquire(); @@ -631,7 +626,7 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.UNKNOWN_FAMILY); } - Object[] getnameinfo = posixLib.getnameinfo(posixSupport, queryAddr, flags); + Object[] getnameinfo = posixSupport.getnameinfo(queryAddr, flags); TruffleString host = posixSupport.getCStringAsString(getnameinfo[0]); TruffleString service = posixSupport.getCStringAsString(getnameinfo[1]); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{host, service}); @@ -667,7 +662,6 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje @Bind Node inliningTarget, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary cursorLib, @Cached InlinedExactClassProfile profile, @Cached("createIdna()") IdnaFromStringOrBytesConverterNode idna, @Cached PyLongAsLongNode asLongNode, @@ -707,7 +701,7 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje // TODO getaddrinfo lock gil.release(true); try { - cursor = posixLib.getaddrinfo(posixSupport, host, port, family, type, proto, flags); + cursor = posixSupport.getaddrinfo(host, port, family, type, proto, flags); } finally { gil.acquire(); } @@ -719,19 +713,19 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje try { SequenceStorage storage = new ObjectSequenceStorage(5); do { - Object addr = makeSockAddrNode.execute(frame, inliningTarget, cursorLib.getSockAddr(cursor)); + Object addr = makeSockAddrNode.execute(frame, inliningTarget, cursor.getSockAddr()); TruffleString canonName = T_EMPTY_STRING; - if (cursorLib.getCanonName(cursor) != null) { - canonName = posixSupport.getCStringAsString(cursorLib.getCanonName(cursor)); + if (cursor.getCanonName() != null) { + canonName = posixSupport.getCStringAsString(cursor.getCanonName()); } PTuple tuple = PFactory.createTuple(context.getLanguage(inliningTarget), - new Object[]{cursorLib.getFamily(cursor), cursorLib.getSockType(cursor), cursorLib.getProtocol(cursor), canonName, addr}); + new Object[]{cursor.getFamily(), cursor.getSockType(), cursor.getProtocol(), canonName, addr}); storage = appendNode.execute(inliningTarget, storage, tuple, SequenceStorageNodes.ListGeneralizationNode.SUPPLIER); - } while (cursorLib.next(cursor)); + } while (cursor.next()); LoopNode.reportLoopCount(inliningTarget, storage.length()); return PFactory.createList(context.getLanguage(inliningTarget), storage); } finally { - cursorLib.release(cursor); + cursor.release(); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index eb12c86071..b7a53a4eac 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -88,7 +88,6 @@ import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; @@ -280,7 +279,6 @@ public abstract static class SetIpAddrNode extends Node { static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @Bind Node inliningTarget, @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoLib, @Cached InetPtoNCachedPNode inetPtoNCachedPNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached GilNode gil, @@ -292,15 +290,15 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, gil.release(true); try { // TODO getaddrinfo lock? - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, null, posixSupport.createCStringFromString(T_ZERO), + AddrInfoCursor cursor = posixSupport.getaddrinfo(null, posixSupport.createCStringFromString(T_ZERO), family, SOCK_DGRAM.value, 0, AI_PASSIVE.value); try { - if (addrInfoLib.next(cursor)) { + if (cursor.next()) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.WILD_CARD_RESOLVED_TO_MULTIPLE_ADDRESS); } - return addrInfoLib.getSockAddr(cursor); + return cursor.getSockAddr(); } finally { - addrInfoLib.release(cursor); + cursor.release(); } } finally { gil.acquire(); @@ -336,12 +334,12 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, gil.release(true); try { // TODO getaddrinfo lock? - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixSupport.createCStringFromBytes(name), null, + AddrInfoCursor cursor = posixSupport.getaddrinfo(posixSupport.createCStringFromBytes(name), null, family, 0, 0, 0); try { - return addrInfoLib.getSockAddr(cursor); + return cursor.getSockAddr(); } finally { - addrInfoLib.release(cursor); + cursor.release(); } } finally { gil.acquire(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index fc78500fe0..6c103bd67d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -231,7 +231,6 @@ import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.ChannelNotSelectableException; import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; @@ -3551,13 +3550,14 @@ public Object inet_ntop(int family, byte[] src) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public Object gethostname() throws PosixException { return getHostName(withoutIOSocket); } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { @@ -3608,7 +3608,7 @@ private String searchServicesForPort(TruffleLanguage.Env env, int port, String p return null; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { @@ -3710,7 +3710,6 @@ public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int s return new EmulatedAddrInfoCursorImpl(items.iterator(), canonName, protocol, flags); } - @ExportLibrary(AddrInfoCursorLibrary.class) protected static class EmulatedAddrInfoCursorImpl implements AddrInfoCursor { final Iterator iterator; final String canonName; @@ -3726,15 +3725,16 @@ protected static class EmulatedAddrInfoCursorImpl implements AddrInfoCursor { item = iterator.next(); } - @ExportMessage - final void release() { + @Override + @TruffleBoundary + public final void release() { checkReleased(); item = null; } - @ExportMessage + @Override @TruffleBoundary - final boolean next() { + public final boolean next() { if (!iterator.hasNext()) { return false; } @@ -3742,36 +3742,42 @@ final boolean next() { return true; } - @ExportMessage - final int getFlags() { + @Override + @TruffleBoundary + public final int getFlags() { return flags; } - @ExportMessage - final int getFamily() { + @Override + @TruffleBoundary + public final int getFamily() { return item.address.getFamily(); } - @ExportMessage - final int getSockType() { + @Override + @TruffleBoundary + public final int getSockType() { return item.socketType; } - @ExportMessage - final int getProtocol() { + @Override + @TruffleBoundary + public final int getProtocol() { if (protocol != 0) { return protocol; } return item.socketType == SOCK_DGRAM.value ? IPPROTO_UDP.value : IPPROTO_TCP.value; } - @ExportMessage - final Object getCanonName() { + @Override + @TruffleBoundary + public final Object getCanonName() { return canonName; } - @ExportMessage - final UniversalSockAddr getSockAddr() { + @Override + @TruffleBoundary + public final UniversalSockAddr getSockAddr() { return item.address; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 217a7f177e..363e7ce8d7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1497,22 +1497,23 @@ public final Object inet_ntop(int family, byte[] src) throws PosixException { } } - @ExportMessage - final Object gethostname(@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object gethostname() throws PosixException { logEnter("gethostname", ""); try { - return logExit("gethostname", "%s", lib.gethostname(delegate)); + return logExit("gethostname", "%s", delegate.gethostname()); } catch (PosixException e) { throw logException("gethostname", e); } } - @ExportMessage - final Object[] getnameinfo(UniversalSockAddr addr, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { logEnter("getnameinfo", "%s, %d", addr, flags); try { - return logExit("getnameinfo", "%s", lib.getnameinfo(delegate, addr, flags)); + return logExit("getnameinfo", "%s", delegate.getnameinfo(addr, flags)); } catch (UnsupportedPosixFeatureException e) { throw logException("getnameinfo", e); } catch (GetAddrInfoException e) { @@ -1520,12 +1521,12 @@ final Object[] getnameinfo(UniversalSockAddr addr, int flags, } } - @ExportMessage - final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { logEnter("getaddrinfo", "%s, %s, %d, %d, %d, %d", node, service, family, sockType, protocol, flags); try { - return logExit("getaddrinfo", "%s", lib.getaddrinfo(delegate, node, service, family, sockType, protocol, flags)); + return logExit("getaddrinfo", "%s", delegate.getaddrinfo(node, service, family, sockType, protocol, flags)); } catch (UnsupportedPosixFeatureException e) { throw logException("getaddrinfo", e); } catch (GetAddrInfoException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 2ca52ab316..6defba203e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -105,7 +105,6 @@ import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; @@ -2696,7 +2695,8 @@ public Object inet_ntop(int family, byte[] src) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object gethostname() throws PosixException { int maxLen = (HOST_NAME_MAX.defined ? HOST_NAME_MAX.getValueIfDefined() : _POSIX_HOST_NAME_MAX.value) + 1; if (maxLen <= 1) { @@ -2719,10 +2719,9 @@ public Object gethostname() throws PosixException { } } - @ExportMessage - public Object[] getnameinfo(UniversalSockAddr usa, int flags, - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws GetAddrInfoException { + @Override + @TruffleBoundary + public Object[] getnameinfo(UniversalSockAddr usa, int flags) throws GetAddrInfoException { Buffer host = Buffer.allocate(NI_MAXHOST.value); Buffer serv = Buffer.allocate(NI_MAXSERV.value); UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; @@ -2735,7 +2734,7 @@ public Object[] getnameinfo(UniversalSockAddr usa, int flags, nativeServ = NativeMemory.mallocByteArray(NI_MAXSERV.value); int res = posixNativeFunctionInvoker.call_getnameinfo(nativeAddr, addr.getLen(), nativeHost, NI_MAXHOST.value, nativeServ, NI_MAXSERV.value, flags); if (res != 0) { - throw new GetAddrInfoException(res, gai_strerror(inliningTarget, res, zeroTerminatedUtf8ToTruffleStringNode)); + throw new GetAddrInfoException(res, gai_strerror(null, res, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.getUncached())); } NativeMemory.readByteArrayElements(nativeHost, 0, host.data, 0, host.data.length); NativeMemory.readByteArrayElements(nativeServ, 0, serv.data, 0, serv.data.length); @@ -2750,10 +2749,9 @@ public Object[] getnameinfo(UniversalSockAddr usa, int flags, } } - @ExportMessage - public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags, - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws GetAddrInfoException { + @Override + @TruffleBoundary + public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws GetAddrInfoException { long nodePtr = NULLPTR; long servicePtr = NULLPTR; long nativePtr = NULLPTR; @@ -2763,7 +2761,7 @@ public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int s nativePtr = NativeMemory.mallocLongArray(1); int res = posixNativeFunctionInvoker.call_getaddrinfo(nodePtr, servicePtr, family, sockType, protocol, flags, nativePtr); if (res != 0) { - throw new GetAddrInfoException(res, gai_strerror(inliningTarget, res, zeroTerminatedUtf8ToTruffleStringNode)); + throw new GetAddrInfoException(res, gai_strerror(null, res, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.getUncached())); } long head = NativeMemory.readLong(nativePtr); assert head != 0; // getaddrinfo should return at least one result @@ -2887,7 +2885,6 @@ long getNextPtr() { } } - @ExportLibrary(AddrInfoCursorLibrary.class) protected static class AddrInfoCursorImpl implements AddrInfoCursor { private final NativePosixSupport nativePosixSupport; @@ -2901,15 +2898,17 @@ protected static class AddrInfoCursorImpl implements AddrInfoCursor { info.update(head, nativePosixSupport); } - @ExportMessage - void release() { + @Override + @TruffleBoundary + public void release() { checkReleased(); nativePosixSupport.posixNativeFunctionInvoker.call_freeaddrinfo(head); head = 0; } - @ExportMessage - boolean next() { + @Override + @TruffleBoundary + public boolean next() { checkReleased(); long nextPtr = info.getNextPtr(); if (nextPtr == 0) { @@ -2919,32 +2918,37 @@ boolean next() { return true; } - @ExportMessage - int getFlags() { + @Override + @TruffleBoundary + public int getFlags() { checkReleased(); return info.getFlags(); } - @ExportMessage - int getFamily() { + @Override + @TruffleBoundary + public int getFamily() { checkReleased(); return info.getFamily(); } - @ExportMessage - int getSockType() { + @Override + @TruffleBoundary + public int getSockType() { checkReleased(); return info.getSockType(); } - @ExportMessage - int getProtocol() { + @Override + @TruffleBoundary + public int getProtocol() { checkReleased(); return info.getProtocol(); } - @ExportMessage - Object getCanonName() { + @Override + @TruffleBoundary + public Object getCanonName() { checkReleased(); long namePtr = info.getCanonNamePtr(); if (namePtr == 0) { @@ -2956,8 +2960,9 @@ Object getCanonName() { return Buffer.wrap(buf); } - @ExportMessage - UniversalSockAddr getSockAddr() { + @Override + @TruffleBoundary + public UniversalSockAddr getSockAddr() { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(nativePosixSupport); PythonUtils.arraycopy(info.socketAddress, 0, addr.data, 0, info.getAddrLen()); addr.setFamily(info.getAddrFamily()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index c1521e9759..6ad61ad418 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -41,7 +41,9 @@ package com.oracle.graal.python.runtime; import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; +import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; +import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; @@ -184,6 +186,14 @@ public final long semOpen(Object name) throws PosixException { public abstract Object inet_ntop(int family, byte[] src) throws PosixException; + public abstract Object gethostname() throws PosixException; + + public abstract Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException; + + /** The caller must release the returned cursor exactly once. */ + public abstract AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) + throws UnsupportedPosixFeatureException, GetAddrInfoException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index c9426d9498..cd287124af 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -332,125 +332,39 @@ public String toString() { // region Name resolution messages - /** - * @return an opaque string to be converted using {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - */ - public abstract Object gethostname(Object receiver) throws PosixException; - - /** - * Corresponds to POSIX {@code getnameinfo(3)}, except it always retrieves both host and service - * names. - * - * @param addr socket address to convert - * @param flags a combination of {@code NI_xxx} flags - * @return an array of two (host, service) opaque strings to be converted using - * {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - * @throws GetAddrInfoException when an error occurs (PosixException is not thrown because - * getnameinfo uses its own error codes and gai_strerror instead of the usual errno - * and strerror) - */ - public abstract Object[] getnameinfo(Object receiver, UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException; - - /** - * Corresponds to POSIX {@code getaddrinfo(3)}, except it always passes a non-null value for the - * {@code hints} parameter. - * - * @param node {@code null} or the host name converted using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)} - * @param service {@code null} or the service name converted using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)} - * @param family one of the {@code AF_xxx} constants, or {@link PosixConstants#AF_UNSPEC} to get - * addresses of any family - * @param sockType one of the {@code SOCK_xxx} constants, or 0 to get addresses of any type - * @param protocol 0 to get addresses with any protocol - * @param flags bitwise OR of {@code AI_xxx} constants - * @return an object representing one or more {@code struct addrinfo}s, which must be explicitly - * released by the caller - * @throws GetAddrInfoException when an error occurs (PosixException is not thrown because - * getaddrinfo uses its own error codes and gai_strerror instead of the usual errno - * and strerror) - */ - public abstract AddrInfoCursor getaddrinfo(Object receiver, Object node, Object service, int family, int sockType, int protocol, int flags) - throws UnsupportedPosixFeatureException, GetAddrInfoException; - /** * Represents one or more addrinfos returned by {@code getaddrinfo()}. * - * Must be explicitly released using {@link AddrInfoCursorLibrary#release(AddrInfoCursor)}. + * Must be explicitly released using {@link #release()}. * Behaves like a cursor which points to a {@code struct addrinfo} structure (initially pointing * at the first address info). The cursor can only move forward using the - * {@link AddrInfoCursorLibrary#next(AddrInfoCursor)} message. - * - * @see AddrInfoCursorLibrary + * {@link #next()} method. */ public interface AddrInfoCursor { - } + void release(); - public abstract int ioctlBytes(Object receiver, int fd, long request, byte[] arg) throws PosixException; + boolean next(); - public abstract int ioctlInt(Object receiver, int fd, long request, int arg) throws PosixException; + int getFlags(); - /** - * Provides messages for manipulating {@link AddrInfoCursor}. - */ - @GenerateLibrary - public abstract static class AddrInfoCursorLibrary extends Library { + int getFamily(); - protected AddrInfoCursorLibrary() { - } + int getSockType(); - /** - * Releases resources associated with the results of {@code getaddrinfo()}. - * - * This must be called exactly once on all instances returned from - * {@link #getaddrinfo(Object, Object, Object, int, int, int, int)}. Released instances can - * no longer be used for any purpose. - */ - public abstract void release(AddrInfoCursor receiver); - - /** - * Moves the cursor to the next address info. - * - * @return false if there are no more address infos in which case the cursor keeps pointing - * to the last item - */ - public abstract boolean next(AddrInfoCursor receiver); - - public abstract int getFlags(AddrInfoCursor receiver); - - public abstract int getFamily(AddrInfoCursor receiver); - - public abstract int getSockType(AddrInfoCursor receiver); - - public abstract int getProtocol(AddrInfoCursor receiver); - - /** - * @return {@code null} or opaque name to be converted using - * {@link PosixSupportLibrary#getPathAsString(Object, Object)} or - * {@link PosixSupportLibrary#getPathAsBytes(Object, Object)} - */ - public abstract Object getCanonName(AddrInfoCursor receiver); + int getProtocol(); - public abstract UniversalSockAddr getSockAddr(AddrInfoCursor receiver); + Object getCanonName(); - static final LibraryFactory FACTORY = LibraryFactory.resolve(AddrInfoCursorLibrary.class); + UniversalSockAddr getSockAddr(); + } - public static LibraryFactory getFactory() { - return FACTORY; - } + public abstract int ioctlBytes(Object receiver, int fd, long request, byte[] arg) throws PosixException; - public static AddrInfoCursorLibrary getUncached() { - return FACTORY.getUncached(); - } - } + public abstract int ioctlInt(Object receiver, int fd, long request, int arg) throws PosixException; /** * Exception that indicates and error while executing - * {@link #getaddrinfo(Object, Object, Object, int, int, int, int)}. + * {@link PosixSupport#getaddrinfo(Object, Object, int, int, int, int)}. */ public static final class GetAddrInfoException extends Exception { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 897a9118a2..832a44b0ed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -1096,24 +1096,25 @@ public final Object inet_ntop(int family, byte[] src) throws PosixException { return nativePosixSupport.inet_ntop(family, src); } - @ExportMessage - final Object gethostname(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object gethostname() throws PosixException { checkNotInPreInitialization(); - return nativeLib.gethostname(nativePosixSupport); + return nativePosixSupport.gethostname(); } - @ExportMessage - final Object[] getnameinfo(UniversalSockAddr addr, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { checkNotInPreInitialization(); - return nativeLib.getnameinfo(nativePosixSupport, addr, flags); + return nativePosixSupport.getnameinfo(addr, flags); } - @ExportMessage - final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { checkNotInPreInitialization(); - return nativeLib.getaddrinfo(nativePosixSupport, node, service, family, sockType, protocol, flags); + return nativePosixSupport.getaddrinfo(node, service, family, sockType, protocol, flags); } @Override From 1d929f0774533389c42281537e9a0a3f81876a51 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 20:01:59 +0200 Subject: [PATCH 058/129] Convert PosixSupportLibrary device control (cherry picked from commit ad2c4308bf63b38035f03a9ad438569896620190) --- .../builtins/modules/FcntlModuleBuiltins.java | 11 +++++------ .../python/runtime/EmulatedPosixSupport.java | 6 ++++-- .../python/runtime/LoggingPosixSupport.java | 16 ++++++++-------- .../graal/python/runtime/NativePosixSupport.java | 6 ++++-- .../graal/python/runtime/PosixSupport.java | 4 ++++ .../python/runtime/PosixSupportLibrary.java | 4 ---- .../python/runtime/PreInitPosixSupport.java | 16 ++++++++-------- 7 files changed, 33 insertions(+), 30 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java index 68d542c33b..c2a3e79cec 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java @@ -204,7 +204,6 @@ abstract static class IoctlNode extends PythonClinicBuiltinNode { Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutateArg, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @CachedLibrary(limit = "3") PythonBufferAcquireLibrary acquireLib, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Cached("createFor($node)") InteropCallData callData, @@ -260,7 +259,7 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat bufferLib.readIntoByteArray(buffer, 0, ioctlArg, 0, len); } try { - int ret = callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, releaseGil, posixLib, gilNode, constructAndRaiseNode); + int ret = callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, releaseGil, gilNode, constructAndRaiseNode); if (writable && mutateArg) { return ret; } else { @@ -292,7 +291,7 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat } byte[] ioctlArg = new byte[len + 1]; copyToByteArrayNode.execute(stringArg, 0, ioctlArg, 0, len, utf8); - callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, true, posixLib, gilNode, constructAndRaiseNode); + callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, true, gilNode, constructAndRaiseNode); return PFactory.createBytes(context.getLanguage(inliningTarget), ioctlArg, len); } @@ -305,7 +304,7 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat try { gilNode.release(true); try { - return posixLib.ioctlInt(getPosixSupport(), fd, request, intArg); + return getPosixSupport().ioctlInt(fd, request, intArg); } finally { gilNode.acquire(); } @@ -314,14 +313,14 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat } } - private int callIoctlBytes(VirtualFrame frame, Node inliningTarget, int fd, long request, byte[] ioctlArg, boolean releaseGil, PosixSupportLibrary posixLib, GilNode gilNode, + private int callIoctlBytes(VirtualFrame frame, Node inliningTarget, int fd, long request, byte[] ioctlArg, boolean releaseGil, GilNode gilNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { if (releaseGil) { gilNode.release(true); } try { - return posixLib.ioctlBytes(getPosixSupport(), fd, request, ioctlArg); + return getPosixSupport().ioctlBytes(fd, request, ioctlArg); } finally { if (releaseGil) { gilNode.acquire(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 6c103bd67d..2e8c591a7c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -3113,13 +3113,15 @@ private static PwdResult createPwdResult(UnixSystem unix) { return new PwdResult(toTruffleStringUncached(unix.getUsername()), unix.getUid(), unix.getGid(), homeDir, T_BIN_SH); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") public int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { throw createUnsupportedFeature("ioctl"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") public int ioctlInt(int fd, long request, int arg) throws PosixException { throw createUnsupportedFeature("ioctl"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 363e7ce8d7..e96fc22d4a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -1265,23 +1265,23 @@ public PwdResult[] getpwentries() throws PosixException { } } - @ExportMessage - final int ioctlBytes(int fd, long request, byte[] arg, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { logEnter("ioctl", "%d %d %s", fd, request, arg); try { - return logExit("ioctl", "%d", lib.ioctlBytes(delegate, fd, request, arg)); + return logExit("ioctl", "%d", delegate.ioctlBytes(fd, request, arg)); } catch (PosixException e) { throw logException("ioctl", e); } } - @ExportMessage - final int ioctlInt(int fd, long request, int arg, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlInt(int fd, long request, int arg) throws PosixException { logEnter("ioctl", "%d %d %d", fd, request, arg); try { - return logExit("ioctl", "%d", lib.ioctlInt(delegate, fd, request, arg)); + return logExit("ioctl", "%d", delegate.ioctlInt(fd, request, arg)); } catch (PosixException e) { throw logException("ioctl", e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 6defba203e..9eea60b88f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -3406,7 +3406,8 @@ private static PwdResult createPwdResult(byte[] data, long[] output, TruffleStri extractZeroTerminatedString(data, output[4], fromByteArrayNode, switchEncodingFromUtf8Node)); } - @ExportMessage + @Override + @TruffleBoundary public int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { long nativeArg = NULLPTR; try { @@ -3427,7 +3428,8 @@ public int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int ioctlInt(int fd, long request, int arg) throws PosixException { int res = posixNativeFunctionInvoker.call_ioctl_int(fd, request, arg); if (res < 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 6ad61ad418..91431234d0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -194,6 +194,10 @@ public final long semOpen(Object name) throws PosixException { public abstract AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException; + public abstract int ioctlBytes(int fd, long request, byte[] arg) throws PosixException; + + public abstract int ioctlInt(int fd, long request, int arg) throws PosixException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index cd287124af..b3c900586b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -358,10 +358,6 @@ public interface AddrInfoCursor { UniversalSockAddr getSockAddr(); } - public abstract int ioctlBytes(Object receiver, int fd, long request, byte[] arg) throws PosixException; - - public abstract int ioctlInt(Object receiver, int fd, long request, int arg) throws PosixException; - /** * Exception that indicates and error while executing * {@link PosixSupport#getaddrinfo(Object, Object, int, int, int, int)}. diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 832a44b0ed..487d9e9d0c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -949,18 +949,18 @@ public PwdResult[] getpwentries() throws PosixException { return nativePosixSupport.getpwentries(); } - @ExportMessage - final int ioctlBytes(int fd, long request, byte[] arg, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { checkNotInPreInitialization(); - return nativeLib.ioctlBytes(nativePosixSupport, fd, request, arg); + return nativePosixSupport.ioctlBytes(fd, request, arg); } - @ExportMessage - final int ioctlInt(int fd, long request, int arg, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlInt(int fd, long request, int arg) throws PosixException { checkNotInPreInitialization(); - return nativeLib.ioctlInt(nativePosixSupport, fd, request, arg); + return nativePosixSupport.ioctlInt(fd, request, arg); } @Override From 67cdac7ff495b199d769e00bfbeb78d6136375a8 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 20:10:12 +0200 Subject: [PATCH 059/129] Convert PosixSupport socket-address factories and access (cherry picked from commit 9670d74e7e857aa16aeea6d3c20c7d38f293a9ed) --- .../oracle/graal/python/test/SocketTests.java | 69 ++++++++---------- .../modules/SocketModuleBuiltins.java | 20 ++--- .../objects/socket/SocketBuiltins.java | 4 +- .../builtins/objects/socket/SocketNodes.java | 41 +++++------ .../python/runtime/EmulatedPosixSupport.java | 36 +++++---- .../python/runtime/LoggingPosixSupport.java | 26 ++++--- .../python/runtime/NativePosixSupport.java | 39 ++++++---- .../graal/python/runtime/PosixSupport.java | 10 +++ .../python/runtime/PosixSupportLibrary.java | 73 +++---------------- .../python/runtime/PreInitPosixSupport.java | 26 ++++--- 10 files changed, 146 insertions(+), 198 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index 550303d753..4bc9a211b1 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -114,7 +114,6 @@ import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.runtime.PosixConstants.MandatoryIntConstant; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; @@ -130,7 +129,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; import com.oracle.graal.python.test.integration.CleanupRule; import com.oracle.truffle.api.CompilerDirectives; @@ -159,14 +157,10 @@ public static String[] params() { private static final UnixSockAddr UNIX_SOCK_ADDR_UNNAMED = new UnixSockAddr(new byte[0]); private PosixSupport posixSupport; - private PosixSupportLibrary lib; - private UniversalSockAddrLibrary usaLib; @Before public void setUp() { posixSupport = withPythonContextRule.getPythonContext().getPosixSupport(); - lib = PosixSupportLibrary.getUncached(); - usaLib = UniversalSockAddrLibrary.getUncached(); } @Test @@ -428,7 +422,7 @@ public void streamRecvfromInet() throws PosixException { checkUsa(cli.address(), c.getpeername()); c.send(DATA, 0); - assertEquals(AF_UNSPEC.value, usaLib.getFamily(cli.recvfrom(DATA, 0))); + assertEquals(AF_UNSPEC.value, cli.recvfrom(DATA, 0).getFamily()); } @Test @@ -477,7 +471,7 @@ public void streamWriteReadUnix() throws PosixException, IOException { Socket cli = new Socket(AF_UNIX.value, SOCK_STREAM.value); UniversalSockAddr addr = null; try { - addr = lib.createUniversalSockAddrUnix(posixSupport, unixSockAddr); + addr = posixSupport.createUniversalSockAddrUnix(unixSockAddr); } catch (InvalidUnixSocketPathException e) { assumeNoException(e); } @@ -805,9 +799,9 @@ public void getaddrinfoServiceOnly() throws PosixException, GetAddrInfoException assertNull(aic.getCanonName()); UniversalSockAddr usa = aic.getSockAddr(); - assertEquals(family, usaLib.getFamily(usa)); + assertEquals(family, usa.getFamily()); if (family == AF_INET.value) { - Inet4SockAddr addr2 = usaLib.asInet4SockAddr(usa); + Inet4SockAddr addr2 = usa.asInet4SockAddr(); assertEquals(INADDR_LOOPBACK.value, addr2.getAddress()); assertEquals(443, addr2.getPort()); } @@ -818,14 +812,14 @@ public void getaddrinfoServiceOnly() throws PosixException, GetAddrInfoException public void getaddrinfoPassive() throws PosixException, GetAddrInfoException { Object service = s2p("https"); AddrInfoCursor aic = posixSupport.getaddrinfo(null, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_PASSIVE.value); - cleanup.add(() -> aic.release()); + cleanup.add(aic::release); assertEquals(AF_INET.value, aic.getFamily()); assertEquals(SOCK_STREAM.value, aic.getSockType()); assertEquals(IPPROTO_TCP.value, aic.getProtocol()); assertNull(aic.getCanonName()); UniversalSockAddr usa = aic.getSockAddr(); - Inet4SockAddr addr = usaLib.asInet4SockAddr(usa); + Inet4SockAddr addr = usa.asInet4SockAddr(); assertEquals(INADDR_ANY.value, addr.getAddress()); assertEquals(443, addr.getPort()); } @@ -834,7 +828,7 @@ public void getaddrinfoPassive() throws PosixException, GetAddrInfoException { public void getaddrinfoServerOnlyNoCanon() throws PosixException, GetAddrInfoException { Object node = s2p("localhost"); AddrInfoCursor aic = posixSupport.getaddrinfo(node, null, AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); - cleanup.add(() -> aic.release()); + cleanup.add(aic::release); do { assertEquals(SOCK_DGRAM.value, aic.getSockType()); assertEquals(IPPROTO_UDP.value, aic.getProtocol()); @@ -842,8 +836,8 @@ public void getaddrinfoServerOnlyNoCanon() throws PosixException, GetAddrInfoExc if (aic.getFamily() == AF_INET.value) { UniversalSockAddr usa = aic.getSockAddr(); - assertEquals(AF_INET.value, usaLib.getFamily(usa)); - Inet4SockAddr addr = usaLib.asInet4SockAddr(usa); + assertEquals(AF_INET.value, usa.getFamily()); + Inet4SockAddr addr = usa.asInet4SockAddr(); assertEquals(INADDR_LOOPBACK.value, addr.getAddress()); assertEquals(0, addr.getPort()); } @@ -855,15 +849,15 @@ public void getaddrinfo() throws PosixException, GetAddrInfoException { Object node = s2p("localhost"); Object service = s2p("https"); AddrInfoCursor aic = posixSupport.getaddrinfo(node, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_CANONNAME.value); - cleanup.add(() -> aic.release()); + cleanup.add(aic::release); assertEquals(AF_INET.value, aic.getFamily()); assertEquals(SOCK_STREAM.value, aic.getSockType()); assertEquals(IPPROTO_TCP.value, aic.getProtocol()); assertEquals("localhost", p2s(aic.getCanonName())); UniversalSockAddr usa = aic.getSockAddr(); - assertEquals(AF_INET.value, usaLib.getFamily(usa)); - Inet4SockAddr addr2 = usaLib.asInet4SockAddr(usa); + assertEquals(AF_INET.value, usa.getFamily()); + Inet4SockAddr addr2 = usa.asInet4SockAddr(); assertEquals(INADDR_LOOPBACK.value, addr2.getAddress()); assertEquals(443, addr2.getPort()); } @@ -1017,7 +1011,7 @@ public void inet_ntop_len() { @Test public void gethostname() throws PosixException { - assertTrue(p2s(posixSupport.gethostname()).length() > 0); + assertFalse(p2s(posixSupport.gethostname()).isEmpty()); } private static FamilySpecificSockAddr localAddress(int family, int port) { @@ -1028,13 +1022,13 @@ private static FamilySpecificSockAddr localAddress(int family, int port) { } } - private int checkBound(int family, UniversalSockAddr usa) { - assertEquals(family, usaLib.getFamily(usa)); + private static int checkBound(int family, UniversalSockAddr usa) { + assertEquals(family, usa.getFamily()); int port; if (family == AF_INET.value) { - port = usaLib.asInet4SockAddr(usa).getPort(); + port = usa.asInet4SockAddr().getPort(); } else if (family == AF_INET6.value) { - port = usaLib.asInet6SockAddr(usa).getPort(); + port = usa.asInet6SockAddr().getPort(); } else { throw CompilerDirectives.shouldNotReachHere(); } @@ -1043,26 +1037,23 @@ private int checkBound(int family, UniversalSockAddr usa) { } private void checkUsa(FamilySpecificSockAddr expectedAddr, UniversalSockAddr actualUsa) { - if (expectedAddr instanceof Inet4SockAddr) { - Inet4SockAddr expected = (Inet4SockAddr) expectedAddr; - assertEquals(AF_INET.value, usaLib.getFamily(actualUsa)); - Inet4SockAddr actual = usaLib.asInet4SockAddr(actualUsa); + if (expectedAddr instanceof Inet4SockAddr expected) { + assertEquals(AF_INET.value, actualUsa.getFamily()); + Inet4SockAddr actual = actualUsa.asInet4SockAddr(); assertEquals(expected.getPort(), actual.getPort()); assertEquals(expected.getAddress(), actual.getAddress()); - } else if (expectedAddr instanceof Inet6SockAddr) { - Inet6SockAddr expected = (Inet6SockAddr) expectedAddr; - assertEquals(AF_INET6.value, usaLib.getFamily(actualUsa)); - Inet6SockAddr actual = usaLib.asInet6SockAddr(actualUsa); + } else if (expectedAddr instanceof Inet6SockAddr expected) { + assertEquals(AF_INET6.value, actualUsa.getFamily()); + Inet6SockAddr actual = actualUsa.asInet6SockAddr(); assertEquals(expected.getPort(), actual.getPort()); assertArrayEquals(expected.getAddress(), actual.getAddress()); assertEquals(expected.getScopeId(), actual.getScopeId()); if ("native".equals(backendName)) { assertEquals(expected.getFlowInfo(), actual.getFlowInfo()); } - } else if (expectedAddr instanceof UnixSockAddr) { - UnixSockAddr expected = (UnixSockAddr) expectedAddr; - assertEquals(AF_UNIX.value, usaLib.getFamily(actualUsa)); - UnixSockAddr actual = usaLib.asUnixSockAddr(actualUsa); + } else if (expectedAddr instanceof UnixSockAddr expected) { + assertEquals(AF_UNIX.value, actualUsa.getFamily()); + UnixSockAddr actual = actualUsa.asUnixSockAddr(); assertNullTerminatedArrayEquals(expected.getPath(), actual.getPath()); } else { fail("Unexpected subclass of FamilySpecificSockAddr: " + expectedAddr.getClass().getName()); @@ -1108,12 +1099,12 @@ private int createSocket(int family, int type, int protocol) throws PosixExcepti private UniversalSockAddr createUsa(FamilySpecificSockAddr src) throws PosixException { if (src instanceof Inet4SockAddr inet4SockAddr) { - return lib.createUniversalSockAddrInet4(posixSupport, inet4SockAddr); + return posixSupport.createUniversalSockAddrInet4(inet4SockAddr); } else if (src instanceof Inet6SockAddr inet6SockAddr) { - return lib.createUniversalSockAddrInet6(posixSupport, inet6SockAddr); + return posixSupport.createUniversalSockAddrInet6(inet6SockAddr); } else if (src instanceof UnixSockAddr unixSockAddr) { try { - return lib.createUniversalSockAddrUnix(posixSupport, unixSockAddr); + return posixSupport.createUniversalSockAddrUnix(unixSockAddr); } catch (InvalidUnixSocketPathException e) { assumeNoException(e); return null; // unreachable @@ -1236,7 +1227,7 @@ void write(byte[] data) throws PosixException { } void read(byte[] expectedData) throws PosixException { - Buffer buf = posixSupport.read(fd, expectedData.length * 2); + Buffer buf = posixSupport.read(fd, expectedData.length * 2L); assertEquals(expectedData.length, buf.length); assertArrayEquals(expectedData, Arrays.copyOf(buf.data, expectedData.length)); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index 49ac532eb2..e3e8e86591 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -116,7 +116,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage; @@ -272,7 +271,6 @@ public abstract static class GetHostByAddrNode extends PythonUnaryBuiltinNode { static Object doGeneric(VirtualFrame frame, Object ip, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SocketNodes.SetIpAddrNode setIpAddrNode, @@ -287,7 +285,7 @@ static Object doGeneric(VirtualFrame frame, Object ip, */ auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYADDR, ip); UniversalSockAddr addr = setIpAddrNode.execute(frame, idnaConverter.execute(frame, ip), AF_UNSPEC.value); - int family = sockAddrLibrary.getFamily(addr); + int family = addr.getFamily(); try { Object[] getnameinfoResult = context.getPosixSupport().getnameinfo(addr, NI_NAMEREQD.value); TruffleString hostname = context.getPosixSupport().getCStringAsString(getnameinfoResult[0]); @@ -338,7 +336,6 @@ public abstract static class GetHostByNameNode extends PythonUnaryBuiltinNode { static TruffleString getHostByName(VirtualFrame frame, Object nameObj, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary addrLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, @@ -347,7 +344,7 @@ static TruffleString getHostByName(VirtualFrame frame, Object nameObj, byte[] name = idnaConverter.execute(frame, nameObj); auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYNAME, PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{nameObj})); UniversalSockAddr addr = setIpAddrNode.execute(frame, name, AF_INET.value); - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); + Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); try { return context.getPosixSupport().getCStringAsString(context.getPosixSupport().inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); } catch (PosixException e) { @@ -368,7 +365,6 @@ public abstract static class GetHostByNameExNode extends PythonUnaryBuiltinNode static Object get(VirtualFrame frame, Object nameObj, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary addrLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, @@ -387,7 +383,7 @@ static Object get(VirtualFrame frame, Object nameObj, null, AF_INET.value, 0, 0, AI_CANONNAME.value); try { TruffleString canonName = posixSupport.getCStringAsString(cursor.getCanonName()); - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(cursor.getSockAddr()); + Inet4SockAddr inet4SockAddr = cursor.getSockAddr().asInet4SockAddr(); TruffleString addr = posixSupport.getCStringAsString(posixSupport.inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); // getaddrinfo doesn't support aliases PList aliases = PFactory.createList(context.getLanguage(inliningTarget)); @@ -421,7 +417,6 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec @Cached InlinedConditionProfile noneProtocol, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Cached TruffleString.ToJavaStringNode toJavaStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @@ -457,7 +452,7 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec } try { UniversalSockAddr addr = cursor.getSockAddr(); - return sockAddrLibrary.asInet4SockAddr(addr).getPort(); + return addr.asInet4SockAddr().getPort(); } finally { cursor.release(); } @@ -512,7 +507,7 @@ Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, try { gil.release(true); try { - UniversalSockAddr addr = posixLib.createUniversalSockAddrInet4(getPosixSupport(), new Inet4SockAddr(port, INADDR_ANY.value)); + UniversalSockAddr addr = getPosixSupport().createUniversalSockAddrInet4(new Inet4SockAddr(port, INADDR_ANY.value)); int flags = 0; if (protocolName != null && equalNode.execute(protocolName, T_UDP, TS_ENCODING)) { flags |= NI_DGRAM.value; @@ -556,7 +551,6 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, @SuppressWarnings("unused") @Cached PyTupleCheckNode tupleCheckNode, @Cached GetTupleStorage getTupleStorage, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Cached GilNode gil, @Cached SequenceStorageNodes.GetItemScalarNode getItem, @Cached CastToTruffleStringNode castAddress, @@ -619,9 +613,9 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, if (addrLen != 2) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.IPV4_MUST_BE_2_TUPLE); } - queryAddr = posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(port, sockAddrLibrary.asInet4SockAddr(resolvedAddr).getAddress())); + queryAddr = posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(port, resolvedAddr.asInet4SockAddr().getAddress())); } else if (family == AF_INET6.value) { - queryAddr = posixLib.createUniversalSockAddrInet6(posixSupport, new Inet6SockAddr(port, sockAddrLibrary.asInet6SockAddr(resolvedAddr).getAddress(), flowinfo, scopeid)); + queryAddr = posixSupport.createUniversalSockAddrInet6(new Inet6SockAddr(port, resolvedAddr.asInet6SockAddr().getAddress(), flowinfo, scopeid)); } else { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.UNKNOWN_FAMILY); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index 08fe982f1c..277c96fec0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -102,7 +102,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -223,7 +222,6 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, int protoIn, Object fileno, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary addrLib, @Bind Node inliningTarget, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PyLongAsIntNode asIntNode, @@ -240,7 +238,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i try { UniversalSockAddr addr = context.getPosixSupport().getsockname(fd); if (family == -1) { - family = addrLib.getFamily(addr); + family = addr.getFamily(); } } catch (PosixException e) { if (family == -1 || e.hasErrno(EBADF) || e.hasErrno(ENOTSOCK)) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index b7a53a4eac..0e1f3951ad 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -95,7 +95,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.PythonContext; @@ -129,7 +128,6 @@ public abstract static class GetSockAddrArgNode extends Node { static UniversalSockAddr doInet(VirtualFrame frame, @SuppressWarnings("unused") PSocket socket, Object address, String caller, @Bind Node inliningTarget, @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") @Shared("sockAddrLib") UniversalSockAddrLibrary sockAddrLib, @Shared("tupleCheck") @Cached PyTupleCheckNode tupleCheckNode, @Cached @Shared("tupleSize") PyTupleSizeNode tupleSize, @Cached @Shared("tupleGetItem") PyTupleGetItem tupleGetItem, @@ -150,14 +148,13 @@ static UniversalSockAddr doInet(VirtualFrame frame, @SuppressWarnings("unused") int port = parsePort(frame, caller, asIntNode, inliningTarget, errorProfile, tupleGetItem.execute(inliningTarget, address, 1), raiseNode); UniversalSockAddr addr = setIpAddrNode.execute(frame, host, AF_INET.value); PosixSupport posixSupport = context.getPosixSupport(); - return posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(port, sockAddrLib.asInet4SockAddr(addr).getAddress())); + return posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(port, addr.asInet4SockAddr().getAddress())); } @Specialization(guards = "isInet6(socket)") static UniversalSockAddr doInet6(VirtualFrame frame, @SuppressWarnings("unused") PSocket socket, Object address, String caller, @Bind Node inliningTarget, @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") @Shared("sockAddrLib") UniversalSockAddrLibrary sockAddrLib, @Shared("tupleCheck") @Cached PyTupleCheckNode tupleCheckNode, @Cached @Shared("tupleSize") PyTupleSizeNode tupleSize, @Cached @Shared("tupleGetItem") PyTupleGetItem tupleGetItem, @@ -188,8 +185,8 @@ static UniversalSockAddr doInet6(VirtualFrame frame, @SuppressWarnings("unused") scopeid = asIntNode.execute(frame, inliningTarget, tupleGetItem.execute(inliningTarget, address, 3)); } UniversalSockAddr addr = setIpAddrNode.execute(frame, host, AF_INET6.value); - Object posixSupport = context.getPosixSupport(); - return posixLib.createUniversalSockAddrInet6(posixSupport, new Inet6SockAddr(port, sockAddrLib.asInet6SockAddr(addr).getAddress(), flowinfo, scopeid)); + PosixSupport posixSupport = context.getPosixSupport(); + return posixSupport.createUniversalSockAddrInet6(new Inet6SockAddr(port, addr.asInet6SockAddr().getAddress(), flowinfo, scopeid)); } @Specialization(guards = "isUnix(socket)") @@ -219,9 +216,9 @@ static UniversalSockAddr doUnix(VirtualFrame frame, @SuppressWarnings("unused") path = arrayCopyOf(path, path.length + 1); } PythonContext context = PythonContext.get(inliningTarget); - Object posixSupport = context.getPosixSupport(); + PosixSupport posixSupport = context.getPosixSupport(); try { - return posixLib.createUniversalSockAddrUnix(posixSupport, new UnixSockAddr(path)); + return posixSupport.createUniversalSockAddrUnix(new UnixSockAddr(path)); } catch (UnsupportedPosixFeatureException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.AF_UNIX_NOT_SUPPORTED, caller); } catch (InvalidUnixSocketPathException e) { @@ -309,14 +306,14 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, if (family != AF_INET.value && family != AF_UNSPEC.value) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.ADDRESS_FAMILY_MISMATCHED); } - return posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(0, INADDR_BROADCAST.value)); + return posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(0, INADDR_BROADCAST.value)); } /* avoid a name resolution in case of numeric address */ /* check for an IPv4 address */ if (family == AF_INET.value || family == AF_UNSPEC.value) { byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixLib, posixSupport, AF_INET.value, name); if (bytes != null) { - return posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(0, bytes)); + return posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(0, bytes)); } } /* @@ -327,7 +324,7 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, if ((family == AF_INET6.value || family == AF_UNSPEC.value) && !hasScopeId(inliningTarget, name)) { byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixLib, posixSupport, AF_INET6.value, name); if (bytes != null) { - return posixLib.createUniversalSockAddrInet6(posixSupport, new Inet6SockAddr(0, bytes, 0, 0)); + return posixSupport.createUniversalSockAddrInet6(new Inet6SockAddr(0, bytes, 0, 0)); } } /* perform a name resolution */ @@ -397,10 +394,8 @@ private static boolean hasScopeId(Node inliningTarget, byte[] name) { public abstract static class MakeSockAddrNode extends Node { public abstract Object execute(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr); - @Specialization(limit = "1") + @Specialization static Object makeSockAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, - @CachedLibrary("addr") UniversalSockAddrLibrary addrLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Cached TruffleString.SwitchEncodingNode switchEncodingNode, @@ -408,19 +403,19 @@ static Object makeSockAddr(VirtualFrame frame, Node inliningTarget, UniversalSoc try { PythonContext context = PythonContext.get(inliningTarget); PythonLanguage language = context.getLanguage(inliningTarget); - int family = addrLib.getFamily(addr); + int family = addr.getFamily(); if (family == AF_INET.value) { - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); + Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); TruffleString addressString = posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); return PFactory.createTuple(language, new Object[]{addressString, inet4SockAddr.getPort()}); } else if (family == AF_INET6.value) { - Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); + Inet6SockAddr inet6SockAddr = addr.asInet6SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); TruffleString addressString = posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); return PFactory.createTuple(language, new Object[]{addressString, inet6SockAddr.getPort(), inet6SockAddr.getFlowInfo(), inet6SockAddr.getScopeId()}); } else if (family == AF_UNIX.value) { - UnixSockAddr unixSockAddr = addrLib.asUnixSockAddr(addr); + UnixSockAddr unixSockAddr = addr.asUnixSockAddr(); byte[] path = unixSockAddr.getPath(); if (PosixConstants.IS_LINUX && path.length > 0 && path[0] == 0) { // linux-specific "abstract" address @@ -457,21 +452,19 @@ private static TruffleString bytesToString(byte[] path, TruffleString.FromByteAr public abstract static class MakeIpAddrNode extends Node { public abstract Object execute(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr); - @Specialization(limit = "1") + @Specialization static Object makeAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, - @CachedLibrary("addr") UniversalSockAddrLibrary addrLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { PythonContext context = PythonContext.get(inliningTarget); - int family = addrLib.getFamily(addr); + int family = addr.getFamily(); if (family == AF_INET.value) { - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); + Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); return posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); } else if (family == AF_INET6.value) { - Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); + Inet6SockAddr inet6SockAddr = addr.asInet6SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); return posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 2e8c591a7c..c47ccfbd32 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -246,7 +246,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.exception.PythonExitException; @@ -381,6 +380,8 @@ public void setEnv(Env env) { } @Override + @ExportMessage + @TruffleBoundary public TruffleString getBackend() { return T_JAVA; } @@ -3800,22 +3801,24 @@ static final class Item { } } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { return EmulatedUniversalSockAddrImpl.inet4(src.getAddressAsBytes(), src.getPort()); } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { return EmulatedUniversalSockAddrImpl.inet6(src.getAddress(), src.getScopeId(), src.getPort()); } - @ExportMessage - UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("AF_UNIX"); } - @ExportLibrary(UniversalSockAddrLibrary.class) protected static class EmulatedUniversalSockAddrImpl implements UniversalSockAddr { final int family; final InetSocketAddress socketAddress; @@ -3826,23 +3829,24 @@ private EmulatedUniversalSockAddrImpl(int family, InetSocketAddress socketAddres this.socketAddress = socketAddress; } - @ExportMessage - int getFamily() { + @Override + @TruffleBoundary + public int getFamily() { return family; } - @ExportMessage + @Override @TruffleBoundary - Inet4SockAddr asInet4SockAddr() { + public Inet4SockAddr asInet4SockAddr() { if (getFamily() != AF_INET.value) { throw new IllegalArgumentException("Only AF_INET socket address can be converted to Inet4SockAddr"); } return new Inet4SockAddr(socketAddress.getPort(), socketAddress.getAddress().getAddress()); } - @ExportMessage + @Override @TruffleBoundary - Inet6SockAddr asInet6SockAddr() { + public Inet6SockAddr asInet6SockAddr() { if (getFamily() != AF_INET6.value) { throw new IllegalArgumentException("Only AF_INET6 socket address can be converted to Inet6SockAddr"); } @@ -3856,9 +3860,9 @@ Inet6SockAddr asInet6SockAddr() { return new Inet6SockAddr(socketAddress.getPort(), ipv6, 0, 0); } - @ExportMessage + @Override @TruffleBoundary - UnixSockAddr asUnixSockAddr() { + public UnixSockAddr asUnixSockAddr() { assert getFamily() != AF_UNIX.value; throw new IllegalArgumentException("Only AF_UNIX socket address can be converted to Unix4SockAddr"); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index e96fc22d4a..3c8f63de03 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -120,6 +120,8 @@ public void setEnv(Env env) { } @Override + @ExportMessage + @TruffleBoundary public final TruffleString getBackend() { logEnter(Level.FINEST, "getBackend", ""); return logExit(Level.FINEST, "getBackend", "%s", delegate.getBackend()); @@ -1644,26 +1646,26 @@ public final boolean semTimedWait(Node location, long handle, long deadlineNs) t } } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { logEnter("createUniversalSockAddrInet4", "%s", src); - return logExit("createUniversalSockAddrInet4", "%s", lib.createUniversalSockAddrInet4(delegate, src)); + return logExit("createUniversalSockAddrInet4", "%s", delegate.createUniversalSockAddrInet4(src)); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { logEnter("createUniversalSockAddrInet6", "%s", src); - return logExit("createUniversalSockAddrInet6", "%s", lib.createUniversalSockAddrInet6(delegate, src)); + return logExit("createUniversalSockAddrInet6", "%s", delegate.createUniversalSockAddrInet6(src)); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { logEnter("createUniversalSockAddrUnix", "%s", src); try { - return logExit("createUniversalSockAddrUnix", "%s", lib.createUniversalSockAddrUnix(delegate, src)); + return logExit("createUniversalSockAddrUnix", "%s", delegate.createUniversalSockAddrUnix(src)); } catch (UnsupportedPosixFeatureException e) { throw logException("createUniversalSockAddrUnix", e); } catch (InvalidUnixSocketPathException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 9eea60b88f..3f8e2f5bde 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -120,7 +120,6 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary; @@ -712,6 +711,8 @@ public void setEnv(Env env) { } @Override + @ExportMessage + @TruffleBoundary public TruffleString getBackend() { return nativeBackend; } @@ -2977,8 +2978,9 @@ private void checkReleased() { } } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); addr.setFamily(AF_INET.value); ARRAY_ACCESSOR_BE.putShort(addr.data, getConstant(OFFSETOF_STRUCT_SOCKADDR_IN_SIN_PORT), (short) src.getPort()); @@ -2987,8 +2989,9 @@ UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { return addr; } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); addr.setFamily(AF_INET6.value); ARRAY_ACCESSOR_BE.putShort(addr.data, getConstant(OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_PORT), (short) src.getPort()); @@ -3000,8 +3003,9 @@ UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { return addr; } - @ExportMessage - UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws InvalidUnixSocketPathException { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws InvalidUnixSocketPathException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); addr.setFamily(AF_UNIX.value); byte[] path = src.getPath(); @@ -3014,7 +3018,6 @@ UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws InvalidUn return addr; } - @ExportLibrary(UniversalSockAddrLibrary.class) protected static class UniversalSockAddrImpl implements UniversalSockAddr { private final NativePosixSupport nativePosixSupport; @@ -3026,8 +3029,9 @@ protected static class UniversalSockAddrImpl implements UniversalSockAddr { this.data = new byte[(int) getConstant(SIZEOF_STRUCT_SOCKADDR_STORAGE)]; } - @ExportMessage - int getFamily() { + @Override + @TruffleBoundary + public int getFamily() { int offset = (int) getConstant(OFFSETOF_STRUCT_SOCKADDR_SA_FAMILY); int size = (int) getConstant(SIZEOF_STRUCT_SOCKADDR_SA_FAMILY); if (getLen() >= offset + size) { @@ -3059,8 +3063,9 @@ void setFamily(int family) { } } - @ExportMessage - Inet4SockAddr asInet4SockAddr() { + @Override + @TruffleBoundary + public Inet4SockAddr asInet4SockAddr() { if (getFamily() != AF_INET.value) { throw CompilerDirectives.shouldNotReachHere("Only AF_INET socket address can be converted to Inet4SockAddr"); } @@ -3072,8 +3077,9 @@ Inet4SockAddr asInet4SockAddr() { return new Inet4SockAddr(port, address); } - @ExportMessage - Inet6SockAddr asInet6SockAddr() { + @Override + @TruffleBoundary + public Inet6SockAddr asInet6SockAddr() { if (getFamily() != AF_INET6.value) { throw CompilerDirectives.shouldNotReachHere("Only AF_INET6 socket address can be converted to Inet6SockAddr"); } @@ -3088,8 +3094,9 @@ Inet6SockAddr asInet6SockAddr() { return new Inet6SockAddr(port, address, flowInfo, scopeId); } - @ExportMessage - UnixSockAddr asUnixSockAddr() { + @Override + @TruffleBoundary + public UnixSockAddr asUnixSockAddr() { if (getFamily() != AF_UNIX.value) { throw CompilerDirectives.shouldNotReachHere("Only AF_UNIX socket address can be converted to UnixSockAddr"); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 91431234d0..b771ae6e65 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -45,6 +45,9 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; +import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; +import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; +import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; @@ -54,6 +57,7 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; +import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -198,6 +202,12 @@ public abstract AddrInfoCursor getaddrinfo(Object node, Object service, int fami public abstract int ioctlInt(int fd, long request, int arg) throws PosixException; + public abstract UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src); + + public abstract UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src); + + public abstract UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException; + public abstract void raise(int signal) throws PosixException; public abstract int alarm(int seconds) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index b3c900586b..1d64102c1d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -73,6 +73,9 @@ @GenerateLibrary(receiverType = PosixSupport.class) public abstract class PosixSupportLibrary extends Library { + /** Retained for the generated library until the remaining exports are removed. */ + public abstract TruffleString getBackend(Object receiver); + public static final char POSIX_FILENAME_SEPARATOR = '/'; // Constants for accessing the fields of the fstat result: @@ -168,9 +171,15 @@ public int getFamily() { * {@link FamilySpecificSockAddr} subclasses). This interface roughly corresponds to POSIX * {@code struct sockaddr_storage}. * - * @see UniversalSockAddrLibrary */ public interface UniversalSockAddr { + int getFamily(); + + Inet4SockAddr asInet4SockAddr(); + + Inet6SockAddr asInet6SockAddr(); + + UnixSockAddr asUnixSockAddr(); } /** @@ -392,68 +401,6 @@ public final Throwable fillInStackTrace() { // endregion - /** - * Allocates a new {@link UniversalSockAddr} and initializes it with the provided address. - */ - public abstract UniversalSockAddr createUniversalSockAddrInet4(Object receiver, Inet4SockAddr src); - - public abstract UniversalSockAddr createUniversalSockAddrInet6(Object receiver, Inet6SockAddr src); - - public abstract UniversalSockAddr createUniversalSockAddrUnix(Object receiver, UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException; - - /** - * Provides messages for manipulating {@link UniversalSockAddr}. - */ - @GenerateLibrary - public abstract static class UniversalSockAddrLibrary extends Library { - - protected UniversalSockAddrLibrary() { - } - - /** - * Returns the socket family of the address (one of the {@code AF_xxx} values defined in - * {@link PosixConstants}). - */ - public abstract int getFamily(UniversalSockAddr receiver); - - /** - * Converts the address represented by the receiver (which must be of the - * {@link PosixConstants#AF_INET} family) into a {@link Inet4SockAddr} instance. - * - * @throws IllegalArgumentException if the socket family of the address is not - * {@link PosixConstants#AF_INET} - */ - public abstract Inet4SockAddr asInet4SockAddr(UniversalSockAddr receiver); - - /** - * Converts the address represented by the receiver (which must be of the - * {@link PosixConstants#AF_INET6} family) into a {@link Inet6SockAddr} instance. - * - * @throws IllegalArgumentException if the socket family of the address is not - * {@link PosixConstants#AF_INET6} - */ - public abstract Inet6SockAddr asInet6SockAddr(UniversalSockAddr receiver); - - /** - * Converts the address represented by the receiver (which must be of the - * {@link PosixConstants#AF_UNIX} family) into a {@link UnixSockAddr} instance. - * - * @throws IllegalArgumentException if the socket family of the address is not - * {@link PosixConstants#AF_UNIX} - */ - public abstract UnixSockAddr asUnixSockAddr(UniversalSockAddr receiver); - - static final LibraryFactory FACTORY = LibraryFactory.resolve(UniversalSockAddrLibrary.class); - - public static LibraryFactory getFactory() { - return FACTORY; - } - - public static UniversalSockAddrLibrary getUncached() { - return FACTORY.getUncached(); - } - } - /** * Base class for exceptions that originate in the POSIX support layer. */ diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 487d9e9d0c..ca74927ef4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -153,6 +153,8 @@ private Object removeDirStream(Object dirStream) { } @Override + @ExportMessage + @TruffleBoundary public final TruffleString getBackend() { checkNotInPreInitialization(); return nativePosixSupport.getBackend(); @@ -1187,25 +1189,25 @@ public final boolean semTimedWait(Node location, long handle, long deadlineNs) t return nativePosixSupport.semTimedWait(location, handle, deadlineNs); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { checkNotInPreInitialization(); - return nativeLib.createUniversalSockAddrInet4(nativePosixSupport, src); + return nativePosixSupport.createUniversalSockAddrInet4(src); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { checkNotInPreInitialization(); - return nativeLib.createUniversalSockAddrInet6(nativePosixSupport, src); + return nativePosixSupport.createUniversalSockAddrInet6(src); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { checkNotInPreInitialization(); - return nativeLib.createUniversalSockAddrUnix(nativePosixSupport, src); + return nativePosixSupport.createUniversalSockAddrUnix(src); } @Override From 0ee91303fd03bdd77d02d9495b127fc423464786 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Wed, 30 Sep 2026 22:38:46 +0200 Subject: [PATCH 060/129] Move shared POSIX types and remove generated dispatch (cherry picked from commit c84c43dbd82cb299b1438a9b3f5bd1574202d0cd) --- .../oracle/graal/python/test/SocketTests.java | 32 +- .../oracle/graal/python/PythonLanguage.java | 2 +- .../modules/FaulthandlerModuleBuiltins.java | 8 +- .../builtins/modules/FcntlModuleBuiltins.java | 3 +- .../modules/GraalPythonModuleBuiltins.java | 1 - .../modules/MsvcrtModuleBuiltins.java | 11 +- .../builtins/modules/NtModuleBuiltins.java | 1 - .../builtins/modules/PosixModuleBuiltins.java | 49 +- .../modules/PosixShMemModuleBuiltins.java | 6 +- .../PosixSubprocessModuleBuiltins.java | 15 +- .../builtins/modules/PwdModuleBuiltins.java | 9 +- .../modules/ResourceModuleBuiltins.java | 4 +- .../modules/SelectModuleBuiltins.java | 10 +- .../modules/SignalModuleBuiltins.java | 6 +- .../modules/SocketModuleBuiltins.java | 29 +- .../modules/cext/PythonCextBuiltins.java | 4 +- .../cext/PythonCextObjectBuiltins.java | 3 - .../io/AbstractBufferedIOBuiltins.java | 2 +- .../modules/io/BufferedWriterNodes.java | 2 +- .../builtins/modules/io/FileIOBuiltins.java | 10 +- .../python/builtins/modules/io/PFileIO.java | 3 +- .../modules/io/WindowsConsoleIOBuiltins.java | 4 +- .../MultiprocessingModuleBuiltins.java | 6 +- .../multiprocessing/SemLockBuiltins.java | 8 +- .../builtins/objects/mmap/MMapBuiltins.java | 4 +- .../python/builtins/objects/mmap/PMMap.java | 5 +- .../objects/posix/DirEntryBuiltins.java | 6 +- .../objects/posix/PScandirIterator.java | 2 +- .../posix/ScandirIteratorBuiltins.java | 2 +- .../builtins/objects/select/PollBuiltins.java | 4 +- .../objects/socket/SocketBuiltins.java | 36 +- .../builtins/objects/socket/SocketNodes.java | 37 +- .../builtins/objects/socket/SocketUtils.java | 8 +- .../objects/ssl/SSLOperationNode.java | 5 +- .../python/nodes/PConstructAndRaiseNode.java | 6 +- .../python/runtime/EmulatedPosixSupport.java | 52 +- .../python/runtime/LoggingPosixSupport.java | 61 +- .../python/runtime/NativePosixSupport.java | 57 +- .../graal/python/runtime/PosixSupport.java | 625 +++++++++++++++- .../python/runtime/PosixSupportLibrary.java | 674 ------------------ .../python/runtime/PreInitPosixSupport.java | 60 +- .../oracle/graal/python/util/TimeUtils.java | 2 +- 42 files changed, 851 insertions(+), 1023 deletions(-) delete mode 100644 graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index 4bc9a211b1..7a3c46bfb9 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -114,22 +114,22 @@ import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.runtime.PosixConstants.MandatoryIntConstant; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.FamilySpecificSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.AcceptResult; +import com.oracle.graal.python.runtime.PosixSupport.AddrInfoCursor; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.FamilySpecificSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.GetAddrInfoException; +import com.oracle.graal.python.runtime.PosixSupport.Inet4SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.Inet6SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.InvalidAddressException; +import com.oracle.graal.python.runtime.PosixSupport.InvalidUnixSocketPathException; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.RecvfromResult; +import com.oracle.graal.python.runtime.PosixSupport.SelectResult; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.UnixSockAddr; import com.oracle.graal.python.test.integration.CleanupRule; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.memory.ByteArraySupport; 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 8e73ecbfae..54ddb4c584 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 @@ -103,8 +103,8 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PosixSupport.WindowsVersion; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.PythonThreadState; import com.oracle.graal.python.runtime.PythonImageBuildOptions; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java index a664258afa..0c6321b671 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java @@ -86,8 +86,8 @@ import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.ExceptionUtils; @@ -405,8 +405,8 @@ public void write(int b) { public void flush() throws IOException { super.flush(); try { - PythonContext.get(null).getPosixSupport().write(fd, PosixSupportLibrary.Buffer.wrap(bb.toArray())); - } catch (PosixSupportLibrary.PosixException e) { + PythonContext.get(null).getPosixSupport().write(fd, PosixSupport.Buffer.wrap(bb.toArray())); + } catch (PosixSupport.PosixException e) { // Ignore } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java index c2a3e79cec..efd562580e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java @@ -80,8 +80,7 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixConstants.IntConstant; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; 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 1e852540f3..796cecdbba 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 @@ -172,7 +172,6 @@ import com.oracle.graal.python.runtime.ExecutionContext.InteropCallContext; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonImageBuildOptions; import com.oracle.graal.python.runtime.PythonOptions; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java index 200d0faed4..d89c46b6fe 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java @@ -59,14 +59,13 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateNodeFactory; 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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -112,7 +111,7 @@ Object locking(VirtualFrame frame, int fd, int mode, long nbytes, } finally { gilNode.acquire(); } - } catch (PosixSupportLibrary.PosixException e) { + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } return PNone.NONE; @@ -135,7 +134,7 @@ int setMode(VirtualFrame frame, int fd, int flags, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { return getPosixSupport().setMode(fd, flags); - } catch (PosixSupportLibrary.PosixException e) { + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -158,7 +157,7 @@ long getOsfHandle(VirtualFrame frame, int fd, auditNode.audit(frame, inliningTarget, T_MSVCRT_GET_OSFHANDLE, fd); try { return getPosixSupport().getOsfHandle(fd); - } catch (PosixSupportLibrary.PosixException e) { + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -182,7 +181,7 @@ int openOsfHandle(VirtualFrame frame, long handle, int flags, auditNode.audit(frame, inliningTarget, T_MSVCRT_OPEN_OSFHANDLE, handle, flags); try { return getPosixSupport().openOsfHandle(handle, flags); - } catch (PosixSupportLibrary.PosixException e) { + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java index 48363313f8..b1036dda6c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java @@ -64,7 +64,6 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 17cf3a54ae..e6873dab1f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -123,12 +123,11 @@ import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixConstants.IntConstant; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.OpenPtyResult; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -353,7 +352,6 @@ public void patchPostInitialize(Python3Core core) { } private void populateEnviron(Python3Core core) { - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); PosixSupport posixSupport = core.getContext().getPosixSupport(); PythonLanguage language = core.getLanguage(); @@ -446,7 +444,6 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object valueObject, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { // Unlike in other posix builtins, we go through str -> bytes -> byte[] -> String @@ -523,7 +520,6 @@ static PNone putenv(VirtualFrame frame, Object nameObject, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object nameOpaque; @@ -566,7 +562,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile isPListProfile, @Cached TupleNodes.GetTupleStorage getTupleStorage, @Cached PyTupleCheckNode tupleCheckNode, @@ -640,7 +635,7 @@ static long getUid(@Bind Node inliningTarget, @Bind PythonContext context, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return context.getPosixSupport().geteuid(); + return context.getPosixSupport().geteuid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -664,7 +659,7 @@ static long getGid(@Bind Node inliningTarget, @Bind PythonContext context, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return context.getPosixSupport().getegid(); + return context.getPosixSupport().getegid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -1776,7 +1771,6 @@ abstract static class GetcwdNode extends PythonBuiltinNode { static TruffleString getcwd(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { return context.getPosixSupport().getPathAsString(context.getPosixSupport().getcwd()); @@ -1793,7 +1787,6 @@ abstract static class GetcwdbNode extends PythonBuiltinNode { static PBytes getcwdb(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object path = context.getPosixSupport().getcwd(); @@ -1946,12 +1939,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PList listdirPath(VirtualFrame frame, PosixPath path, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { - return listdir(frame, inliningTarget, context.getPosixSupport().opendir(path.value), path.wasBufferLike, false, posixLib, constructAndRaiseNode, + return listdir(frame, inliningTarget, context.getPosixSupport().opendir(path.value), path.wasBufferLike, false, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -1962,16 +1954,15 @@ static PList listdirPath(VirtualFrame frame, PosixPath path, static PList listdirFd(VirtualFrame frame, PosixFd fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, fd.originalObject); Object dirStream = dupAndFdopendir(frame, inliningTarget, context.getPosixSupport(), fd, constructAndRaiseNode); - return listdir(frame, inliningTarget, dirStream, false, true, posixLib, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); + return listdir(frame, inliningTarget, dirStream, false, true, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); } - private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dirStream, boolean produceBytes, boolean needsRewind, PosixSupportLibrary posixLib, - PConstructAndRaiseNode.Lazy constructAndRaiseNode, PythonLanguage language, PosixSupport posixSupport) { + private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dirStream, boolean produceBytes, boolean needsRewind, PConstructAndRaiseNode.Lazy constructAndRaiseNode, + PythonLanguage language, PosixSupport posixSupport) { List list = new ArrayList<>(); try { while (true) { @@ -2567,7 +2558,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object readlinkAsBytes(VirtualFrame frame, PosixPath path, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile wasBufferLikeProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { @@ -2854,7 +2844,6 @@ static int system(VirtualFrame frame, Object command, @Cached BytesNodes.ToBytesNode toBytesNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil) { // Unlike in other posix builtins, we go through str -> bytes -> byte[] -> String // conversions for emulated backend because the bytes version after fsencode conversion @@ -3077,7 +3066,7 @@ static Object register(Object before, Object afterInChild, Object afterInParent) /** * Helper node that accepts either str or bytes and converts it to a representation specific to - * the {@link PosixSupportLibrary} in use. Basically equivalent of + * the {@link PosixSupport} in use. Basically equivalent of * {@code PyUnicode_EncodeFSDefault}. */ @GenerateInline @@ -3090,7 +3079,6 @@ abstract static class StringOrBytesToOpaquePathNode extends Node { static Object doString(Node inliningTarget, Object strObj, @Cached CastToTruffleStringNode castToStringNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, strObj); return checkPath(inliningTarget, context.getPosixSupport().createPathFromString(str), raiseNode); @@ -3100,7 +3088,6 @@ static Object doString(Node inliningTarget, Object strObj, static Object doBytes(Node inliningTarget, PBytes bytes, @Cached(inline = false) BytesNodes.ToBytesNode toBytesNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { return checkPath(inliningTarget, context.getPosixSupport().createPathFromBytes(toBytesNode.execute(bytes)), raiseNode); } @@ -3115,7 +3102,7 @@ private static Object checkPath(Node inliningTarget, Object path, PRaiseNode rai /** * Similar to {@code PyUnicode_FSConverter}, but the actual conversion is delegated to the - * {@link PosixSupportLibrary} implementation. + * {@link PosixSupport} implementation. */ @GenerateInline @GenerateCached(false) @@ -3434,7 +3421,6 @@ public PathConversionNode(String functionName, String argumentName, boolean null PosixFileHandle doNone(@SuppressWarnings("unused") PNone value, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { Object path = context.getPosixSupport().createPathFromString(T_DOT); return new PosixPath(null, checkPath(inliningTarget, path, raiseNode), false); @@ -3473,7 +3459,6 @@ PosixFileHandle doUnicode(Object value, @Bind Node inliningTarget, @Exclusive @Cached CastToTruffleStringNode castToStringNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, value); Object path = context.getPosixSupport().createPathFromString(str); @@ -3486,7 +3471,6 @@ PosixFileHandle doBytes(PBytes value, @Bind Node inliningTarget, @Exclusive @Cached BytesNodes.ToBytesNode toByteArrayNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { Object path = context.getPosixSupport().createPathFromBytes(toByteArrayNode.execute(value)); return new PosixPath(value, checkPath(inliningTarget, path, raiseNode), true); @@ -3513,7 +3497,6 @@ PosixFileHandle doGeneric(VirtualFrame frame, Object value, @Exclusive @Cached BytesNodes.ToBytesNode toByteArrayNode, @Exclusive @Cached CastToTruffleStringNode castToStringNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { Object pathObject; try { @@ -3525,10 +3508,10 @@ PosixFileHandle doGeneric(VirtualFrame frame, Object value, // 'pathObject' replaces 'value' as the PosixPath.originalObject for auditing purposes // by design if (pathObject instanceof PBytes) { - return doBytes((PBytes) pathObject, inliningTarget, toByteArrayNode, context, posixLib, raiseNode); + return doBytes((PBytes) pathObject, inliningTarget, toByteArrayNode, context, raiseNode); } if (PGuards.isString(pathObject)) { - return doUnicode(pathObject, inliningTarget, castToStringNode, context, posixLib, raiseNode); + return doUnicode(pathObject, inliningTarget, castToStringNode, context, raiseNode); } throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.EXPECTED_FSPATH_TO_RETURN_STR_OR_BYTES, value, pathObject); } @@ -3745,7 +3728,7 @@ protected PosixFileHandle(Object originalObject) { } /** - * Contains the path converted to the representation used by the {@code PosixSupportLibrary} + * Contains the path converted to the representation used by the {@code PosixSupport} * implementation * * @see PosixSupport#createPathFromString(TruffleString) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java index 9e43933540..2e40dd5a0c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java @@ -53,8 +53,7 @@ import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -62,7 +61,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -90,7 +88,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static int shmOpen(VirtualFrame frame, TruffleString path, int flags, int mode, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object name = context.getPosixSupport().createCStringFromString(path); @@ -115,7 +112,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone shmUnlink(VirtualFrame frame, TruffleString path, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object name = context.getPosixSupport().createCStringFromString(path); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java index 0766f8f4b7..94bda1b824 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java @@ -81,9 +81,8 @@ import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -97,7 +96,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -111,7 +109,7 @@ protected List> getNodeFa /** * Helper converter which iterates the argv argument and converts each element to the opaque - * narrow string representation used by {@link PosixSupportLibrary}. + * narrow string representation used by {@link PosixSupport}. */ abstract static class ProcessArgsConversionNode extends ArgumentCastNode { @Specialization @@ -129,7 +127,6 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, @Cached GetSequenceStorageNode getSequenceStorageNode, @Cached IsBuiltinObjectProfile isBuiltinClassProfile, @Cached ObjectToOpaquePathNode objectToOpaquePathNode, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached("createNotNormalized()") GetItemNode getItemNode, @Cached PRaiseNode raiseNode) { PList argsList; @@ -178,7 +175,6 @@ static Object doSequence(VirtualFrame frame, Object env, @Cached PyObjectSizeNode sizeNode, @Cached ToBytesNode toBytesNode, @Cached PyObjectGetItem getItem, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PRaiseNode raiseNode) { // TODO unlike CPython, this accepts a dict (if the keys are integers (0, 1, ..., len-1) int length = sizeNode.execute(frame, inliningTarget, env); @@ -242,8 +238,8 @@ private static byte[] fsEncode(String s) { private static Object createCStringFromBytes(Node inliningTarget, byte[] bytes, PRaiseNode raiseNode) { Object o = PosixSupport.get(inliningTarget).createCStringFromBytes(bytes); if (o == null) { - // TODO reconsider the contract of PosixSupportLibrary#createCStringFromBytes w.r.t. - // embedded null checks (we need to review that anyway since PosixSupportLibrary + // TODO reconsider the contract of PosixSupport#createCStringFromBytes w.r.t. + // embedded null checks (we need to review that anyway since PosixSupport // cannot do Python-specific fsencode) throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.EMBEDDED_NULL_BYTE); } @@ -258,7 +254,6 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo int stderrRead, int stderrWrite, int errPipeRead, int errPipeWrite, boolean restoreSignals, boolean callSetsid, int pgidToSet, Object gidObject, Object groupsList, Object uidObject, int childUmask, Object preexecFn, boolean allowVFork, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached("createNotNormalized()") GetItemNode tupleGetItem, @Cached TupleNodes.GetTupleStorage getTupleStorage, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java index 6e9027b582..09bc67c816 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java @@ -71,10 +71,9 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PwdResult; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -84,7 +83,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -195,7 +193,6 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, @Bind PythonContext context, @Cached GilNode gil, @Cached StringOrBytesToOpaquePathNode encodeFSDefault, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile unsignedConversionProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java index 8d4258b3ee..a4370602c3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java @@ -60,8 +60,8 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.RusageResult; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java index fd1b058f96..9a621b1fe4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java @@ -72,11 +72,10 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.ChannelNotSelectableException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.ChannelNotSelectableException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.SelectResult; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PythonErrorType; import com.oracle.graal.python.runtime.object.PFactory; @@ -91,7 +90,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java index f80e547447..1d4a767c20 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java @@ -82,9 +82,9 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.AsyncHandler; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index e3e8e86591..3081a68e87 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -109,13 +109,12 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.AddrInfoCursor; +import com.oracle.graal.python.runtime.PosixSupport.GetAddrInfoException; +import com.oracle.graal.python.runtime.PosixSupport.Inet4SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.Inet6SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage; @@ -246,7 +245,6 @@ public abstract static class GetHostnameNode extends PythonBuiltinNode { static TruffleString doGeneric(VirtualFrame frame, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -270,7 +268,6 @@ public abstract static class GetHostByAddrNode extends PythonUnaryBuiltinNode { @Specialization static Object doGeneric(VirtualFrame frame, Object ip, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SocketNodes.SetIpAddrNode setIpAddrNode, @@ -335,7 +332,6 @@ public abstract static class GetHostByNameNode extends PythonUnaryBuiltinNode { @Specialization static TruffleString getHostByName(VirtualFrame frame, Object nameObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, @@ -364,7 +360,6 @@ public abstract static class GetHostByNameExNode extends PythonUnaryBuiltinNode @Specialization static Object get(VirtualFrame frame, Object nameObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, @@ -416,7 +411,6 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec @Bind Node inliningTarget, @Cached InlinedConditionProfile noneProtocol, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached TruffleString.ToJavaStringNode toJavaStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @@ -481,7 +475,6 @@ public abstract static class GetServByPortNode extends PythonBinaryClinicBuiltin Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, @Bind Node inliningTarget, @Cached InlinedConditionProfile nonProtocol, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached TruffleString.EqualNode equalNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @@ -550,7 +543,6 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, @Bind PythonContext context, @SuppressWarnings("unused") @Cached PyTupleCheckNode tupleCheckNode, @Cached GetTupleStorage getTupleStorage, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached SequenceStorageNodes.GetItemScalarNode getItem, @Cached CastToTruffleStringNode castAddress, @@ -655,7 +647,6 @@ public abstract static class GetAddrInfoNode extends PythonClinicBuiltinNode { static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObject, int family, int type, int proto, int flags, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedExactClassProfile profile, @Cached("createIdna()") IdnaFromStringOrBytesConverterNode idna, @Cached PyLongAsLongNode asLongNode, @@ -804,7 +795,6 @@ abstract static class InetAtoNNode extends PythonUnaryClinicBuiltinNode { static PBytes doConvert(TruffleString addr, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); @@ -812,7 +802,7 @@ static PBytes doConvert(TruffleString addr, byte[] bytes = new byte[4]; ByteArraySupport.bigEndian().putInt(bytes, 0, converted); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); - } catch (PosixSupportLibrary.InvalidAddressException e) { + } catch (PosixSupport.InvalidAddressException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.ILLEGAL_IP_ADDR_STRING_TO_INET_ATON); } } @@ -833,7 +823,6 @@ static TruffleString doGeneric(VirtualFrame frame, Object addr, @CachedLibrary("addr") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PRaiseNode raiseNode) { Object buffer = bufferAcquireLib.acquireReadonly(addr, frame, callData); try { @@ -860,7 +849,6 @@ abstract static class InetPtoNNode extends PythonBinaryClinicBuiltinNode { static PBytes doConvert(VirtualFrame frame, int family, TruffleString addr, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { @@ -869,7 +857,7 @@ static PBytes doConvert(VirtualFrame frame, int family, TruffleString addr, return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); - } catch (PosixSupportLibrary.InvalidAddressException e) { + } catch (PosixSupport.InvalidAddressException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.ILLEGAL_IP_ADDR_STRING_TO_INET_PTON); } } @@ -891,7 +879,6 @@ static TruffleString doGeneric(VirtualFrame frame, int family, Object obj, @CachedLibrary("obj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object buffer = bufferAcquireLib.acquireReadonly(obj, frame, callData); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java index a3c3eafdf5..1ace10234d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java @@ -161,7 +161,7 @@ import com.oracle.graal.python.nodes.statement.AbstractImportNode; import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.ExceptionUtils; @@ -1588,7 +1588,7 @@ static long GraalPyPrivate_GetMMapData(long objectPtr) { PythonContext context = PythonContext.get(null); try { return context.getPosixSupport().mmapGetPointer(object.getPosixSupportHandle()); - } catch (PosixSupportLibrary.UnsupportedPosixFeatureException e) { + } catch (PosixSupport.UnsupportedPosixFeatureException e) { throw PConstructAndRaiseNode.getUncached().raiseOSErrorUnsupported(null, e); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 9faf2f1306..0719aa213a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -154,7 +154,6 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; @@ -172,7 +171,6 @@ import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -504,7 +502,6 @@ abstract static class PyObject_AsFileDescriptor extends CApiUnaryBuiltinNode { static Object asFileDescriptor(Object obj, @Bind Node inliningTarget, @Cached PyLongCheckNode longCheckNode, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached TruffleString.EqualNode eqNode, @Cached PyObjectAsFileDescriptor asFileDescriptorNode, @Cached PRaiseNode raiseNode) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java index 878188e5b0..bc9e122cca 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java @@ -65,7 +65,7 @@ import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.CompilerDirectives; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java index 76dd9cdd65..baf270a634 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java @@ -70,7 +70,7 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index 05715262c0..cce71e3894 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -140,8 +140,7 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -236,7 +235,6 @@ private static void errorCleanup(VirtualFrame frame, PFileIO self, boolean fdIsO private static int open(VirtualFrame frame, TruffleString name, int flags, int mode, PythonContext ctxt, Node inliningTarget, - PosixSupportLibrary posixLib, GilNode gil, InlinedBranchProfile errorProfile, PRaiseNode raiseNode, @@ -314,7 +312,6 @@ public static void internalInit(PFileIO self, TruffleString name, int fd, IOMode @Specialization(guards = {"!isBadMode(mode)", "!isInvalidMode(mode)"}) static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object nameobj, IONodes.IOMode mode, boolean closefd, Object opener, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached(inline = false) CallNode callOpener, @Cached PyIndexCheckNode indexCheckNode, @Cached PyNumberAsSizeNode asSizeNode, @@ -363,7 +360,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object } if (opener instanceof PNone) { - self.setFD(open(frame, name, flags, 0666, context, inliningTarget, posixLib, gil, exceptionProfile, raiseNode, constructAndRaiseNode), context); + self.setFD(open(frame, name, flags, 0666, context, inliningTarget, gil, exceptionProfile, raiseNode, constructAndRaiseNode), context); } else { Object fdobj = callOpener.execute(frame, opener, nameobj, flags); if (!indexCheckNode.execute(inliningTarget, fdobj)) { @@ -400,7 +397,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object * On Unix, open will succeed for directories. In Python, there should be no * file objects referring to directories, so we need a check. */ - if (errorProfile.profile(inliningTarget, PosixSupportLibrary.isDIR(fstatResult[0]))) { + if (errorProfile.profile(inliningTarget, PosixSupport.isDIR(fstatResult[0]))) { errorCleanup(frame, self, fdIsOwn, posixClose); TruffleString fname = name == null ? fromLongNode.execute(fd, TS_ENCODING, false) : name; throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, OSErrorEnum.EISDIR, fname); @@ -663,7 +660,6 @@ static Object readinto(VirtualFrame frame, PFileIO self, Object buffer, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Cached InlinedBranchProfile readErrorProfile, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java index df6bd57b7b..41e3b9a33f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java @@ -44,8 +44,7 @@ import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.AsyncHandler.SharedFinalizer.FinalizableReference; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.object.Shape; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java index d507e6c635..dcd8cef20e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java @@ -79,8 +79,8 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java index f7b3550d6f..6523a0c20b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java @@ -60,8 +60,7 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -89,7 +88,6 @@ abstract static class Recv extends PythonBinaryClinicBuiltinNode { PBytes doit(VirtualFrame frame, int handle, int size, @Bind PythonContext context, @Bind PythonLanguage language, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] buffer = new byte[size]; @@ -121,7 +119,6 @@ abstract static class Send extends PythonBinaryClinicBuiltinNode { static int doit(VirtualFrame frame, int handle, Object buffer, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -170,7 +167,6 @@ abstract static class SemUnlink extends PythonUnaryBuiltinNode { @Specialization PNone doit(VirtualFrame frame, TruffleString name, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java index b7a0f8c510..289d9ac5dd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java @@ -77,9 +77,8 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -87,7 +86,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -120,7 +118,6 @@ abstract static class SemLockNode extends PythonClinicBuiltinNode { static PSemLock construct(VirtualFrame frame, Object cls, int kind, int value, int maxValue, TruffleString name, boolean unlink, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -418,7 +415,6 @@ abstract static class RebuildNode extends PythonClinicBuiltinNode { static Object rebuild(VirtualFrame frame, Object cls, long origHandle, int kind, int maxValue, Object name, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index 50ad524b15..86fbf6dfb0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -65,7 +65,7 @@ import static com.oracle.graal.python.runtime.PosixConstants.MAP_SHARED; import static com.oracle.graal.python.runtime.PosixConstants.PROT_READ; import static com.oracle.graal.python.runtime.PosixConstants.PROT_WRITE; -import static com.oracle.graal.python.runtime.PosixSupportLibrary.ST_SIZE; +import static com.oracle.graal.python.runtime.PosixSupport.ST_SIZE; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -134,7 +134,7 @@ import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.nativeaccess.NativeAccessSupport; import com.oracle.graal.python.runtime.nativeaccess.NativeContext; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java index 990483a1d1..fa45827226 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java @@ -50,8 +50,7 @@ import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.NativePosixSupport; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -225,7 +224,7 @@ boolean isNative( long getNativePointer(@Bind Node inliningTarget) { try { return PythonContext.get(inliningTarget).getPosixSupport().mmapGetPointer(getPosixSupportHandle()); - } catch (PosixSupportLibrary.UnsupportedPosixFeatureException e) { + } catch (PosixSupport.UnsupportedPosixFeatureException e) { return NULLPTR; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java index 9a513ee0f0..94c84a1156 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java @@ -80,8 +80,7 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; @@ -94,7 +93,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -116,7 +114,6 @@ abstract static class NameNode extends PythonUnaryBuiltinNode { static Object nameAsBytes(VirtualFrame frame, PDirEntry self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile produceBytesProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { @@ -158,7 +155,6 @@ static PosixPath cached(PDirEntry self) { @Specialization(guards = "self.pathCache == null") static PosixPath createBytes(VirtualFrame frame, Node inliningTarget, PDirEntry self, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile produceBytesProfile, @Cached InlinedConditionProfile posixPathProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java index 3ab811c013..6933af7dfd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java @@ -46,7 +46,7 @@ import com.oracle.graal.python.runtime.AsyncHandler.AsyncAction; import com.oracle.graal.python.runtime.AsyncHandler.SharedFinalizer; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.object.Shape; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java index c62de55eea..e4f7e136db 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java @@ -61,7 +61,7 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.runtime.AsyncHandler.AsyncAction; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.ThreadLocalAction.Access; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java index f2634ee309..97bec5dc30 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java @@ -72,8 +72,7 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -85,7 +84,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.library.CachedLibrary; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index 277c96fec0..30a2474890 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -97,11 +97,10 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.RecvfromResult; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -171,7 +170,6 @@ public abstract static class InitNode extends PythonClinicBuiltinNode { @Specialization static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, int protoIn, @SuppressWarnings("unused") PNone fileno, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @@ -221,7 +219,6 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i @Specialization(guards = "!isPNone(fileno)") static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, int protoIn, Object fileno, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PyLongAsIntNode asIntNode, @@ -310,7 +307,6 @@ abstract static class AcceptNode extends PythonUnaryBuiltinNode { static Object accept(VirtualFrame frame, PSocket self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -319,7 +315,7 @@ static Object accept(VirtualFrame frame, PSocket self, try { PosixSupport posixSupport = context.getPosixSupport(); - PosixSupportLibrary.AcceptResult acceptResult = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, self, + PosixSupport.AcceptResult acceptResult = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, self, s -> s.accept(self.getFd()), false, false); try { @@ -409,7 +405,6 @@ abstract static class ConnectNode extends PythonBinaryBuiltinNode { @Specialization static Object connect(VirtualFrame frame, PSocket self, Object address, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @Cached GilNode gil, @@ -420,14 +415,14 @@ static Object connect(VirtualFrame frame, PSocket self, Object address, auditNode.audit(frame, inliningTarget, T_SOCKET_CONNECT, self, address); try { - doConnect(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, self, connectAddr); + doConnect(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, self, connectAddr); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } return PNone.NONE; } - static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, PosixSupport posixSupport, GilNode gil, PSocket self, + static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupport posixSupport, GilNode gil, PSocket self, UniversalSockAddr connectAddr) throws PosixException { try { gil.release(true); @@ -470,7 +465,6 @@ abstract static class ConnectExNode extends PythonBinaryBuiltinNode { @Specialization static Object connectEx(VirtualFrame frame, PSocket self, Object address, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @Cached GilNode gil, @@ -481,7 +475,7 @@ static Object connectEx(VirtualFrame frame, PSocket self, Object address, auditNode.audit(frame, inliningTarget, T_SOCKET_CONNECT, self, address); // sic! connect try { - ConnectNode.doConnect(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, self, connectAddr); + ConnectNode.doConnect(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, self, connectAddr); } catch (PosixException e) { if (e instanceof PosixErrnoException errnoException) { return errnoException.getErrorCode(); @@ -500,7 +494,6 @@ abstract static class GetPeerNameNode extends PythonUnaryBuiltinNode { static Object get(VirtualFrame frame, PSocket socket, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -527,7 +520,6 @@ abstract static class GetSockNameNode extends PythonUnaryBuiltinNode { static Object get(VirtualFrame frame, PSocket socket, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -579,7 +571,6 @@ abstract static class ListenNode extends PythonBinaryClinicBuiltinNode { static Object listen(VirtualFrame frame, PSocket self, int backlogIn, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int backlog = backlogIn; @@ -615,7 +606,6 @@ abstract static class RecvNode extends PythonTernaryClinicBuiltinNode { static Object recv(VirtualFrame frame, PSocket socket, int recvlen, int flags, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -665,7 +655,6 @@ abstract static class RecvFromNode extends PythonTernaryClinicBuiltinNode { static Object recvFrom(VirtualFrame frame, PSocket socket, int recvlen, int flags, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -719,7 +708,6 @@ static Object recvInto(VirtualFrame frame, PSocket socket, Object bufferObj, int @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -787,7 +775,6 @@ static Object recvFromInto(VirtualFrame frame, PSocket socket, Object bufferObj, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -854,7 +841,6 @@ static int send(VirtualFrame frame, PSocket socket, Object bufferObj, int flags, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -895,7 +881,6 @@ static Object sendAll(VirtualFrame frame, PSocket socket, Object bufferObj, int @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -954,7 +939,6 @@ static Object sendTo(VirtualFrame frame, PSocket socket, Object bufferObj, Objec @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile hasFlagsProfile, @Cached PyLongAsIntNode asIntNode, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @@ -1049,7 +1033,6 @@ abstract static class ShutdownNode extends PythonBinaryClinicBuiltinNode { static Object shutdown(VirtualFrame frame, PSocket socket, int how, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { context.getPosixSupport().shutdown(socket.getFd(), how); @@ -1126,7 +1109,6 @@ abstract static class SetSockOptNode extends PythonClinicBuiltinNode { static Object setInt(VirtualFrame frame, PSocket socket, int level, int option, Object value, @SuppressWarnings("unused") PNone none, @Bind PythonContext context, @Cached("createFor($node)") InteropCallData callData, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @CachedLibrary(limit = "3") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Bind Node inliningTarget, @@ -1160,7 +1142,6 @@ static Object setInt(VirtualFrame frame, PSocket socket, int level, int option, @Specialization(guards = "isNone(none)") static Object setNull(VirtualFrame frame, PSocket socket, int level, int option, @SuppressWarnings("unused") PNone none, Object buflenObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Exclusive @Cached PyLongAsIntNode asIntNode, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -1201,7 +1182,6 @@ abstract static class GetSockOptNode extends PythonQuaternaryClinicBuiltinNode { static Object getSockOpt(VirtualFrame frame, PSocket socket, int level, int option, int buflen, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index 0e1f3951ad..1fc12e6d09 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -86,17 +86,16 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import com.oracle.graal.python.runtime.PosixSupport.AddrInfoCursor; +import com.oracle.graal.python.runtime.PosixSupport.GetAddrInfoException; +import com.oracle.graal.python.runtime.PosixSupport.Inet4SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.Inet6SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.InvalidAddressException; +import com.oracle.graal.python.runtime.PosixSupport.InvalidUnixSocketPathException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.UnixSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -127,7 +126,6 @@ public abstract static class GetSockAddrArgNode extends Node { @Specialization(guards = "isInet(socket)") static UniversalSockAddr doInet(VirtualFrame frame, @SuppressWarnings("unused") PSocket socket, Object address, String caller, @Bind Node inliningTarget, - @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, @Shared("tupleCheck") @Cached PyTupleCheckNode tupleCheckNode, @Cached @Shared("tupleSize") PyTupleSizeNode tupleSize, @Cached @Shared("tupleGetItem") PyTupleGetItem tupleGetItem, @@ -154,7 +152,6 @@ static UniversalSockAddr doInet(VirtualFrame frame, @SuppressWarnings("unused") @Specialization(guards = "isInet6(socket)") static UniversalSockAddr doInet6(VirtualFrame frame, @SuppressWarnings("unused") PSocket socket, Object address, String caller, @Bind Node inliningTarget, - @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, @Shared("tupleCheck") @Cached PyTupleCheckNode tupleCheckNode, @Cached @Shared("tupleSize") PyTupleSizeNode tupleSize, @Cached @Shared("tupleGetItem") PyTupleGetItem tupleGetItem, @@ -198,7 +195,6 @@ static UniversalSockAddr doUnix(VirtualFrame frame, @SuppressWarnings("unused") @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode, @CachedLibrary(limit = "1") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { byte[] path; if (unicodeCheckNode.execute(inliningTarget, address)) { @@ -275,7 +271,6 @@ public abstract static class SetIpAddrNode extends Node { @Specialization static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @Bind Node inliningTarget, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached InetPtoNCachedPNode inetPtoNCachedPNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached GilNode gil, @@ -311,7 +306,7 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, /* avoid a name resolution in case of numeric address */ /* check for an IPv4 address */ if (family == AF_INET.value || family == AF_UNSPEC.value) { - byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixLib, posixSupport, AF_INET.value, name); + byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixSupport, AF_INET.value, name); if (bytes != null) { return posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(0, bytes)); } @@ -322,7 +317,7 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, * index */ if ((family == AF_INET6.value || family == AF_UNSPEC.value) && !hasScopeId(inliningTarget, name)) { - byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixLib, posixSupport, AF_INET6.value, name); + byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixSupport, AF_INET6.value, name); if (bytes != null) { return posixSupport.createUniversalSockAddrInet6(new Inet6SockAddr(0, bytes, 0, 0)); } @@ -352,19 +347,19 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @GenerateCached(false) @ImportStatic(Arrays.class) abstract static class InetPtoNCachedPNode extends Node { - abstract byte[] execute(Node inliningTarget, PosixSupportLibrary posixLib, PosixSupport posixSupport, int family, byte[] string); + abstract byte[] execute(Node inliningTarget, PosixSupport posixSupport, int family, byte[] string); @Specialization(guards = {"family == cachedFamily", "equals(string, cachedString)"}, limit = "3") @SuppressWarnings("unused") - static byte[] cached(PosixSupportLibrary posixLib, PosixSupport posixSupport, int family, byte[] string, + static byte[] cached(PosixSupport posixSupport, int family, byte[] string, @Cached("family") int cachedFamily, @Cached(value = "string", dimensions = 1) byte[] cachedString, - @Cached(value = "doParse(posixLib, posixSupport, family, string)", dimensions = 1) byte[] cachedResult) { + @Cached(value = "doParse(posixSupport, family, string)", dimensions = 1) byte[] cachedResult) { return cachedResult; } @Specialization(replaces = "cached") - static byte[] doParse(PosixSupportLibrary posixLib, PosixSupport posixSupport, int family, byte[] string) { + static byte[] doParse(PosixSupport posixSupport, int family, byte[] string) { assert family == AF_INET.value || family == AF_INET6.value; try { return posixSupport.inet_pton(family, posixSupport.createCStringFromBytes(string)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java index d26dc88a35..c0bb455c1e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java @@ -51,10 +51,10 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.SelectResult; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.util.TimeUtils; import com.oracle.truffle.api.frame.Frame; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java index 722bbca2b5..44aa301295 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java @@ -60,8 +60,7 @@ import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.util.OverflowException; @@ -73,7 +72,6 @@ import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; /** @@ -171,7 +169,6 @@ protected enum SSLOperation { @Specialization(guards = "socket.getSocket() != null") static void doSocket(VirtualFrame frame, Node inliningTarget, PSSLSocket socket, ByteBuffer appInput, ByteBuffer targetBuffer, SSLOperation operation, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached(inline = false) GilNode gil, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Shared @Cached PRaiseNode raiseNode) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java index 1be0aad2b2..565ba7cca7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java @@ -56,9 +56,9 @@ import com.oracle.graal.python.builtins.objects.ssl.SSLErrorCode; import com.oracle.graal.python.nodes.PConstructAndRaiseNodeGen.LazyNodeGen; import com.oracle.graal.python.nodes.call.CallNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.formatting.ErrorMessageFormatter; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index c47ccfbd32..3fb5f6c6bc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -229,25 +229,6 @@ import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.OperationWouldBlockException; import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNodeGen; import com.oracle.graal.python.nodes.ErrorMessages; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.ChannelNotSelectableException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.exception.PythonExitException; import com.oracle.graal.python.util.FileDeleteShutdownHook; import com.oracle.graal.python.util.IPAddressUtil; @@ -262,19 +243,10 @@ import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.TruffleOptions; import com.oracle.truffle.api.TruffleSafepoint; -import com.oracle.truffle.api.dsl.Bind; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Exclusive; -import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.io.TruffleProcessBuilder; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.library.ExportLibrary; -import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.library.ExportMessage.Ignore; import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; import com.sun.security.auth.UnixNumericGroupPrincipal; import com.sun.security.auth.module.UnixSystem; @@ -306,7 +278,6 @@ *
  • {@code select} supports only network sockets, but not regular files.
  • * */ -@ExportLibrary(PosixSupportLibrary.class) @SuppressWarnings("unused") public final class EmulatedPosixSupport extends PosixResources { @@ -380,7 +351,6 @@ public void setEnv(Env env) { } @Override - @ExportMessage @TruffleBoundary public TruffleString getBackend() { return T_JAVA; @@ -410,6 +380,7 @@ private long determinePid() { } @Override + @TruffleBoundary public long getpid() { if (pidInitialized) { return pid; @@ -418,6 +389,7 @@ public long getpid() { } @Override + @TruffleBoundary public int umask(int umask) { int prev = currentUmask; currentUmask = umask & 00777; @@ -429,6 +401,7 @@ public int umask(int umask) { } @Override + @TruffleBoundary public TruffleString strerror(int errorCode) { OSErrorEnum err = OSErrorEnum.fromNumber(errorCode); if (err == null) { @@ -438,6 +411,7 @@ public TruffleString strerror(int errorCode) { } @Override + @TruffleBoundary public int close(int fd) throws PosixException { try { if (!removeFD(fd)) { @@ -485,6 +459,7 @@ private int openTruffleFile(TruffleFile truffleFile, Set opt } @Override + @TruffleBoundary public long write(int fd, Buffer data) throws PosixException { Channel channel = getFileChannel(fd); if (!(channel instanceof WritableByteChannel)) { @@ -515,6 +490,7 @@ private static int doWriteOp(ByteBuffer data, WritableByteChannel channel) throw } @Override + @TruffleBoundary public Buffer read(int fd, long length) throws PosixException { Channel channel = getFileChannel(fd); if (!(channel instanceof ReadableByteChannel)) { @@ -549,12 +525,14 @@ private static Buffer readBytesFromChannel(ReadableByteChannel channel, long siz } @Override + @TruffleBoundary public int dup(int fd) { // TODO: will disappear once the super class is merged with this class return super.dup(fd); } @Override + @TruffleBoundary public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable) throws PosixException { // TODO: will merge with super.dup2 once the super class is merged with this class try { @@ -565,29 +543,34 @@ public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable } @Override + @TruffleBoundary public boolean getInheritable(int fd) { compatibilityIgnored("getting inheritable for file descriptor %d in POSIX emulation layer (not supported, always returns false)", fd); return false; } @Override + @TruffleBoundary public void setInheritable(int fd, boolean inheritable) { compatibilityIgnored("setting inheritable '%b' for file descriptor %d in POSIX emulation layer (not supported)", inheritable, fd); } @Override @SuppressWarnings("static-method") + @TruffleBoundary public long getOsfHandle(int fd) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("get_osfhandle"); } @Override @SuppressWarnings("static-method") + @TruffleBoundary public int openOsfHandle(long handle, int flags) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("open_osfhandle"); } @Override + @TruffleBoundary public int setMode(int fd, int mode) throws PosixException { int binary = PosixConstants.O_BINARY.getValueIfDefined(); int text = PosixConstants.O_TEXT.getValueIfDefined(); @@ -602,6 +585,7 @@ public int setMode(int fd, int mode) throws PosixException { } @Override + @TruffleBoundary public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { @@ -617,6 +601,7 @@ public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { } @Override + @TruffleBoundary public int[] pipe() throws PosixException { try { return super.pipeResource(); @@ -903,6 +888,7 @@ private static long setPosition(long pos, int how, SeekableByteChannel fc) throw } @Override + @TruffleBoundary public void ftruncate(int fd, long length) throws PosixException { Object ret; try { @@ -916,6 +902,7 @@ public void ftruncate(int fd, long length) throws PosixException { } @Override + @TruffleBoundary public void truncate(Object path, long length) throws PosixException { TruffleFile file = getTruffleFile(pathToJavaString(path)); try { @@ -933,6 +920,7 @@ private static void doTruncate(TruffleFile file, long length) throws IOException } @Override + @TruffleBoundary public void fsync(int fd) throws PosixException { if (!hasFsyncResource(fd)) { throw posixException(OSErrorEnum.ENOENT); @@ -940,6 +928,7 @@ public void fsync(int fd) throws PosixException { } @Override + @TruffleBoundary public void flock(int fd, int operation) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { @@ -956,6 +945,7 @@ public void flock(int fd, int operation) throws PosixException { } @Override + @TruffleBoundary public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { @@ -1424,6 +1414,7 @@ private static int posixPermissionsToMode(int inputMode, final SetFINEST - supporting messages (e.g. path conversions) + top 5 frames of the call stack * */ -@ExportLibrary(PosixSupportLibrary.class) public class LoggingPosixSupport extends PosixSupport { private static final TruffleLogger LOGGER = PythonLanguage.getLogger(LoggingPosixSupport.class); @@ -120,7 +97,6 @@ public void setEnv(Env env) { } @Override - @ExportMessage @TruffleBoundary public final TruffleString getBackend() { logEnter(Level.FINEST, "getBackend", ""); @@ -128,18 +104,21 @@ public final TruffleString getBackend() { } @Override + @TruffleBoundary public final TruffleString strerror(int errorCode) { logEnter(Level.FINEST, "strerror", "%d", errorCode); return logExit(Level.FINEST, "strerror", "%s", delegate.strerror(errorCode)); } @Override + @TruffleBoundary public final long getpid() { logEnter("getpid", ""); return logExit("getpid", "%d", delegate.getpid()); } @Override + @TruffleBoundary public final int umask(int mask) throws PosixException { logEnter("umask", "0%o", mask); try { @@ -150,6 +129,7 @@ public final int umask(int mask) throws PosixException { } @Override + @TruffleBoundary public final int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { logEnter("openAt", "%d, %s, 0x%x, 0%o", dirFd, pathname, flags, mode); try { @@ -160,6 +140,7 @@ public final int openat(int dirFd, Object pathname, int flags, int mode) throws } @Override + @TruffleBoundary public final int close(int fd) throws PosixException { logEnter("close", "%d", fd); try { @@ -170,6 +151,7 @@ public final int close(int fd) throws PosixException { } @Override + @TruffleBoundary public final Buffer read(int fd, long length) throws PosixException { logEnter("read", "%d, %d", fd, length); try { @@ -182,6 +164,7 @@ public final Buffer read(int fd, long length) throws PosixException { } @Override + @TruffleBoundary public final long write(int fd, Buffer data) throws PosixException { logEnter("write", "%d, %d", fd, data.length); try { @@ -210,6 +193,7 @@ public final long writeWindowsConsole(int fd, Buffer data) throws PosixException } @Override + @TruffleBoundary public final int dup(int fd) throws PosixException { logEnter("dup", "%d", fd); try { @@ -220,6 +204,7 @@ public final int dup(int fd) throws PosixException { } @Override + @TruffleBoundary public final int dup2(int fd, int fd2, boolean inheritable) throws PosixException { logEnter("dup2", "%d, %d, %b", fd, fd2, inheritable); try { @@ -230,6 +215,7 @@ public final int dup2(int fd, int fd2, boolean inheritable) throws PosixExceptio } @Override + @TruffleBoundary public final boolean getInheritable(int fd) throws PosixException { logEnter("getInheritable", "%d", fd); try { @@ -240,6 +226,7 @@ public final boolean getInheritable(int fd) throws PosixException { } @Override + @TruffleBoundary public final void setInheritable(int fd, boolean inheritable) throws PosixException { logEnter("setInheritable", "%d, %b", fd, inheritable); try { @@ -250,6 +237,7 @@ public final void setInheritable(int fd, boolean inheritable) throws PosixExcept } @Override + @TruffleBoundary public final long getOsfHandle(int fd) throws PosixException { logEnter("getOsfHandle", "%d", fd); try { @@ -260,6 +248,7 @@ public final long getOsfHandle(int fd) throws PosixException { } @Override + @TruffleBoundary public final int openOsfHandle(long handle, int flags) throws PosixException { logEnter("openOsfHandle", "%d, %d", handle, flags); try { @@ -270,6 +259,7 @@ public final int openOsfHandle(long handle, int flags) throws PosixException { } @Override + @TruffleBoundary public final int setMode(int fd, int mode) throws PosixException { logEnter("setMode", "%d, %d", fd, mode); try { @@ -280,6 +270,7 @@ public final int setMode(int fd, int mode) throws PosixException { } @Override + @TruffleBoundary public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { logEnter("msvcrtLocking", "%d, %d, %d", fd, mode, nbytes); try { @@ -290,6 +281,7 @@ public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixExcep } @Override + @TruffleBoundary public final int[] pipe() throws PosixException { logEnter("pipe", ""); try { @@ -300,6 +292,7 @@ public final int[] pipe() throws PosixException { } @Override + @TruffleBoundary public final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { logEnter("select", "%s %s %s %s", readfds, writefds, errorfds, timeout); try { @@ -310,6 +303,7 @@ public final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, } @Override + @TruffleBoundary public final void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { logEnter("poll", "%s %s %s", fds, events, timeout); try { @@ -321,6 +315,7 @@ public final void poll(int[] fds, int[] events, int[] revents, int timeout) thro } @Override + @TruffleBoundary public final long lseek(int fd, long offset, int how) throws PosixException { logEnter("lseek", "%d, %d, %d", fd, offset, how); try { @@ -331,6 +326,7 @@ public final long lseek(int fd, long offset, int how) throws PosixException { } @Override + @TruffleBoundary public final void ftruncate(int fd, long length) throws PosixException { logEnter("ftruncate", "%d, %d", fd, length); try { @@ -341,6 +337,7 @@ public final void ftruncate(int fd, long length) throws PosixException { } @Override + @TruffleBoundary public final void truncate(Object path, long length) throws PosixException { logEnter("truncate", "%s, %d", path, length); try { @@ -351,6 +348,7 @@ public final void truncate(Object path, long length) throws PosixException { } @Override + @TruffleBoundary public final void fsync(int fd) throws PosixException { logEnter("fsync", "%d", fd); try { @@ -361,6 +359,7 @@ public final void fsync(int fd) throws PosixException { } @Override + @TruffleBoundary public final void flock(int fd, int operation) throws PosixException { logEnter("flock", "%d %d", fd, operation); try { @@ -371,6 +370,7 @@ public final void flock(int fd, int operation) throws PosixException { } @Override + @TruffleBoundary public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { logEnter("fcntlLock", "%d %s %d %d %d %d", fd, blocking, lockType, whence, start, length); try { @@ -381,6 +381,7 @@ public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, } @Override + @TruffleBoundary public final boolean getBlocking(int fd) throws PosixException { logEnter("getBlocking", "%d", fd); try { @@ -391,6 +392,7 @@ public final boolean getBlocking(int fd) throws PosixException { } @Override + @TruffleBoundary public final void setBlocking(int fd, boolean blocking) throws PosixException { logEnter("setBlocking", "%d, %b", fd, blocking); try { @@ -401,6 +403,7 @@ public final void setBlocking(int fd, boolean blocking) throws PosixException { } @Override + @TruffleBoundary public final int[] getTerminalSize(int fd) throws PosixException { logEnter("getTerminalSize", "%d", fd); try { @@ -411,6 +414,7 @@ public final int[] getTerminalSize(int fd) throws PosixException { } @Override + @TruffleBoundary public final long sysconf(int name) throws PosixException { logEnter("sysconf", "%d", name); try { @@ -465,6 +469,7 @@ public final long[] fstatvfs(int fd) throws PosixException { } @Override + @TruffleBoundary public final Object[] uname() throws PosixException { logEnter("uname", ""); try { @@ -793,6 +798,7 @@ public final void fchown(int fd, long owner, long group) throws PosixException { } @Override + @TruffleBoundary public final Object readlinkat(int dirFd, Object path) throws PosixException { logEnter("readlinkat", "%d, %s", dirFd, path); try { @@ -991,7 +997,7 @@ public final long getuid() { public final long geteuid() throws UnsupportedPosixFeatureException { logEnter("geteuid", ""); try { - return logExit("geteuid", "%d", delegate.geteuid()); + return logExit("geteuid", "%d", delegate.geteuid()); } catch (UnsupportedPosixFeatureException e) { throw logException("geteuid", e); } @@ -1009,7 +1015,7 @@ public final long getgid() { public final long getegid() throws UnsupportedPosixFeatureException { logEnter("getegid", ""); try { - return logExit("getegid", "%d", delegate.getegid()); + return logExit("getegid", "%d", delegate.getegid()); } catch (UnsupportedPosixFeatureException e) { throw logException("getegid", e); } @@ -1171,7 +1177,8 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) th @Override @TruffleBoundary - public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, + public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, + int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { logEnter("forkExec", "%s, %s, %s, %s, %d, %d, %d, %d, %d, %d, %d, %d, %b, %b, %b, %d, %s, %b", executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 3f8e2f5bde..b03e091c84 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -78,7 +78,6 @@ import static com.oracle.graal.python.runtime.PosixConstants.PATH_MAX; import static com.oracle.graal.python.runtime.PosixConstants.WNOHANG; import static com.oracle.graal.python.runtime.PosixConstants._POSIX_HOST_NAME_MAX; -import static com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR_BE; @@ -103,24 +102,6 @@ import com.oracle.graal.python.lib.PyUnicodeFSDecoderNode; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.call.CallNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary; import com.oracle.graal.python.runtime.nativeaccess.NativeLibraryLoadException; @@ -136,13 +117,7 @@ import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.TruffleSafepoint; -import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Exclusive; -import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.library.ExportLibrary; -import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.AbstractTruffleString; import com.oracle.truffle.api.strings.InternalByteArray; @@ -159,7 +134,6 @@ * functions store errno in a C thread-local only when the POSIX return value indicates an error. This * avoids unconditional FFM call-state capture on the hot POSIX path. */ -@ExportLibrary(PosixSupportLibrary.class) public final class NativePosixSupport extends PosixSupport { private static final String SUPPORTING_NATIVE_LIB_NAME = "posix"; private static final int UNAME_BUF_LENGTH = 256; @@ -711,13 +685,13 @@ public void setEnv(Env env) { } @Override - @ExportMessage @TruffleBoundary public TruffleString getBackend() { return nativeBackend; } @Override + @TruffleBoundary public TruffleString strerror(int errorCode) { // From man pages: The GNU C Library uses a buffer of 1024 characters for strerror(). // This buffer size therefore should be sufficient to avoid an ERANGE error when calling @@ -735,16 +709,19 @@ public TruffleString strerror(int errorCode) { } @Override + @TruffleBoundary public long getpid() { return posixNativeFunctionInvoker.call_getpid(); } @Override + @TruffleBoundary public int umask(int mask) { return posixNativeFunctionInvoker.call_umask(mask); } @Override + @TruffleBoundary public int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { long pathnamePtr = pathToNativeCString(pathname); try { @@ -759,6 +736,7 @@ public int openat(int dirFd, Object pathname, int flags, int mode) throws PosixE } @Override + @TruffleBoundary public int close(int fd) throws PosixException { final int rv = posixNativeFunctionInvoker.call_close(fd); if (rv < 0) { @@ -768,6 +746,7 @@ public int close(int fd) throws PosixException { } @Override + @TruffleBoundary public Buffer read(int fd, long length) throws PosixException { long count = Math.min(length, MAX_READ); Buffer buffer = Buffer.allocate(count); @@ -785,6 +764,7 @@ public Buffer read(int fd, long length) throws PosixException { } @Override + @TruffleBoundary public long write(int fd, Buffer data) throws PosixException { long nativeBuffer = NativeMemory.mallocByteArrayOrNull(data.length); try { @@ -822,6 +802,7 @@ public long writeWindowsConsole(int fd, Buffer data) throws PosixException { } @Override + @TruffleBoundary public int dup(int fd) throws PosixException { int newFd = posixNativeFunctionInvoker.call_dup(fd); if (newFd < 0) { @@ -831,6 +812,7 @@ public int dup(int fd) throws PosixException { } @Override + @TruffleBoundary public int dup2(int fd, int fd2, boolean inheritable) throws PosixException { int newFd = posixNativeFunctionInvoker.call_dup2(fd, fd2, inheritable ? 1 : 0); if (newFd < 0) { @@ -840,6 +822,7 @@ public int dup2(int fd, int fd2, boolean inheritable) throws PosixException { } @Override + @TruffleBoundary public boolean getInheritable(int fd) throws PosixException { int result = posixNativeFunctionInvoker.get_inheritable(fd); if (result < 0) { @@ -849,6 +832,7 @@ public boolean getInheritable(int fd) throws PosixException { } @Override + @TruffleBoundary public void setInheritable(int fd, boolean inheritable) throws PosixException { if (posixNativeFunctionInvoker.set_inheritable(fd, inheritable ? 1 : 0) < 0) { throw getErrnoAndThrowPosixException(); @@ -856,6 +840,7 @@ public void setInheritable(int fd, boolean inheritable) throws PosixException { } @Override + @TruffleBoundary public long getOsfHandle(int fd) throws PosixException { long nativeOut = NativeMemory.mallocLongArray(1); try { @@ -869,6 +854,7 @@ public long getOsfHandle(int fd) throws PosixException { } @Override + @TruffleBoundary public int openOsfHandle(long handle, int flags) throws PosixException { int fd = posixNativeFunctionInvoker.call_open_osfhandle(handle, flags); if (fd < 0) { @@ -878,6 +864,7 @@ public int openOsfHandle(long handle, int flags) throws PosixException { } @Override + @TruffleBoundary public int setMode(int fd, int mode) throws PosixException { int previousMode = posixNativeFunctionInvoker.call_setmode(fd, mode); if (previousMode < 0) { @@ -887,6 +874,7 @@ public int setMode(int fd, int mode) throws PosixException { } @Override + @TruffleBoundary public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { if (posixNativeFunctionInvoker.call_msvcrt_locking(fd, mode, nbytes) != 0) { throw getErrnoAndThrowPosixException(); @@ -894,6 +882,7 @@ public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { } @Override + @TruffleBoundary public int[] pipe() throws PosixException { int[] fds = new int[2]; long nativeFds = NativeMemory.mallocIntArray(fds.length); @@ -909,6 +898,7 @@ public int[] pipe() throws PosixException { } @Override + @TruffleBoundary public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { int largestFD = findMax(readfds, -1); largestFD = findMax(writefds, largestFD); @@ -975,6 +965,7 @@ private static int findMax(int[] items, int currentMax) { } @Override + @TruffleBoundary public void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { assert fds.length == events.length && fds.length == revents.length; int count = fds.length; @@ -1006,6 +997,7 @@ public void poll(int[] fds, int[] events, int[] revents, int timeout) throws Pos } @Override + @TruffleBoundary public long lseek(int fd, long offset, int how) throws PosixException { long res = posixNativeFunctionInvoker.call_lseek(fd, offset, how); if (res < 0) { @@ -1015,6 +1007,7 @@ public long lseek(int fd, long offset, int how) throws PosixException { } @Override + @TruffleBoundary public void ftruncate(int fd, long length) throws PosixException { int res = posixNativeFunctionInvoker.call_ftruncate(fd, length); if (res != 0) { @@ -1023,6 +1016,7 @@ public void ftruncate(int fd, long length) throws PosixException { } @Override + @TruffleBoundary public void truncate(Object path, long length) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1036,6 +1030,7 @@ public void truncate(Object path, long length) throws PosixException { } @Override + @TruffleBoundary public void fsync(int fd) throws PosixException { int res = posixNativeFunctionInvoker.call_fsync(fd); if (res != 0) { @@ -1044,6 +1039,7 @@ public void fsync(int fd) throws PosixException { } @Override + @TruffleBoundary public void flock(int fd, int operation) throws PosixException { int res = posixNativeFunctionInvoker.call_flock(fd, operation); if (res != 0) { @@ -1052,6 +1048,7 @@ public void flock(int fd, int operation) throws PosixException { } @Override + @TruffleBoundary public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { int res = posixNativeFunctionInvoker.call_fcntl_lock(fd, blocking ? 1 : 0, lockType, whence, start, length); if (res != 0) { @@ -1060,6 +1057,7 @@ public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long s } @Override + @TruffleBoundary public boolean getBlocking(int fd) throws PosixException { int result = posixNativeFunctionInvoker.get_blocking(fd); if (result < 0) { @@ -1069,6 +1067,7 @@ public boolean getBlocking(int fd) throws PosixException { } @Override + @TruffleBoundary public void setBlocking(int fd, boolean blocking) throws PosixException { if (posixNativeFunctionInvoker.set_blocking(fd, blocking ? 1 : 0) < 0) { throw getErrnoAndThrowPosixException(); @@ -1076,6 +1075,7 @@ public void setBlocking(int fd, boolean blocking) throws PosixException { } @Override + @TruffleBoundary public int[] getTerminalSize(int fd) throws PosixException { int[] size = new int[2]; long nativeSize = NativeMemory.mallocIntArray(size.length); @@ -1091,6 +1091,7 @@ public int[] getTerminalSize(int fd) throws PosixException { } @Override + @TruffleBoundary public long sysconf(int name) throws PosixException { long result = posixNativeFunctionInvoker.call_sysconf(name); if (result == Long.MIN_VALUE) { @@ -1176,6 +1177,7 @@ public long[] fstatvfs(int fd) throws PosixException { } @Override + @TruffleBoundary public Object[] uname() throws PosixException { long sysPtr = NULLPTR; long nodePtr = NULLPTR; @@ -1654,6 +1656,7 @@ public void fchown(int fd, long owner, long group) throws PosixException { } @Override + @TruffleBoundary public Object readlinkat(int dirFd, Object path) throws PosixException { int bufferBytes = WINDOWS ? PATH_MAX.value * 2 : PATH_MAX.value; byte[] buffer = new byte[bufferBytes]; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index b771ae6e65..3fbbe446e5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -40,24 +40,25 @@ */ package com.oracle.graal.python.runtime; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; +import static com.oracle.graal.python.runtime.PosixConstants.AF_INET; +import static com.oracle.graal.python.runtime.PosixConstants.AF_INET6; +import static com.oracle.graal.python.runtime.PosixConstants.AF_UNIX; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFBLK; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFCHR; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFDIR; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFIFO; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFLNK; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFMT; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFREG; +import java.nio.ByteBuffer; +import java.util.Arrays; +import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; +import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.CompilerDirectives.ValueType; +import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -66,7 +67,593 @@ public abstract class PosixSupport { public static final int ST_MODE = 0; - public static abstract class Path { + public static final char POSIX_FILENAME_SEPARATOR = '/'; + + // Constants for accessing the fields of the fstat result: + // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants + public static final int ST_SIZE = 6; + + /** + * Equivalent to struct r_usage with the fields expected on macOS and Linux. + * + * @param ru_utime time in user mode (fractional seconds) + * @param ru_stime time in system mode (fractional seconds) + * @param ru_maxrss reserved memory size + * @param ru_ixrss shared memory size + * @param ru_idrss unshared memory size + * @param ru_isrss unshared stack size + * @param ru_minflt page faults not requiring I/O + * @param ru_majflt page faults requiring I/O + * @param ru_nswap number of swap outs + * @param ru_inblock block input operations + * @param ru_oublock block output operations + * @param ru_msgsnd messages sent + * @param ru_msgrcv messages received + * @param ru_nsignals signals received + * @param ru_nvcsw voluntary context switches + * @param ru_nivcsw involuntary context switches + */ + public record RusageResult(double ru_utime, double ru_stime, + long ru_maxrss, long ru_ixrss, long ru_idrss, long ru_isrss, + long ru_minflt, long ru_majflt, long ru_nswap, long ru_inblock, long ru_oublock, + long ru_msgsnd, long ru_msgrcv, long ru_nsignals, long ru_nvcsw, long ru_nivcsw) { + } + + public record OpenPtyResult(int masterFd, int slaveFd) { + } + + public static final class PwdResult { + public final TruffleString name; + /** + * This value represents unsigned 64 bit integer. + */ + public final long uid; + /** + * This value represents unsigned 64 bit integer. + */ + public final long gid; + public final TruffleString dir; + public final TruffleString shell; + + public PwdResult(TruffleString name, long uid, long gid, TruffleString dir, TruffleString shell) { + this.name = name; + this.uid = uid; + this.gid = gid; + this.dir = dir; + this.shell = shell; + } + + @Override + public String toString() { + return "PwdResult{name='" + name + '\'' + + ", uid=" + uid + + ", gid=" + gid + + ", dir='" + dir + '\'' + + ", shell='" + shell + "'}"; + } + } + + // region Socket addresses + + /** + * Base class for addresses specific to a particular socket family. + * + * The subclasses are simple POJOs whose definitions are common to all backends. They need to be + * converted to {@code UniversalSockAddr} before use. + */ + public abstract static class FamilySpecificSockAddr { + private final int family; + + protected FamilySpecificSockAddr(int family) { + this.family = family; + } + + public int getFamily() { + return family; + } + } + + /** + * A tagged union of all address types which is capable of holding an address of any socket + * family. + * + * An universal socket address keeps the value in a representation used internally by the given + * backend, therefore implementations of this interface are backend-specific (unlike + * {@link FamilySpecificSockAddr} subclasses). This interface roughly corresponds to POSIX + * {@code struct sockaddr_storage}. + * + */ + public interface UniversalSockAddr { + int getFamily(); + + Inet4SockAddr asInet4SockAddr(); + + Inet6SockAddr asInet6SockAddr(); + + UnixSockAddr asUnixSockAddr(); + } + + /** + * Represents an address for IPv4 sockets (the {@link PosixConstants#AF_INET} socket family). + * + * This is a higher level equivalent of POSIX {@code struct sockaddr_in} - integer values are + * kept in host byte order, conversion to network order ({@code htons/htonl}) is done + * automatically by the backend. This makes the integer representation of address compatible + * with the {@code INADDR_xxx} constants. On the other hand, addresses represented as byte + * arrays are in network order to make them compatible with {@code inet_pton} and + * {@code inet_ntop}). + */ + @ValueType + public static final class Inet4SockAddr extends FamilySpecificSockAddr { + private final int port; // host order, 0 - 65535 + private final int address; // host order, e.g. INADDR_LOOPBACK + + public Inet4SockAddr(int port, int address) { + super(AF_INET.value); + assert port >= 0 && port <= 65535; + this.port = port; + this.address = address; + } + + public Inet4SockAddr(int port, byte[] address) { + this(port, bytesToInt(address)); + } + + public int getPort() { + return port; + } + + public int getAddress() { + return address; + } + + public byte[] getAddressAsBytes() { + return intToBytes(address); + } + + private static int bytesToInt(byte[] src) { + assert src != null && src.length >= 4; + return ByteArraySupport.bigEndian().getInt(src, 0); + } + + private static byte[] intToBytes(int src) { + byte[] dst = new byte[4]; + ByteArraySupport.bigEndian().putInt(dst, 0, src); + return dst; + } + } + + /** + * Represents an address for IPv6 sockets (the {@link PosixConstants#AF_INET6} socket family). + * + * This is a higher level equivalent of POSIX {@code struct sockaddr_in6} - the values are kept + * in host byte order, conversion to network order ({@code htons/htonl}) is done automatically + * by the backend. + */ + @ValueType + public static final class Inet6SockAddr extends FamilySpecificSockAddr { + private final int port; // host order, 0 - 65535 + private final byte[] address = new byte[16]; + private final int flowInfo; // host order, 0 - 2^20-1 + private final int scopeId; // host order, interpreted as unsigned + + public Inet6SockAddr(int port, byte[] address, int flowInfo, int scopeId) { + super(AF_INET6.value); + assert port >= 0 && port <= 65535; + assert address != null && address.length == 16; + assert flowInfo >= 0 && flowInfo <= 1048575; + this.port = port; + PythonUtils.arraycopy(address, 0, this.address, 0, 16); + this.flowInfo = flowInfo; + this.scopeId = scopeId; + } + + public int getPort() { + return port; + } + + public byte[] getAddress() { + return Arrays.copyOf(address, 16); + } + + public int getFlowInfo() { + return flowInfo; + } + + public int getScopeId() { + return scopeId; + } + } + + /** + * Represents an address for UNIX domain sockets (the {@link PosixConstants#AF_UNIX} socket + * family). + * + * This is a higher level equivalent of POSIX {@code struct sockaddr_un}, see + * {@code man -7 unix}. It is the responsibility of the user to ensure that pathname addresses + * are zero terminated and abstract addresses start with a zero. + */ + @ValueType + public static final class UnixSockAddr extends FamilySpecificSockAddr { + private final byte[] path; + + public UnixSockAddr(byte[] path) { + super(AF_UNIX.value); + this.path = path; + } + + /** + * Returns the path, which: + *
      + *
    • for unnamed addresses is of length 0,
    • + *
    • for pathname addresses contains the terminating zero,
    • + *
    • for abstract addresses start with a zero,
    • + *
    • should not be modified by the caller.
    • + *
    + */ + public byte[] getPath() { + return path; + } + } + + // endregion + + public static final class AcceptResult { + public final int socketFd; + public final UniversalSockAddr sockAddr; + + public AcceptResult(int socketFd, UniversalSockAddr sockAddr) { + this.socketFd = socketFd; + this.sockAddr = sockAddr; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "RecvfromResult{" + "socketFd=" + socketFd + ", sockAddr=" + sockAddr + '}'; + } + } + + public static final class RecvfromResult { + public final int readBytes; + public final UniversalSockAddr sockAddr; + + public RecvfromResult(int readBytes, UniversalSockAddr sockAddr) { + this.readBytes = readBytes; + this.sockAddr = sockAddr; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "RecvfromResult{" + "readBytes=" + readBytes + ", sockAddr=" + sockAddr + '}'; + } + } + + // region Name resolution messages + + /** + * Represents one or more addrinfos returned by {@code getaddrinfo()}. + * + * Must be explicitly released using {@link #release()}. + * Behaves like a cursor which points to a {@code struct addrinfo} structure (initially pointing + * at the first address info). The cursor can only move forward using the + * {@link #next()} method. + */ + public interface AddrInfoCursor { + void release(); + + boolean next(); + + int getFlags(); + + int getFamily(); + + int getSockType(); + + int getProtocol(); + + Object getCanonName(); + + UniversalSockAddr getSockAddr(); + } + + /** + * Exception that indicates and error while executing + * {@link PosixSupport#getaddrinfo(Object, Object, int, int, int, int)}. + */ + public static final class GetAddrInfoException extends Exception { + + private static final long serialVersionUID = 3013253817849329391L; + + private final int errorCode; + private final transient TruffleString msg; + + public GetAddrInfoException(int errorCode, TruffleString message) { + super(message.toJavaStringUncached()); + this.errorCode = errorCode; + msg = message; + } + + public int getErrorCode() { + return errorCode; + } + + public final TruffleString getMessageAsTruffleString() { + return msg; + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return this; + } + } + + // endregion + + /** + * Base class for exceptions that originate in the POSIX support layer. + */ + public abstract static class PosixException extends Exception { + + private static final long serialVersionUID = 8700515065120346760L; + + protected PosixException() { + } + + protected PosixException(String message) { + super(message); + } + + public final boolean hasErrno(OSErrorEnum errno) { + return this instanceof PosixErrnoException errnoException && errnoException.getErrorCode() == errno.getNumber(); + } + + @SuppressWarnings("sync-override") + @Override + public Throwable fillInStackTrace() { + return this; + } + } + + /** + * Exception that indicates POSIX level error associated with numeric code. If the message is + * known, it may be included in the exception, otherwise it can be queried using + * {@link PosixSupport#strerror(int)}. + */ + public static final class PosixErrnoException extends PosixException { + + private static final long serialVersionUID = -115762483478883093L; + + private final int errorCode; + private final transient TruffleString msg; + /* + * Windows APIs expose both POSIX errno and a native Win32/Winsock error code. Store the + * native code as java.lang.Integer rather than int because most PosixErrnoException + * instances are not backed by a Windows error, so this field can be null. + */ + private final Integer winerror; + + public PosixErrnoException(int errorCode, TruffleString message) { + this(errorCode, message, null); + } + + public PosixErrnoException(int errorCode, TruffleString message, Integer winerror) { + this.errorCode = errorCode; + msg = message; + this.winerror = winerror; + } + + public TruffleString getMessageAsTruffleString() { + return msg; + } + + @Override + public String getMessage() { + return msg.toJavaStringUncached(); + } + + public int getErrorCode() { + return errorCode; + } + + public Integer getWinerror() { + return winerror; + } + } + + /** + * Exception that indicates that a string of characters passed into the {@code inet_aton} or + * {@code inet_pton} function does not represent a valid IP address. These functions do not use + * the usual {@code errno} mechanism to report this kind of errors. + */ + public static class InvalidAddressException extends Exception { + + private static final long serialVersionUID = -2999913421191382026L; + + public InvalidAddressException() { + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return this; + } + } + + /** + * Exception that indicates that path for a unix socket was too long. + */ + public static class InvalidUnixSocketPathException extends Exception { + + private static final long serialVersionUID = 3603545222627858084L; + + public static InvalidUnixSocketPathException INSTANCE = new InvalidUnixSocketPathException(); + + private InvalidUnixSocketPathException() { + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return this; + } + } + + /** + * Exception that may be thrown by all the messages. It indicates that given functionality is + * not available in given implementation. In the future, there will be methods to query if + * certain feature is supported or not, but even then this exception may be thrown for other + * features. + */ + public static class UnsupportedPosixFeatureException extends PosixException { + + private static final long serialVersionUID = 1846254827094902593L; + + public UnsupportedPosixFeatureException(String message) { + super(message); + } + } + + /** + * Simple wrapper that allows exchanging byte buffers with the outside world. + */ + @ValueType + public static class Buffer { + public final byte[] data; + public long length; + + public Buffer(byte[] data, long length) { + assert data != null && length >= 0 && length <= data.length; + this.data = data; + this.length = length; + } + + public static Buffer allocate(long capacity) { + if (capacity > Integer.MAX_VALUE) { + throw CompilerDirectives.shouldNotReachHere("Long arrays are not supported yet"); + } + return new Buffer(new byte[(int) capacity], 0); + } + + public static Buffer wrap(byte[] data) { + return new Buffer(data, data.length); + } + + public Buffer withLength(long newLength) { + if (newLength > data.length) { + throw CompilerDirectives.shouldNotReachHere("Actual length cannot be greater than capacity"); + } + length = newLength; + return this; + } + + @TruffleBoundary + public ByteBuffer getByteBuffer() { + return ByteBuffer.wrap(data, 0, (int) length); + } + } + + /** + * Corresponds to the {@code timeval} struct. + */ + @ValueType + public static final class Timeval { + public static final Timeval SELECT_TIMEOUT_NOW = new Timeval(0, 0); + + private final long seconds; + private final long microseconds; + + public Timeval(long seconds, long microseconds) { + this.seconds = seconds; + this.microseconds = microseconds; + } + + public long getSeconds() { + return seconds; + } + + public long getMicroseconds() { + return microseconds; + } + } + + /** + * Wraps boolean arrays that indicate if given file descriptor was selected or not. For example, + * if {@code getReadFds()[X]} is {@code true}, then the file descriptor that was passed to + * {@code select} as {@code readfds[X]} was selected. + */ + @ValueType + public static final class SelectResult { + private final boolean[] readfds; + private final boolean[] writefds; + private final boolean[] errorfds; + + public SelectResult(boolean[] readfds, boolean[] writefds, boolean[] errorfds) { + this.readfds = readfds; + this.writefds = writefds; + this.errorfds = errorfds; + } + + public boolean[] getReadFds() { + return readfds; + } + + public boolean[] getWriteFds() { + return writefds; + } + + public boolean[] getErrorFds() { + return errorfds; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return String.format("select[read = %s; write = %s; err = %s]", Arrays.toString(readfds), Arrays.toString(writefds), Arrays.toString(errorfds)); + } + } + + // from stat.h macros + private static boolean istype(long mode, int mask) { + return (mode & S_IFMT.value) == mask; + } + + public static boolean isDIR(long mode) { + return istype(mode, S_IFDIR.value); + } + + public static boolean isCHR(long mode) { + return istype(mode, S_IFCHR.value); + } + + public static boolean isBLK(long mode) { + return istype(mode, S_IFBLK.value); + } + + public static boolean isREG(long mode) { + return istype(mode, S_IFREG.value); + } + + public static boolean isFIFO(long mode) { + return istype(mode, S_IFIFO.value); + } + + public static boolean isLNK(long mode) { + return istype(mode, S_IFLNK.value); + } + + public static class ChannelNotSelectableException extends UnsupportedPosixFeatureException { + private static final long serialVersionUID = -4185480181939639297L; + static ChannelNotSelectableException INSTANCE = new ChannelNotSelectableException(); + + private ChannelNotSelectableException() { + super(null); + } + } + + public abstract static class Path { } public void setEnv(@SuppressWarnings("unused") Env env) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java deleted file mode 100644 index 1d64102c1d..0000000000 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * 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.runtime; - -import static com.oracle.graal.python.runtime.PosixConstants.AF_INET; -import static com.oracle.graal.python.runtime.PosixConstants.AF_INET6; -import static com.oracle.graal.python.runtime.PosixConstants.AF_UNIX; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFBLK; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFCHR; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFDIR; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFIFO; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFLNK; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFMT; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFREG; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; -import com.oracle.graal.python.util.PythonUtils; -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.CompilerDirectives.ValueType; -import com.oracle.truffle.api.library.GenerateLibrary; -import com.oracle.truffle.api.library.Library; -import com.oracle.truffle.api.library.LibraryFactory; -import com.oracle.truffle.api.memory.ByteArraySupport; -import com.oracle.truffle.api.strings.TruffleString; - -/** - * Internal abstraction layer for POSIX functionality. Instance of the implementation is stored in - * the context. Use {@link PythonContext#getPosixSupport()} to access it. - */ -@GenerateLibrary(receiverType = PosixSupport.class) -public abstract class PosixSupportLibrary extends Library { - - /** Retained for the generated library until the remaining exports are removed. */ - public abstract TruffleString getBackend(Object receiver); - - public static final char POSIX_FILENAME_SEPARATOR = '/'; - - // Constants for accessing the fields of the fstat result: - // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants - public static final int ST_SIZE = 6; - - /** - * Equivalent to struct r_usage with the fields expected on macOS and Linux. - * - * @param ru_utime time in user mode (fractional seconds) - * @param ru_stime time in system mode (fractional seconds) - * @param ru_maxrss reserved memory size - * @param ru_ixrss shared memory size - * @param ru_idrss unshared memory size - * @param ru_isrss unshared stack size - * @param ru_minflt page faults not requiring I/O - * @param ru_majflt page faults requiring I/O - * @param ru_nswap number of swap outs - * @param ru_inblock block input operations - * @param ru_oublock block output operations - * @param ru_msgsnd messages sent - * @param ru_msgrcv messages received - * @param ru_nsignals signals received - * @param ru_nvcsw voluntary context switches - * @param ru_nivcsw involuntary context switches - */ - public record RusageResult(double ru_utime, double ru_stime, - long ru_maxrss, long ru_ixrss, long ru_idrss, long ru_isrss, - long ru_minflt, long ru_majflt, long ru_nswap, long ru_inblock, long ru_oublock, - long ru_msgsnd, long ru_msgrcv, long ru_nsignals, long ru_nvcsw, long ru_nivcsw) { - } - - public record OpenPtyResult(int masterFd, int slaveFd) { - } - - public static final class PwdResult { - public final TruffleString name; - /** - * This value represents unsigned 64 bit integer. - */ - public final long uid; - /** - * This value represents unsigned 64 bit integer. - */ - public final long gid; - public final TruffleString dir; - public final TruffleString shell; - - public PwdResult(TruffleString name, long uid, long gid, TruffleString dir, TruffleString shell) { - this.name = name; - this.uid = uid; - this.gid = gid; - this.dir = dir; - this.shell = shell; - } - - @Override - public String toString() { - return "PwdResult{name='" + name + '\'' + - ", uid=" + uid + - ", gid=" + gid + - ", dir='" + dir + '\'' + - ", shell='" + shell + "'}"; - } - } - - // region Socket addresses - - /** - * Base class for addresses specific to a particular socket family. - * - * The subclasses are simple POJOs whose definitions are common to all backends. They need to be - * converted to {@code UniversalSockAddr} before use. - */ - public abstract static class FamilySpecificSockAddr { - private final int family; - - protected FamilySpecificSockAddr(int family) { - this.family = family; - } - - public int getFamily() { - return family; - } - } - - /** - * A tagged union of all address types which is capable of holding an address of any socket - * family. - * - * An universal socket address keeps the value in a representation used internally by the given - * backend, therefore implementations of this interface are backend-specific (unlike - * {@link FamilySpecificSockAddr} subclasses). This interface roughly corresponds to POSIX - * {@code struct sockaddr_storage}. - * - */ - public interface UniversalSockAddr { - int getFamily(); - - Inet4SockAddr asInet4SockAddr(); - - Inet6SockAddr asInet6SockAddr(); - - UnixSockAddr asUnixSockAddr(); - } - - /** - * Represents an address for IPv4 sockets (the {@link PosixConstants#AF_INET} socket family). - * - * This is a higher level equivalent of POSIX {@code struct sockaddr_in} - integer values are - * kept in host byte order, conversion to network order ({@code htons/htonl}) is done - * automatically by the backend. This makes the integer representation of address compatible - * with the {@code INADDR_xxx} constants. On the other hand, addresses represented as byte - * arrays are in network order to make them compatible with {@code inet_pton} and - * {@code inet_ntop}). - */ - @ValueType - public static final class Inet4SockAddr extends FamilySpecificSockAddr { - private final int port; // host order, 0 - 65535 - private final int address; // host order, e.g. INADDR_LOOPBACK - - public Inet4SockAddr(int port, int address) { - super(AF_INET.value); - assert port >= 0 && port <= 65535; - this.port = port; - this.address = address; - } - - public Inet4SockAddr(int port, byte[] address) { - this(port, bytesToInt(address)); - } - - public int getPort() { - return port; - } - - public int getAddress() { - return address; - } - - public byte[] getAddressAsBytes() { - return intToBytes(address); - } - - private static int bytesToInt(byte[] src) { - assert src != null && src.length >= 4; - return ByteArraySupport.bigEndian().getInt(src, 0); - } - - private static byte[] intToBytes(int src) { - byte[] dst = new byte[4]; - ByteArraySupport.bigEndian().putInt(dst, 0, src); - return dst; - } - } - - /** - * Represents an address for IPv6 sockets (the {@link PosixConstants#AF_INET6} socket family). - * - * This is a higher level equivalent of POSIX {@code struct sockaddr_in6} - the values are kept - * in host byte order, conversion to network order ({@code htons/htonl}) is done automatically - * by the backend. - */ - @ValueType - public static final class Inet6SockAddr extends FamilySpecificSockAddr { - private final int port; // host order, 0 - 65535 - private final byte[] address = new byte[16]; - private final int flowInfo; // host order, 0 - 2^20-1 - private final int scopeId; // host order, interpreted as unsigned - - public Inet6SockAddr(int port, byte[] address, int flowInfo, int scopeId) { - super(AF_INET6.value); - assert port >= 0 && port <= 65535; - assert address != null && address.length == 16; - assert flowInfo >= 0 && flowInfo <= 1048575; - this.port = port; - PythonUtils.arraycopy(address, 0, this.address, 0, 16); - this.flowInfo = flowInfo; - this.scopeId = scopeId; - } - - public int getPort() { - return port; - } - - public byte[] getAddress() { - return Arrays.copyOf(address, 16); - } - - public int getFlowInfo() { - return flowInfo; - } - - public int getScopeId() { - return scopeId; - } - } - - /** - * Represents an address for UNIX domain sockets (the {@link PosixConstants#AF_UNIX} socket - * family). - * - * This is a higher level equivalent of POSIX {@code struct sockaddr_un}, see - * {@code man -7 unix}. It is the responsibility of the user to ensure that pathname addresses - * are zero terminated and abstract addresses start with a zero. - */ - @ValueType - public static final class UnixSockAddr extends FamilySpecificSockAddr { - private final byte[] path; - - public UnixSockAddr(byte[] path) { - super(AF_UNIX.value); - this.path = path; - } - - /** - * Returns the path, which: - *
      - *
    • for unnamed addresses is of length 0,
    • - *
    • for pathname addresses contains the terminating zero,
    • - *
    • for abstract addresses start with a zero,
    • - *
    • should not be modified by the caller.
    • - *
    - */ - public byte[] getPath() { - return path; - } - } - - // endregion - - public static final class AcceptResult { - public final int socketFd; - public final UniversalSockAddr sockAddr; - - public AcceptResult(int socketFd, UniversalSockAddr sockAddr) { - this.socketFd = socketFd; - this.sockAddr = sockAddr; - } - - @Override - public String toString() { - CompilerAsserts.neverPartOfCompilation(); - return "RecvfromResult{" + "socketFd=" + socketFd + ", sockAddr=" + sockAddr + '}'; - } - } - - public static final class RecvfromResult { - public final int readBytes; - public final UniversalSockAddr sockAddr; - - public RecvfromResult(int readBytes, UniversalSockAddr sockAddr) { - this.readBytes = readBytes; - this.sockAddr = sockAddr; - } - - @Override - public String toString() { - CompilerAsserts.neverPartOfCompilation(); - return "RecvfromResult{" + "readBytes=" + readBytes + ", sockAddr=" + sockAddr + '}'; - } - } - - // region Name resolution messages - - /** - * Represents one or more addrinfos returned by {@code getaddrinfo()}. - * - * Must be explicitly released using {@link #release()}. - * Behaves like a cursor which points to a {@code struct addrinfo} structure (initially pointing - * at the first address info). The cursor can only move forward using the - * {@link #next()} method. - */ - public interface AddrInfoCursor { - void release(); - - boolean next(); - - int getFlags(); - - int getFamily(); - - int getSockType(); - - int getProtocol(); - - Object getCanonName(); - - UniversalSockAddr getSockAddr(); - } - - /** - * Exception that indicates and error while executing - * {@link PosixSupport#getaddrinfo(Object, Object, int, int, int, int)}. - */ - public static final class GetAddrInfoException extends Exception { - - private static final long serialVersionUID = 3013253817849329391L; - - private final int errorCode; - private final transient TruffleString msg; - - public GetAddrInfoException(int errorCode, TruffleString message) { - super(message.toJavaStringUncached()); - this.errorCode = errorCode; - msg = message; - } - - public int getErrorCode() { - return errorCode; - } - - public final TruffleString getMessageAsTruffleString() { - return msg; - } - - @SuppressWarnings("sync-override") - @Override - public final Throwable fillInStackTrace() { - return this; - } - } - - // endregion - - /** - * Base class for exceptions that originate in the POSIX support layer. - */ - public abstract static class PosixException extends Exception { - - private static final long serialVersionUID = 8700515065120346760L; - - protected PosixException() { - } - - protected PosixException(String message) { - super(message); - } - - public final boolean hasErrno(OSErrorEnum errno) { - return this instanceof PosixErrnoException errnoException && errnoException.getErrorCode() == errno.getNumber(); - } - - @SuppressWarnings("sync-override") - @Override - public Throwable fillInStackTrace() { - return this; - } - } - - /** - * Exception that indicates POSIX level error associated with numeric code. If the message is - * known, it may be included in the exception, otherwise it can be queried using - * {@link PosixSupport#strerror(int)}. - */ - public static final class PosixErrnoException extends PosixException { - - private static final long serialVersionUID = -115762483478883093L; - - private final int errorCode; - private final transient TruffleString msg; - /* - * Windows APIs expose both POSIX errno and a native Win32/Winsock error code. Store the - * native code as java.lang.Integer rather than int because most PosixErrnoException - * instances are not backed by a Windows error, so this field can be null. - */ - private final Integer winerror; - - public PosixErrnoException(int errorCode, TruffleString message) { - this(errorCode, message, null); - } - - public PosixErrnoException(int errorCode, TruffleString message, Integer winerror) { - this.errorCode = errorCode; - msg = message; - this.winerror = winerror; - } - - public TruffleString getMessageAsTruffleString() { - return msg; - } - - @Override - public String getMessage() { - return msg.toJavaStringUncached(); - } - - public int getErrorCode() { - return errorCode; - } - - public Integer getWinerror() { - return winerror; - } - } - - /** - * Exception that indicates that a string of characters passed into the {@code inet_aton} or - * {@code inet_pton} function does not represent a valid IP address. These functions do not use - * the usual {@code errno} mechanism to report this kind of errors. - */ - public static class InvalidAddressException extends Exception { - - private static final long serialVersionUID = -2999913421191382026L; - - public InvalidAddressException() { - } - - @SuppressWarnings("sync-override") - @Override - public final Throwable fillInStackTrace() { - return this; - } - } - - /** - * Exception that indicates that path for a unix socket was too long. - */ - public static class InvalidUnixSocketPathException extends Exception { - - private static final long serialVersionUID = 3603545222627858084L; - - public static InvalidUnixSocketPathException INSTANCE = new InvalidUnixSocketPathException(); - - private InvalidUnixSocketPathException() { - } - - @SuppressWarnings("sync-override") - @Override - public final Throwable fillInStackTrace() { - return this; - } - } - - /** - * Exception that may be thrown by all the messages. It indicates that given functionality is - * not available in given implementation. In the future, there will be methods to query if - * certain feature is supported or not, but even then this exception may be thrown for other - * features. - */ - public static class UnsupportedPosixFeatureException extends PosixException { - - private static final long serialVersionUID = 1846254827094902593L; - - public UnsupportedPosixFeatureException(String message) { - super(message); - } - } - - /** - * Simple wrapper that allows exchanging byte buffers with the outside world. - */ - @ValueType - public static class Buffer { - public final byte[] data; - public long length; - - public Buffer(byte[] data, long length) { - assert data != null && length >= 0 && length <= data.length; - this.data = data; - this.length = length; - } - - public static Buffer allocate(long capacity) { - if (capacity > Integer.MAX_VALUE) { - throw CompilerDirectives.shouldNotReachHere("Long arrays are not supported yet"); - } - return new Buffer(new byte[(int) capacity], 0); - } - - public static Buffer wrap(byte[] data) { - return new Buffer(data, data.length); - } - - public Buffer withLength(long newLength) { - if (newLength > data.length) { - throw CompilerDirectives.shouldNotReachHere("Actual length cannot be greater than capacity"); - } - length = newLength; - return this; - } - - @TruffleBoundary - public ByteBuffer getByteBuffer() { - return ByteBuffer.wrap(data, 0, (int) length); - } - } - - /** - * Corresponds to the {@code timeval} struct. - */ - @ValueType - public static final class Timeval { - public static final Timeval SELECT_TIMEOUT_NOW = new Timeval(0, 0); - - private final long seconds; - private final long microseconds; - - public Timeval(long seconds, long microseconds) { - this.seconds = seconds; - this.microseconds = microseconds; - } - - public long getSeconds() { - return seconds; - } - - public long getMicroseconds() { - return microseconds; - } - } - - /** - * Wraps boolean arrays that indicate if given file descriptor was selected or not. For example, - * if {@code getReadFds()[X]} is {@code true}, then the file descriptor that was passed to - * {@code select} as {@code readfds[X]} was selected. - */ - @ValueType - public static final class SelectResult { - private final boolean[] readfds; - private final boolean[] writefds; - private final boolean[] errorfds; - - public SelectResult(boolean[] readfds, boolean[] writefds, boolean[] errorfds) { - this.readfds = readfds; - this.writefds = writefds; - this.errorfds = errorfds; - } - - public boolean[] getReadFds() { - return readfds; - } - - public boolean[] getWriteFds() { - return writefds; - } - - public boolean[] getErrorFds() { - return errorfds; - } - - @Override - public String toString() { - CompilerAsserts.neverPartOfCompilation(); - return String.format("select[read = %s; write = %s; err = %s]", Arrays.toString(readfds), Arrays.toString(writefds), Arrays.toString(errorfds)); - } - } - - // from stat.h macros - private static boolean istype(long mode, int mask) { - return (mode & S_IFMT.value) == mask; - } - - public static boolean isDIR(long mode) { - return istype(mode, S_IFDIR.value); - } - - public static boolean isCHR(long mode) { - return istype(mode, S_IFCHR.value); - } - - public static boolean isBLK(long mode) { - return istype(mode, S_IFBLK.value); - } - - public static boolean isREG(long mode) { - return istype(mode, S_IFREG.value); - } - - public static boolean isFIFO(long mode) { - return istype(mode, S_IFIFO.value); - } - - public static boolean isLNK(long mode) { - return istype(mode, S_IFLNK.value); - } - - public static class ChannelNotSelectableException extends UnsupportedPosixFeatureException { - private static final long serialVersionUID = -4185480181939639297L; - static ChannelNotSelectableException INSTANCE = new ChannelNotSelectableException(); - - private ChannelNotSelectableException() { - super(null); - } - } - - static final LibraryFactory FACTORY = LibraryFactory.resolve(PosixSupportLibrary.class); - - public static LibraryFactory getFactory() { - return FACTORY; - } - - public static PosixSupportLibrary getUncached() { - return FACTORY.getUncached(); - } -} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index ca74927ef4..60eec6e40c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -45,33 +45,11 @@ import java.util.HashSet; import java.util.IdentityHashMap; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleLanguage.Env; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.library.ExportLibrary; -import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; -@ExportLibrary(PosixSupportLibrary.class) public class PreInitPosixSupport extends PosixSupport { protected final NativePosixSupport nativePosixSupport; @@ -153,7 +131,6 @@ private Object removeDirStream(Object dirStream) { } @Override - @ExportMessage @TruffleBoundary public final TruffleString getBackend() { checkNotInPreInitialization(); @@ -161,24 +138,28 @@ public final TruffleString getBackend() { } @Override + @TruffleBoundary public final TruffleString strerror(int errorCode) { checkNotInPreInitialization(); return nativePosixSupport.strerror(errorCode); } @Override + @TruffleBoundary public final long getpid() { checkNotInPreInitialization(); return nativePosixSupport.getpid(); } @Override + @TruffleBoundary public final int umask(int mask) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.umask(mask); } @Override + @TruffleBoundary public final int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { if (inPreInitialization) { return addFd(emulatedPosixSupport.openat(dirFd, pathname, flags, mode)); @@ -187,6 +168,7 @@ public final int openat(int dirFd, Object pathname, int flags, int mode) throws } @Override + @TruffleBoundary public final int close(int fd) throws PosixException { if (inPreInitialization) { return emulatedPosixSupport.close(removeFd(fd)); @@ -195,6 +177,7 @@ public final int close(int fd) throws PosixException { } @Override + @TruffleBoundary public final Buffer read(int fd, long length) throws PosixException { if (inPreInitialization) { return emulatedPosixSupport.read(fd, length); @@ -203,6 +186,7 @@ public final Buffer read(int fd, long length) throws PosixException { } @Override + @TruffleBoundary public final long write(int fd, Buffer data) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.write(fd, data); @@ -225,24 +209,28 @@ public final long writeWindowsConsole(int fd, Buffer data) throws PosixException } @Override + @TruffleBoundary public final int dup(int fd) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.dup(fd); } @Override + @TruffleBoundary public final int dup2(int fd, int fd2, boolean inheritable) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.dup2(fd, fd2, inheritable); } @Override + @TruffleBoundary public final boolean getInheritable(int fd) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.getInheritable(fd); } @Override + @TruffleBoundary public final void setInheritable(int fd, boolean inheritable) throws PosixException { if (inPreInitialization) { emulatedPosixSupport.setInheritable(fd, inheritable); @@ -252,48 +240,56 @@ public final void setInheritable(int fd, boolean inheritable) throws PosixExcept } @Override + @TruffleBoundary public final long getOsfHandle(int fd) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.getOsfHandle(fd); } @Override + @TruffleBoundary public final int openOsfHandle(long handle, int flags) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.openOsfHandle(handle, flags); } @Override + @TruffleBoundary public final int setMode(int fd, int mode) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.setMode(fd, mode); } @Override + @TruffleBoundary public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.msvcrtLocking(fd, mode, nbytes); } @Override + @TruffleBoundary public final int[] pipe() throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.pipe(); } @Override + @TruffleBoundary public final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.select(readfds, writefds, errorfds, timeout); } @Override + @TruffleBoundary public final void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.poll(fds, events, revents, timeout); } @Override + @TruffleBoundary public final long lseek(int fd, long offset, int how) throws PosixException { if (inPreInitialization) { return emulatedPosixSupport.lseek(fd, offset, how); @@ -302,60 +298,70 @@ public final long lseek(int fd, long offset, int how) throws PosixException { } @Override + @TruffleBoundary public final void ftruncate(int fd, long length) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.ftruncate(fd, length); } @Override + @TruffleBoundary public final void truncate(Object path, long length) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.truncate(path, length); } @Override + @TruffleBoundary public final void fsync(int fd) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.fsync(fd); } @Override + @TruffleBoundary public final void flock(int fd, int operation) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.flock(fd, operation); } @Override + @TruffleBoundary public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.fcntlLock(fd, blocking, lockType, whence, start, length); } @Override + @TruffleBoundary public final boolean getBlocking(int fd) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.getBlocking(fd); } @Override + @TruffleBoundary public final void setBlocking(int fd, boolean blocking) throws PosixException { checkNotInPreInitialization(); nativePosixSupport.setBlocking(fd, blocking); } @Override + @TruffleBoundary public final int[] getTerminalSize(int fd) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.getTerminalSize(fd); } @Override + @TruffleBoundary public final long sysconf(int name) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.sysconf(name); } @Override + @TruffleBoundary public final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { if (inPreInitialization) { return emulatedPosixSupport.fstatat(dirFd, pathname, followSymlinks); @@ -364,6 +370,7 @@ public final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) } @Override + @TruffleBoundary public final long[] fstat(int fd) throws PosixException { if (inPreInitialization) { return emulatedPosixSupport.fstat(fd); @@ -372,6 +379,7 @@ public final long[] fstat(int fd) throws PosixException { } @Override + @TruffleBoundary public final long[] statvfs(Object path) throws PosixException { if (inPreInitialization) { return emulatedPosixSupport.statvfs(path); @@ -380,6 +388,7 @@ public final long[] statvfs(Object path) throws PosixException { } @Override + @TruffleBoundary public final long[] fstatvfs(int fd) throws PosixException { if (inPreInitialization) { return emulatedPosixSupport.fstatvfs(fd); @@ -388,6 +397,7 @@ public final long[] fstatvfs(int fd) throws PosixException { } @Override + @TruffleBoundary public final Object[] uname() throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.uname(); @@ -616,6 +626,7 @@ public final void fchown(int fd, long owner, long group) throws PosixException { } @Override + @TruffleBoundary public final Object readlinkat(int dirFd, Object path) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.readlinkat(dirFd, path); @@ -847,7 +858,8 @@ public final void unsetenv(Object name) throws PosixException { @Override @TruffleBoundary - public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, + public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, + int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.forkExec(executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java index 40ea4fe9b4..63c5a502c3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java @@ -40,7 +40,7 @@ */ package com.oracle.graal.python.util; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; public abstract class TimeUtils { public static final long SEC_TO_MS = 1000L; From ffb839c767f813b163875c88a73e41178e22d417 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 1 Oct 2026 08:39:11 +0200 Subject: [PATCH 061/129] Generic cleanups (cherry picked from commit cc4a2096ada6257cfebf3351e4d4c03f949dafce) --- .../lib/PyUnicodeEncodeFSDefaultNode.java | 7 + .../python/runtime/EmulatedPosixSupport.java | 230 +++++------------- .../python/runtime/NativePosixSupport.java | 49 ++-- 3 files changed, 85 insertions(+), 201 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java index 14be27f2ce..8c4bd448f0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java @@ -49,6 +49,7 @@ import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltins; import com.oracle.graal.python.nodes.PNodeWithContext; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; @@ -66,6 +67,12 @@ @GenerateCached(false) @GenerateInline public abstract class PyUnicodeEncodeFSDefaultNode extends PNodeWithContext { + + @TruffleBoundary + public static byte[] executeUncached(TruffleString string) { + return PyUnicodeEncodeFSDefaultNodeGen.getUncached().execute(null, null, string); + } + public abstract byte[] execute(Frame frame, Node inliningTarget, TruffleString string); @Specialization diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 3fb5f6c6bc..16758ead40 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -227,7 +227,7 @@ import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.ErrorAndMessagePair; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.OperationWouldBlockException; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNodeGen; +import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.runtime.exception.PythonExitException; import com.oracle.graal.python.util.FileDeleteShutdownHook; @@ -278,7 +278,6 @@ *
  • {@code select} supports only network sockets, but not regular files.
  • * */ -@SuppressWarnings("unused") public final class EmulatedPosixSupport extends PosixResources { private static final int MAX_READ = Integer.MAX_VALUE / 2; @@ -315,6 +314,7 @@ public final class EmulatedPosixSupport extends PosixResources { }; private static final TruffleString T_BIN_SH = tsLiteral("/bin/sh"); private static final TruffleString T_DEV_TTY = tsLiteral("/dev/tty"); + private static final LinkOption[] NO_LINK_OPTIONS = new LinkOption[0]; private final ConcurrentHashMap environ = new ConcurrentHashMap<>(); private long pid; @@ -428,7 +428,7 @@ public int close(int fd) throws PosixException { public int openat(int dirFd, Object path, int flags, int mode) throws PosixException { TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); Set options = flagsToOptions(flags); - FileAttribute> attributes = modeToAttributes(mode & ~currentUmask); + FileAttribute> attributes = PosixFilePermissions.asFileAttribute(modeToPosixFilePermissions(mode & ~currentUmask)); try { return openTruffleFile(file, options, attributes); } catch (Exception e) { @@ -462,11 +462,11 @@ private int openTruffleFile(TruffleFile truffleFile, Set opt @TruffleBoundary public long write(int fd, Buffer data) throws PosixException { Channel channel = getFileChannel(fd); - if (!(channel instanceof WritableByteChannel)) { + if (!(channel instanceof WritableByteChannel writableChannel)) { throw posixException(OSErrorEnum.EBADF); } try { - return doWriteOp(data.getByteBuffer(), (WritableByteChannel) channel); + return writableChannel.write(data.getByteBuffer()); } catch (Exception e) { throw posixException(OSErrorEnum.fromException(e)); } @@ -484,20 +484,15 @@ public long writeWindowsConsole(int fd, Buffer data) throws PosixException { return write(fd, data); } - @TruffleBoundary(allowInlining = true) - private static int doWriteOp(ByteBuffer data, WritableByteChannel channel) throws IOException { - return channel.write(data); - } - @Override @TruffleBoundary public Buffer read(int fd, long length) throws PosixException { Channel channel = getFileChannel(fd); - if (!(channel instanceof ReadableByteChannel)) { + if (!(channel instanceof ReadableByteChannel readableChannel)) { throw posixException(OSErrorEnum.EBADF); } try { - return readBytesFromChannel((ReadableByteChannel) channel, length); + return readBytesFromChannel(readableChannel, length); } catch (Exception e) { throw posixException(OSErrorEnum.fromException(e)); } @@ -758,8 +753,7 @@ private SelectableChannel getSelectableChannel(int fd) throws PosixException { return (SelectableChannel) ch; } else if (ch instanceof EmulatedDatagramSocket) { return ((EmulatedDatagramSocket) ch).channel; - } else if (ch instanceof EmulatedStreamSocket) { - EmulatedStreamSocket streamSocket = (EmulatedStreamSocket) ch; + } else if (ch instanceof EmulatedStreamSocket streamSocket) { synchronized (streamSocket) { if (streamSocket.clientChannel != null) { return streamSocket.clientChannel; @@ -846,7 +840,7 @@ public long lseek(int fd, long offset, int how) throws PosixException { if (channel == null) { throw posixException(OSErrorEnum.EBADF); } - if (!(channel instanceof SeekableByteChannel)) { + if (!(channel instanceof SeekableByteChannel fc)) { throw posixException(OSErrorEnum.ESPIPE); } if (SEEK_DATA.defined && how == SEEK_DATA.getValueIfDefined()) { @@ -855,7 +849,6 @@ public long lseek(int fd, long offset, int how) throws PosixException { if (SEEK_HOLE.defined && how == SEEK_HOLE.getValueIfDefined()) { throw createUnsupportedFeature("SEEK_HOLE"); } - SeekableByteChannel fc = (SeekableByteChannel) channel; long newPos; try { newPos = setPosition(offset, how, fc); @@ -1126,7 +1119,7 @@ public long[] fstat(int fd) throws PosixException { } TruffleFile f = getTruffleFile(path); try { - return fstat(f, new LinkOption[0]); + return fstat(f, NO_LINK_OPTIONS); } catch (Exception e) { ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); @@ -1332,9 +1325,13 @@ private static long[] setTimestamps(Attributes attributes, TruffleFile.Attribute FileTime atime = attributes.get(LAST_ACCESS_TIME); FileTime mtime = attributes.get(LAST_MODIFIED_TIME); FileTime ctime = attributes.get(ctimeDescriptor); - statResult[7] = fileTimeToSeconds(atime); - statResult[8] = fileTimeToSeconds(mtime); - statResult[9] = fileTimeToSeconds(ctime); + assert atime != null; + assert mtime != null; + assert ctime != null; + + statResult[7] = atime.to(TimeUnit.SECONDS); + statResult[8] = mtime.to(TimeUnit.SECONDS); + statResult[9] = ctime.to(TimeUnit.SECONDS); statResult[10] = fileTimeNanoSecondsPart(atime); statResult[11] = fileTimeNanoSecondsPart(mtime); statResult[12] = fileTimeNanoSecondsPart(ctime); @@ -1419,7 +1416,7 @@ public Object[] uname() { return new Object[]{ toTruffleStringUncached(getPythonOS().getUname()), toTruffleStringUncached(getHostName(withoutIOSocket)), - toTruffleStringUncached(getOsVersion()), + toTruffleStringUncached(System.getProperty("os.version", "")), T_EMPTY_STRING, PythonUtils.getPythonArch() }; @@ -1456,11 +1453,6 @@ public WindowsVersion getWindowsVersion() { return new WindowsVersion(major, minor, build, 2, T_EMPTY_STRING, 0, 0, 0, 1, major, minor, build); } - @TruffleBoundary - private static String getOsVersion() { - return System.getProperty("os.version", ""); - } - @TruffleBoundary private static String getHostName(boolean withoutSocket) { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutSocket) { @@ -1799,7 +1791,7 @@ private static void setUTime(TruffleFile file, long[] timespec, boolean followSy } } - private static FileTime toFileTime(long seconds, long nanos) { + private static FileTime toFileTime(long seconds, @SuppressWarnings("unused") long nanos) { // JDK allows to set only one time per operation, so setting one may round the other to // seconds. Ignore nanoseconds consistently for both times. return FileTime.from(seconds, TimeUnit.SECONDS); @@ -1862,7 +1854,7 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, } boolean result = true; if ((mode & X_OK.value) != 0) { - result = result && isExecutable(file); + result = isExecutable(file); } if ((mode & R_OK.value) != 0) { result = result && isReadable(file); @@ -2132,13 +2124,8 @@ public long[] waitpid(Node location, long pid, int options) throws PosixExceptio } } - @TruffleBoundary - private static void interruptThread() { - Thread.currentThread().interrupt(); - } - // TODO the implementation of the following builtins is taken from posix.py, - // do they really make sense for the emulated backend? Is the handling of exist status correct? + // do they really make sense for the emulated backend? Is the handling of exit status correct? @Override @TruffleBoundary(allowInlining = true) @@ -2731,31 +2718,31 @@ public boolean isOpen() { } @Override - public void close() throws IOException { + public void close() { open = false; } @Override - public int read(ByteBuffer dst) throws IOException { + public int read(ByteBuffer dst) { int nread = Math.min(dst.remaining(), data.length - cur); dst.put(data, cur, nread); return nread; } @Override - public int write(ByteBuffer src) throws IOException { + public int write(ByteBuffer src) { int nwrite = Math.min(src.remaining(), data.length - cur); src.get(data, cur, nwrite); return nwrite; } @Override - public long position() throws IOException { + public long position() { return cur; } @Override - public SeekableByteChannel position(long newPosition) throws IOException { + public SeekableByteChannel position(long newPosition) { if (newPosition < 0 || newPosition >= data.length) { throw new IllegalArgumentException(); } @@ -2764,12 +2751,12 @@ public SeekableByteChannel position(long newPosition) throws IOException { } @Override - public long size() throws IOException { + public long size() { return data.length; } @Override - public SeekableByteChannel truncate(long size) throws IOException { + public SeekableByteChannel truncate(long size) { for (int i = 0; i < size; i++) { data[i] = 0; } @@ -2799,8 +2786,8 @@ public MMapHandle mmap(@SuppressWarnings("unused") Node location, long length, i // we create a new channel, the file may be closed but the mmap object should still work SeekableByteChannel fileChannel; try { - fileChannel = newByteChannel(file, options); - position(fileChannel, offset); + fileChannel = file.newByteChannel(options); + fileChannel.position(offset); return new MMapHandle(fileChannel, offset); } catch (IOException e) { throw posixException(OSErrorEnum.fromException(e)); @@ -2822,60 +2809,48 @@ private static Set mmapProtToOptions(int prot) throws PosixE return options; } - @TruffleBoundary - private static SeekableByteChannel newByteChannel(TruffleFile file, Set options) throws IOException { - return file.newByteChannel(options); - } - @Override @TruffleBoundary - @SuppressWarnings("static-method") public byte mmapReadByte(Object mmap, long index) throws PosixException { if (mmap == MMapHandle.NONE) { throw posixException(OSErrorEnum.EACCES); } MMapHandle handle = (MMapHandle) mmap; - ByteBuffer readingBuffer = allocateByteBuffer(1); + ByteBuffer readingBuffer = ByteBuffer.allocate(1); int readSize = readBytes(handle, index, readingBuffer); if (readSize == 0) { throw posixException(OSErrorEnum.ENODATA); } - return getByte(readingBuffer); + readingBuffer.flip(); + return readingBuffer.get(); } @Override @TruffleBoundary - @SuppressWarnings("static-method") public void mmapWriteByte(Object mmap, long index, byte value) throws PosixException { mmapWriteBytes(mmap, index, new byte[]{value}, 1); } @Override @TruffleBoundary - @SuppressWarnings("static-method") public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { if (mmap == MMapHandle.NONE) { throw posixException(OSErrorEnum.EACCES); } MMapHandle handle = (MMapHandle) mmap; - int sz; - try { - sz = PythonUtils.toIntExact(length); - } catch (OverflowException e) { - throw posixException(OSErrorEnum.EOVERFLOW); - } - ByteBuffer readingBuffer = allocateByteBuffer(sz); + ByteBuffer readingBuffer = ByteBuffer.allocate(length); int readSize = readBytes(handle, index, readingBuffer); if (readSize > 0) { - getByteBufferArray(readingBuffer, bytes, readSize); + readingBuffer.flip(); + readingBuffer.get(bytes, 0, readSize); } return readSize; } private static int readBytes(MMapHandle handle, long index, ByteBuffer readingBuffer) throws PosixException { try { - position(handle.channel, index + handle.offset); - return readChannel(handle.channel, readingBuffer); + handle.channel.position(index + handle.offset); + return handle.channel.read(readingBuffer); } catch (IOException e) { throw posixException(OSErrorEnum.fromException(e)); } @@ -2883,7 +2858,6 @@ private static int readBytes(MMapHandle handle, long index, ByteBuffer readingBu @Override @TruffleBoundary - @SuppressWarnings("static-method") public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { if (mmap == MMapHandle.NONE) { throw posixException(OSErrorEnum.EACCES); @@ -2891,8 +2865,8 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) th MMapHandle handle = (MMapHandle) mmap; try { SeekableByteChannel channel = handle.channel; - position(channel, handle.offset + index); - int written = writeChannel(channel, bytes, length); + channel.position(handle.offset + index); + int written = channel.write(ByteBuffer.wrap(bytes, 0, length)); if (written != length) { throw posixException(OSErrorEnum.EIO); } @@ -2902,14 +2876,9 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) th } } - @TruffleBoundary - private static int writeChannel(SeekableByteChannel channel, byte[] bytes, int length) throws IOException { - return channel.write(ByteBuffer.wrap(bytes, 0, length)); - } - @Override @TruffleBoundary - @SuppressWarnings({"static-method", "unused"}) + @SuppressWarnings("unused") public void mmapFlush(Object mmap, long offset, long length) { // Intentionally noop // If we had access to the underlying NIO FileChannel, we could explicitly set force(true) @@ -2920,7 +2889,6 @@ public void mmapFlush(Object mmap, long offset, long length) { @Override @TruffleBoundary - @SuppressWarnings("static-method") public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length) throws PosixException { if (mmap == MMapHandle.NONE) { return; @@ -2928,7 +2896,7 @@ public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length) thro MMapHandle handle = (MMapHandle) mmap; if (handle.channel != null) { try { - closeChannel(handle.channel); + handle.channel.close(); } catch (IOException e) { throw posixException(OSErrorEnum.fromException(e)); } @@ -2938,43 +2906,10 @@ public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length) thro @Override @TruffleBoundary - @SuppressWarnings("static-method") public long mmapGetPointer(@SuppressWarnings("unused") Object mmap) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("obtaining mmap pointer"); } - @TruffleBoundary - private static void closeChannel(Channel ch) throws IOException { - ch.close(); - } - - @TruffleBoundary - private static void position(SeekableByteChannel ch, long offset) throws IOException { - ch.position(offset); - } - - @TruffleBoundary(allowInlining = true) - private static ByteBuffer allocateByteBuffer(int n) { - return ByteBuffer.allocate(n); - } - - @TruffleBoundary(allowInlining = true) - private static void getByteBufferArray(ByteBuffer src, byte[] dst, int readSize) { - src.flip(); - src.get(dst, 0, readSize); - } - - @TruffleBoundary(allowInlining = true) - private static byte getByte(ByteBuffer src) { - src.flip(); - return src.get(); - } - - @TruffleBoundary - private static int readChannel(Object readableChannel, ByteBuffer dst) throws IOException { - return ((ReadableByteChannel) readableChannel).read(dst); - } - @Override @TruffleBoundary @SuppressWarnings("unused") @@ -3047,7 +2982,6 @@ public boolean semTimedWait(Node location, long handle, long deadlineNs) throws @Override @TruffleBoundary - @SuppressWarnings("static-method") public PwdResult getpwuid(long uid) throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { switch (PythonLanguage.getPythonOS()) { @@ -3068,7 +3002,6 @@ public PwdResult getpwuid(long uid) throws PosixException { @Override @TruffleBoundary - @SuppressWarnings("static-method") public PwdResult getpwnam(Object name) throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { switch (PythonLanguage.getPythonOS()) { @@ -3088,15 +3021,13 @@ public PwdResult getpwnam(Object name) throws PosixException { } @Override - @TruffleBoundary - @SuppressWarnings("static-method") + @TruffleBoundary(allowInlining = true) public boolean hasGetpwentries() { return false; } @Override @TruffleBoundary - @SuppressWarnings("static-method") public PwdResult[] getpwentries() throws PosixException { throw createUnsupportedFeature("getpwent"); } @@ -3453,7 +3384,6 @@ private static boolean decodeBooleanOptVal(byte[] optval, int optlen) throws Pos @Override @TruffleBoundary - @SuppressWarnings("static-method") public int inet_addr(Object src) { try { return inet_aton(src); @@ -3463,7 +3393,6 @@ public int inet_addr(Object src) { } @Override - @SuppressWarnings("static-method") @TruffleBoundary public int inet_aton(Object src) throws InvalidAddressException { String s = (String) src; @@ -3483,14 +3412,12 @@ public int inet_aton(Object src) throws InvalidAddressException { } @Override - @SuppressWarnings("static-method") @TruffleBoundary public Object inet_ntoa(int address) { return String.format("%d.%d.%d.%d", (address >> 24) & 0xFF, (address >> 16) & 0xFF, (address >> 8) & 0xFF, address & 0xFF); } @Override - @SuppressWarnings("static-method") @TruffleBoundary public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { byte[] bytes; @@ -3523,7 +3450,6 @@ public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAd } @Override - @SuppressWarnings("static-method") @TruffleBoundary public Object inet_ntop(int family, byte[] src) throws PosixException { if (family != AF_INET.value && family != AF_INET6.value) { @@ -3547,13 +3473,11 @@ public Object inet_ntop(int family, byte[] src) throws PosixException { @Override @TruffleBoundary - @SuppressWarnings("static-method") public Object gethostname() throws PosixException { return getHostName(withoutIOSocket); } @Override - @SuppressWarnings("static-method") @TruffleBoundary public Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3587,7 +3511,6 @@ public Object[] getnameinfo(UniversalSockAddr addr, int flags) throws Unsupporte return new Object[]{host, service}; } - @TruffleBoundary private String searchServicesForPort(TruffleLanguage.Env env, int port, String protocol) { Map> services = getServices(); Set servicesNames = services.keySet(); @@ -3604,7 +3527,6 @@ private String searchServicesForPort(TruffleLanguage.Env env, int port, String p } @Override - @SuppressWarnings("static-method") @TruffleBoundary public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3984,7 +3906,7 @@ public int write(ByteBuffer src) throws IOException { } @Override - EmulatedSocket accept() throws IOException { + EmulatedSocket accept() { throw new UnsupportedOperationException(); } @@ -4001,7 +3923,7 @@ void connect(SocketAddress socketAddress) throws IOException { } @Override - void listen(int backlog) throws IOException { + void listen(int backlog) { throw new UnsupportedOperationException(); } @@ -4057,7 +3979,7 @@ int sendto(ByteBuffer bb, int flags, SocketAddress destAddr) throws IOException } @Override - void shutdown(int how) throws IOException { + void shutdown(int how) { // TODO what does native SOCK_DGRAM shutdown do? } @@ -4198,7 +4120,7 @@ EmulatedStreamSocket accept() throws IOException { } @Override - synchronized void bind(SocketAddress socketAddress) throws IOException { + synchronized void bind(SocketAddress socketAddress) { neverPartOfCompilation(); if (clientChannel != null || serverChannel != null || bindAddress != null) { // already bound @@ -4317,7 +4239,7 @@ int send(ByteBuffer bb, int flags) throws IOException { } @Override - int sendto(ByteBuffer bb, int flags, SocketAddress destAddr) throws IOException { + int sendto(ByteBuffer bb, int flags, SocketAddress destAddr) { neverPartOfCompilation(); // sendto() makes sense only for DGRAM sockets throw new AlreadyConnectedException(); @@ -4446,11 +4368,8 @@ private static byte[] mapIPv4toIPv6(byte[] ipv4) { @Override @TruffleBoundary - @SuppressWarnings("static-method") public Object createPathFromString(TruffleString path) { - String javaPath = getPythonOS() == PLATFORM_WIN32 - ? TruffleString.ToJavaStringNode.getUncached().execute(path) - : createUTF8String(PyUnicodeEncodeFSDefaultNodeGen.getUncached().execute(null, null, path)); + String javaPath = getPythonOS() == PLATFORM_WIN32 ? path.toJavaStringUncached() : new String(PyUnicodeEncodeFSDefaultNode.executeUncached(path), StandardCharsets.UTF_8); return checkEmbeddedNulls(javaPath); } @@ -4458,61 +4377,51 @@ public Object createPathFromString(TruffleString path) { @TruffleBoundary @SuppressWarnings("static-method") public Object createPathFromBytes(byte[] path) { - return checkEmbeddedNulls(createUTF8String(path)); + return checkEmbeddedNulls(new String(path, StandardCharsets.UTF_8)); } @Override @TruffleBoundary @SuppressWarnings("static-method") public TruffleString getPathAsString(Object path) { - return TruffleString.FromJavaStringNode.getUncached().execute((String) path, TS_ENCODING); + return TruffleString.fromJavaStringUncached((String) path, TS_ENCODING); } @Override @TruffleBoundary @SuppressWarnings("static-method") public Buffer getPathAsBytes(Object path) { - return Buffer.wrap(utf8StringToBytes((String) path)); + return Buffer.wrap(((String) path).getBytes(StandardCharsets.UTF_8)); } @Override @TruffleBoundary public Object createCStringFromString(TruffleString string) { - return checkEmbeddedNulls(TruffleString.ToJavaStringNode.getUncached().execute(string)); + return checkEmbeddedNulls(string.toJavaStringUncached()); } @Override @TruffleBoundary public Object createCStringFromBytes(byte[] bytes) { - return checkEmbeddedNulls(createUTF8String(bytes)); + return checkEmbeddedNulls(new String(bytes, StandardCharsets.UTF_8)); } @Override @TruffleBoundary public Object createWideStringFromString(TruffleString string) { - return checkEmbeddedNulls(TruffleString.ToJavaStringNode.getUncached().execute(string)); + return checkEmbeddedNulls(string.toJavaStringUncached()); } @Override @TruffleBoundary public TruffleString getCStringAsString(Object string) { - return TruffleString.FromJavaStringNode.getUncached().execute((String) string, TS_ENCODING); + return TruffleString.fromJavaStringUncached((String) string, TS_ENCODING); } @Override @TruffleBoundary public Buffer getCStringAsBytes(Object string) { - return Buffer.wrap(utf8StringToBytes((String) string)); - } - - @TruffleBoundary - private static String createUTF8String(byte[] retbuf) { - return new String(retbuf, StandardCharsets.UTF_8); - } - - @TruffleBoundary - private static byte[] utf8StringToBytes(String str) { - return str.getBytes(StandardCharsets.UTF_8); + return Buffer.wrap(((String) string).getBytes(StandardCharsets.UTF_8)); } private static String checkEmbeddedNulls(String s) { @@ -4626,13 +4535,7 @@ private static PosixException posixException(ErrorAndMessagePair pair) throws Po throw new PosixErrnoException(pair.oserror.getNumber(), pair.message); } - @TruffleBoundary - static long fileTimeToSeconds(FileTime t) { - return t.to(TimeUnit.SECONDS); - } - - @TruffleBoundary - static long fileTimeNanoSecondsPart(FileTime t) { + private static long fileTimeNanoSecondsPart(FileTime t) { return t.toInstant().getNano(); } @@ -4661,7 +4564,7 @@ private TruffleFile resolvePath(int dirFd, String pathname) throws PosixExceptio // any error if the file path is already absolute return file; } - String dirPath = getFilePathOrDefault(dirFd); + String dirPath = filePaths.get(dirFd); if (dirPath == null) { throw posixException(OSErrorEnum.EBADF); } @@ -4673,18 +4576,6 @@ private static String pathToJavaString(Object path) { return (String) path; } - @TruffleBoundary(allowInlining = true) - private String getFilePathOrDefault(int fd) { - return filePaths.getOrDefault(fd, null); - } - - @TruffleBoundary(allowInlining = true) - private static FileAttribute> modeToAttributes(int fileMode) { - Set perms = modeToPosixFilePermissions(fileMode); - return PosixFilePermissions.asFileAttribute(perms); - } - - @TruffleBoundary(allowInlining = true) private static Set modeToPosixFilePermissions(int fileMode) { HashSet perms = new HashSet<>(Arrays.asList(ownerBitsToPermission[fileMode >> 6 & 7])); perms.addAll(Arrays.asList(groupBitsToPermission[fileMode >> 3 & 7])); @@ -4692,7 +4583,6 @@ private static Set modeToPosixFilePermissions(int fileMode) return perms; } - @TruffleBoundary(allowInlining = true) private static Set flagsToOptions(int flags) { Set options = new HashSet<>(); int maskedFlags = flags & (O_RDONLY.value | O_WRONLY.value | O_RDWR.value); @@ -4743,7 +4633,7 @@ private static Set flagsToOptions(int flags) { } public static LinkOption[] getLinkOptions(boolean followSymlinks) { - return followSymlinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; + return followSymlinks ? NO_LINK_OPTIONS : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; } private static final TruffleLogger LOGGER = PythonLanguage.getLogger(EmulatedPosixSupport.class); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index b03e091c84..7e948b12c7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -98,7 +98,7 @@ import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNodeGen; +import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; import com.oracle.graal.python.lib.PyUnicodeFSDecoderNode; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.call.CallNode; @@ -1604,7 +1604,7 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, NativeMemory.free(pathPtr); } if (ret != 0 && LOGGER.isLoggable(Level.FINE)) { - log(Level.FINE, "faccessat return value: %d, errno: %d", ret, getErrno()); + LOGGER.fine(String.format("faccessat return value: %d, errno: %d", ret, getErrno())); } return ret == 0; } @@ -3362,11 +3362,6 @@ public PwdResult[] getpwentries() throws PosixException { NativeMemory.free(nativeOutput); NativeMemory.free(nativeBufferSize); } - return toPwdResultArray(result); - } - - @TruffleBoundary - private static PwdResult[] toPwdResultArray(ArrayList result) { return result.toArray(new PwdResult[0]); } @@ -3487,10 +3482,10 @@ private int getSysConfPwdSizeMax() throws PosixException { @SuppressWarnings("static-method") public Object createPathFromString(TruffleString path) { if (WINDOWS) { - TruffleString utf16 = TruffleString.SwitchEncodingNode.getUncached().execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - return checkWidePath(TruffleString.CopyToByteArrayNode.getUncached().execute(utf16, UTF_16LE)); + TruffleString utf16 = path.switchEncodingUncached(UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return checkWidePath(utf16.copyToByteArrayUncached(UTF_16LE)); } - return checkNarrowPath(PyUnicodeEncodeFSDefaultNodeGen.getUncached().execute(null, null, path)); + return checkNarrowPath(PyUnicodeEncodeFSDefaultNode.executeUncached(path)); } @Override @@ -3498,9 +3493,9 @@ public Object createPathFromString(TruffleString path) { @SuppressWarnings("static-method") public Object createPathFromBytes(byte[] path) { if (WINDOWS) { - TruffleString utf8 = TruffleString.FromByteArrayNode.getUncached().execute(path, UTF_8, true); - TruffleString utf16 = TruffleString.SwitchEncodingNode.getUncached().execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(null, path)); - return checkWidePath(TruffleString.CopyToByteArrayNode.getUncached().execute(utf16, UTF_16LE)); + TruffleString utf8 = TruffleString.fromByteArrayUncached(path, UTF_8); + TruffleString utf16 = utf8.switchEncodingUncached(UTF_16LE, windowsPathDecodeErrorHandler(null, path)); + return checkWidePath(utf16.copyToByteArrayUncached(UTF_16LE)); } return checkNarrowPath(path); } @@ -3510,18 +3505,18 @@ public Object createPathFromBytes(byte[] path) { @SuppressWarnings("static-method") public TruffleString getPathAsString(Object path) { NativePath result = (NativePath) path; - TruffleString encoded = TruffleString.FromByteArrayNode.getUncached().execute(result.data, 0, result.data.length, result.encoding(), true); + TruffleString encoded = TruffleString.fromByteArrayUncached(result.data, result.encoding()); if (result instanceof WidePath) { - return TruffleString.SwitchEncodingNode.getUncached().execute(encoded, TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return encoded.switchEncodingUncached(TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); } TruffleString utf8 = encoded; if (TruffleString.IsValidNode.getUncached().execute(utf8, UTF_8)) { - return TruffleString.SwitchEncodingNode.getUncached().execute(utf8, TS_ENCODING); + return utf8.switchEncodingUncached(TS_ENCODING); } TranscodingErrorHandler errorHandler = PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 ? TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8 : PyUnicodeFSDecoderNode.SURROGATE_ESCAPE_FROM_UTF8_TRANSCODING_ERROR_HANDLER; - return TruffleString.SwitchEncodingNode.getUncached().execute(utf8, TS_ENCODING, errorHandler); + return utf8.switchEncodingUncached(TS_ENCODING, errorHandler); } @Override @@ -3570,22 +3565,21 @@ public Object createCStringFromBytes(byte[] bytes) { @Override @TruffleBoundary public Object createWideStringFromString(TruffleString string) { - TruffleString utf16 = TruffleString.SwitchEncodingNode.getUncached().execute(string, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - byte[] bytes = TruffleString.CopyToByteArrayNode.getUncached().execute(utf16, UTF_16LE); + TruffleString utf16 = string.switchEncodingUncached(UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + byte[] bytes = utf16.copyToByteArrayUncached(UTF_16LE); return checkWideString(bytes); } @Override @TruffleBoundary public TruffleString getCStringAsString(Object string) { - TruffleString.FromByteArrayNode fromByteArrayNode = TruffleString.FromByteArrayNode.getUncached(); - TruffleString.SwitchEncodingNode switchEncodingNode = TruffleString.SwitchEncodingNode.getUncached(); if (string instanceof WideString wideString) { - TruffleString utf16 = fromByteArrayNode.execute(wideString.data, UTF_16LE, true); - return switchEncodingNode.execute(utf16, TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + TruffleString utf16 = TruffleString.fromByteArrayUncached(wideString.data, UTF_16LE); + return utf16.switchEncodingUncached(TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); } Buffer buffer = (Buffer) string; - return createString(buffer.data, 0, (int) buffer.length, true, fromByteArrayNode, switchEncodingNode); + TruffleString utf8 = TruffleString.fromByteArrayUncached(buffer.data, 0, (int) buffer.length, UTF_8, true); + return utf8.switchEncodingUncached(TS_ENCODING); } @Override @@ -4030,13 +4024,6 @@ private static void checkBounds(byte[] buf, int offset, int length) { } } - @TruffleBoundary - private static void log(Level level, String fmt, Object... args) { - if (LOGGER.isLoggable(level)) { - LOGGER.log(level, String.format(fmt, args)); - } - } - private int getErrno() { return posixNativeFunctionInvoker.get_errno(); } From 231449e203cad5ad37743cccb52a3c1859822b79 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 1 Oct 2026 11:13:54 +0200 Subject: [PATCH 062/129] Move POSIX string conversions into nodes (cherry picked from commit b8ff82eb994d918ea6bcfb870ee1ffdf8b83c9e8) --- .../oracle/graal/python/test/SocketTests.java | 5 +- .../modules/PathConversionNodeTests.java | 3 +- .../builtins/modules/NtModuleBuiltins.java | 7 +- .../builtins/modules/PosixModuleBuiltins.java | 118 ++-- .../modules/PosixShMemModuleBuiltins.java | 7 +- .../PosixSubprocessModuleBuiltins.java | 4 +- .../builtins/modules/PwdModuleBuiltins.java | 78 ++- .../modules/SocketModuleBuiltins.java | 70 ++- .../builtins/modules/io/FileIOBuiltins.java | 7 +- .../MultiprocessingModuleBuiltins.java | 4 +- .../multiprocessing/SemLockBuiltins.java | 7 +- .../objects/posix/DirEntryBuiltins.java | 15 +- .../builtins/objects/socket/SocketNodes.java | 15 +- .../python/nodes/util/PosixSupportNodes.java | 524 ++++++++++++++++++ .../python/runtime/EmulatedPosixSupport.java | 80 ++- .../python/runtime/LoggingPosixSupport.java | 74 +-- .../python/runtime/NativePosixSupport.java | 247 +++------ .../graal/python/runtime/PosixSupport.java | 41 +- .../python/runtime/PreInitPosixSupport.java | 88 +-- 19 files changed, 907 insertions(+), 487 deletions(-) create mode 100644 graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index 7a3c46bfb9..3ff5eb39fa 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -112,6 +112,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PosixConstants.MandatoryIntConstant; import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupport.AcceptResult; @@ -1069,11 +1070,11 @@ private byte[] getNulTerminatedTempFileName() throws IOException { } private Object s2p(String s) { - return posixSupport.createCStringFromString(toTruffleStringUncached(s)); + return PosixSupportNodes.createCStringFromString(posixSupport, toTruffleStringUncached(s)); } private String p2s(Object p) { - return posixSupport.getCStringAsString(p).toJavaStringUncached(); + return PosixSupportNodes.getCStringAsString(posixSupport, p).toJavaStringUncached(); } private static void expectErrno(ThrowingRunnable runnable, OSErrorEnum... expectedErrorCodes) { diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java index 43cc571c31..29fd96e092 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java @@ -69,6 +69,7 @@ import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.test.PythonTests; import com.oracle.graal.python.util.Function; @@ -92,7 +93,7 @@ public void setUp() { org.junit.Assume.assumeTrue(backendName.equals("java") || !IS_WINDOWS); PythonTests.enterContext(Collections.singletonMap("python.PosixModuleBackend", backendName), new String[0]); PosixSupport posixSupport = PythonContext.get(null).getPosixSupport(); - pathToString = p -> posixSupport.getPathAsString(p.value).toJavaStringUncached(); + pathToString = p -> PosixSupportNodes.getPathAsString(null, posixSupport, p.value).toJavaStringUncached(); } @After diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java index b1036dda6c..2c62d1340b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java @@ -64,6 +64,7 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -120,11 +121,13 @@ private TruffleString getTruffleStringPath(String fspath) { abstract static class PathSplitRootNode extends PythonUnaryClinicBuiltinNode { @Specialization @TruffleBoundary - Object splitroot(PosixPath path) { + Object splitroot(PosixPath path, + @Bind Node inliningTarget, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode) { // TODO should call WINAPI PathCchSkipRoot PythonLanguage language = PythonLanguage.get(null); - TruffleString pathString = getPosixSupport().getPathAsString(path.value); + TruffleString pathString = getPathAsStringNode.execute(inliningTarget, getPosixSupport(), path.value); int len = pathString.codePointLengthUncached(TS_ENCODING); int index = pathString.indexOfCodePointUncached(':', 0, len, TS_ENCODING); if (index <= 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index e6873dab1f..0ad5dc664a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -102,6 +102,7 @@ import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PConstructAndRaiseNode; import com.oracle.graal.python.nodes.PGuards; +import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.builtins.TupleNodes; import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode; @@ -118,6 +119,8 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.util.CastToJavaLongLossyNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; +import com.oracle.graal.python.nodes.util.PosixSupportNodes.DecodeFilesystemStringNode; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; @@ -146,6 +149,7 @@ import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Idempotent; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; @@ -376,11 +380,11 @@ private void populateEnviron(Python3Core core) { Object k; Object v; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { - k = posixSupport.createWideStringFromString(toTruffleStringUncached(pyenvLauncherKey)); - v = posixSupport.createWideStringFromString(value); + k = PosixSupportNodes.createWideStringFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); + v = PosixSupportNodes.createWideStringFromString(posixSupport, value); } else { - k = posixSupport.createPathFromString(toTruffleStringUncached(pyenvLauncherKey)); - v = posixSupport.createPathFromString(value); + k = PosixSupportNodes.createPathFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); + v = PosixSupportNodes.createPathFromString(posixSupport, value); } posixSupport.setenv(k, v, true); } catch (PosixException ignored) { @@ -442,6 +446,7 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object valueObject, @Cached BytesNodes.ToBytesNode toBytesNode, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, + @Cached PosixSupportNodes.CreateWideStringFromStringNode createWideStringFromStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -455,8 +460,8 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object valueObject, if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { TruffleString name = (TruffleString) nameObject; TruffleString value = (TruffleString) valueObject; - nameOpaque = checkNull(inliningTarget, posixSupport.createWideStringFromString(name), raiseNode); - valueOpaque = checkNull(inliningTarget, posixSupport.createWideStringFromString(value), raiseNode); + nameOpaque = checkNull(inliningTarget, createWideStringFromStringNode.execute(inliningTarget, posixSupport, name), raiseNode); + valueOpaque = checkNull(inliningTarget, createWideStringFromStringNode.execute(inliningTarget, posixSupport, value), raiseNode); checkWindowsEnvName(inliningTarget, name, codePointLengthNode, indexOfCodePointNode, raiseNode); } else { byte[] name = toBytesNode.execute((PBytes) nameObject); @@ -519,13 +524,14 @@ static PNone putenv(VirtualFrame frame, Object nameObject, @Cached BytesNodes.ToBytesNode toBytesNode, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, + @Cached PosixSupportNodes.CreateWideStringFromStringNode createWideStringFromStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object nameOpaque; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { TruffleString name = (TruffleString) nameObject; - nameOpaque = checkNull(inliningTarget, context.getPosixSupport().createWideStringFromString(name), raiseNode); + nameOpaque = checkNull(inliningTarget, createWideStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), name), raiseNode); PutenvNode.checkWindowsEnvName(inliningTarget, name, codePointLengthNode, indexOfCodePointNode, raiseNode); } else { byte[] name = toBytesNode.execute((PBytes) nameObject); @@ -567,6 +573,7 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, @Cached PyTupleCheckNode tupleCheckNode, @Cached ToArrayNode toArrayNode, @Cached ObjectToOpaquePathNode toOpaquePathNode, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -588,7 +595,7 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, Object[] opaqueArgs = new Object[args.length]; for (int i = 0; i < args.length; ++i) { Object opaquePath = toOpaquePathNode.execute(frame, inliningTarget, args[i], i == 0); - Buffer bytes = context.getPosixSupport().getPathAsBytes(opaquePath); + Buffer bytes = getPathAsBytesNode.execute(inliningTarget, context.getPosixSupport(), opaquePath); opaqueArgs[i] = context.getPosixSupport().createCStringFromBytes(bytes.data); } LoopNode.reportLoopCount(inliningTarget, args.length); @@ -1771,9 +1778,10 @@ abstract static class GetcwdNode extends PythonBuiltinNode { static TruffleString getcwd(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return context.getPosixSupport().getPathAsString(context.getPosixSupport().getcwd()); + return getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().getcwd()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1787,10 +1795,11 @@ abstract static class GetcwdbNode extends PythonBuiltinNode { static PBytes getcwdb(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object path = context.getPosixSupport().getcwd(); - return opaquePathToBytes(path, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), path, context.getLanguage(inliningTarget)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1940,11 +1949,13 @@ static PList listdirPath(VirtualFrame frame, PosixPath path, @Bind Node inliningTarget, @Bind PythonContext context, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, + @Shared @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Shared @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { return listdir(frame, inliningTarget, context.getPosixSupport().opendir(path.value), path.wasBufferLike, false, constructAndRaiseNode, - context.getLanguage(inliningTarget), context.getPosixSupport()); + context.getLanguage(inliningTarget), context.getPosixSupport(), opaquePathToBytesNode, getPathAsStringNode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1955,14 +1966,18 @@ static PList listdirFd(VirtualFrame frame, PosixFd fd, @Bind Node inliningTarget, @Bind PythonContext context, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, + @Shared @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Shared @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, fd.originalObject); Object dirStream = dupAndFdopendir(frame, inliningTarget, context.getPosixSupport(), fd, constructAndRaiseNode); - return listdir(frame, inliningTarget, dirStream, false, true, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); + return listdir(frame, inliningTarget, dirStream, false, true, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport(), opaquePathToBytesNode, + getPathAsStringNode); } private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dirStream, boolean produceBytes, boolean needsRewind, PConstructAndRaiseNode.Lazy constructAndRaiseNode, - PythonLanguage language, PosixSupport posixSupport) { + PythonLanguage language, PosixSupport posixSupport, OpaquePathToBytesNode opaquePathToBytesNode, + PosixSupportNodes.GetPathAsStringNode getPathAsStringNode) { List list = new ArrayList<>(); try { while (true) { @@ -1972,9 +1987,9 @@ private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dir } Object name = posixSupport.dirEntryGetName(dirEntry); if (produceBytes) { - addToList(list, opaquePathToBytes(name, posixSupport, language)); + addToList(list, opaquePathToBytesNode.execute(inliningTarget, posixSupport, name, language)); } else { - addToList(list, posixSupport.getPathAsString(name)); + addToList(list, getPathAsStringNode.execute(inliningTarget, posixSupport, name)); } } } catch (PosixException e) { @@ -2559,13 +2574,15 @@ static Object readlinkAsBytes(VirtualFrame frame, PosixPath path, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, @Cached InlinedConditionProfile wasBufferLikeProfile, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { Object link = context.getPosixSupport().readlinkat(dirFd, path.value); if (wasBufferLikeProfile.profile(inliningTarget, path.wasBufferLike)) { - return opaquePathToBytes(link, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), link, context.getLanguage(inliningTarget)); } else { - return context.getPosixSupport().getPathAsString(link); + return getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), link); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -2842,6 +2859,7 @@ protected ArgumentClinicProvider getArgumentClinic() { static int system(VirtualFrame frame, Object command, @Bind Node inliningTarget, @Cached BytesNodes.ToBytesNode toBytesNode, + @Cached PosixSupportNodes.CreateWideStringFromStringNode createWideStringFromStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, @Cached GilNode gil) { @@ -2849,14 +2867,14 @@ static int system(VirtualFrame frame, Object command, // conversions for emulated backend because the bytes version after fsencode conversion // is subject to sys.audit. auditNode.audit(frame, inliningTarget, T_OS_SYSTEM, command); + Object cmdOpaque; + if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { + cmdOpaque = createWideStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), (TruffleString) command); + } else { + cmdOpaque = context.getPosixSupport().createCStringFromBytes(toBytesNode.execute((PBytes) command)); + } gil.release(true); try { - Object cmdOpaque; - if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { - cmdOpaque = context.getPosixSupport().createWideStringFromString((TruffleString) command); - } else { - cmdOpaque = context.getPosixSupport().createCStringFromBytes(toBytesNode.execute((PBytes) command)); - } return context.getPosixSupport().system(cmdOpaque); } finally { gil.acquire(); @@ -2977,9 +2995,11 @@ abstract static class CtermId extends PythonBuiltinNode { static TruffleString ctermid(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { + @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, + @Cached DecodeFilesystemStringNode decodeNode) { try { - return context.getPosixSupport().ctermid(); + Object result = context.getPosixSupport().ctermid(); + return decodeNode.execute(inliningTarget, context.getPosixSupport(), result); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -3078,18 +3098,20 @@ abstract static class StringOrBytesToOpaquePathNode extends Node { @Specialization(guards = "isString(strObj)") static Object doString(Node inliningTarget, Object strObj, @Cached CastToTruffleStringNode castToStringNode, + @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Bind PythonContext context, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, strObj); - return checkPath(inliningTarget, context.getPosixSupport().createPathFromString(str), raiseNode); + return checkPath(inliningTarget, createPathFromStringNode.execute(null, inliningTarget, context.getPosixSupport(), str), raiseNode); } @Specialization static Object doBytes(Node inliningTarget, PBytes bytes, @Cached(inline = false) BytesNodes.ToBytesNode toBytesNode, + @Cached PosixSupportNodes.CreatePathFromBytesNode createPathFromBytesNode, @Bind PythonContext context, @Exclusive @Cached PRaiseNode raiseNode) { - return checkPath(inliningTarget, context.getPosixSupport().createPathFromBytes(toBytesNode.execute(bytes)), raiseNode); + return checkPath(inliningTarget, createPathFromBytesNode.execute(inliningTarget, context.getPosixSupport(), toBytesNode.execute(bytes)), raiseNode); } private static Object checkPath(Node inliningTarget, Object path, PRaiseNode raiseNode) { @@ -3271,14 +3293,22 @@ private static BigInteger convertToNanoseconds(long sec, long ns) { return r.add(BigInteger.valueOf(ns)); } - public static PBytes opaquePathToBytes(Object opaquePath, PosixSupport posixSupport, PythonLanguage language) { - Buffer buf = posixSupport.getPathAsBytes(opaquePath); - if (buf.length > Integer.MAX_VALUE) { - // sanity check that it is safe to cast result.length to int, to be removed once - // we support large arrays - throw CompilerDirectives.shouldNotReachHere("Posix path cannot fit into a Java array"); + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class OpaquePathToBytesNode extends PNodeWithContext { + public abstract PBytes execute(Node inliningTarget, PosixSupport posixSupport, Object opaquePath, PythonLanguage language); + + @Specialization + static PBytes doConvert(Node inliningTarget, PosixSupport posixSupport, Object opaquePath, PythonLanguage language, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode) { + Buffer buf = getPathAsBytesNode.execute(inliningTarget, posixSupport, opaquePath); + if (buf.length > Integer.MAX_VALUE) { + // sanity check that it is safe to cast result.length to int, to be removed once + // we support large arrays + throw CompilerDirectives.shouldNotReachHere("Posix path cannot fit into a Java array"); + } + return PFactory.createBytes(language, buf.data, (int) buf.length); } - return PFactory.createBytes(language, buf.data, (int) buf.length); } // ------------------ @@ -3418,11 +3448,13 @@ public PathConversionNode(String functionName, String argumentName, boolean null } @Specialization(guards = "nullable") + @SuppressWarnings("truffle-static-method") // checkPath uses this node's error-message metadata. PosixFileHandle doNone(@SuppressWarnings("unused") PNone value, @Bind Node inliningTarget, @Bind PythonContext context, + @Exclusive @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Exclusive @Cached PRaiseNode raiseNode) { - Object path = context.getPosixSupport().createPathFromString(T_DOT); + Object path = createPathFromStringNode.execute(null, inliningTarget, context.getPosixSupport(), T_DOT); return new PosixPath(null, checkPath(inliningTarget, path, raiseNode), false); } @@ -3459,9 +3491,10 @@ PosixFileHandle doUnicode(Object value, @Bind Node inliningTarget, @Exclusive @Cached CastToTruffleStringNode castToStringNode, @Bind PythonContext context, + @Exclusive @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, value); - Object path = context.getPosixSupport().createPathFromString(str); + Object path = createPathFromStringNode.execute(null, inliningTarget, context.getPosixSupport(), str); return new PosixPath(value, checkPath(inliningTarget, path, raiseNode), false); } @@ -3471,8 +3504,9 @@ PosixFileHandle doBytes(PBytes value, @Bind Node inliningTarget, @Exclusive @Cached BytesNodes.ToBytesNode toByteArrayNode, @Bind PythonContext context, + @Exclusive @Cached PosixSupportNodes.CreatePathFromBytesNode createPathFromBytesNode, @Exclusive @Cached PRaiseNode raiseNode) { - Object path = context.getPosixSupport().createPathFromBytes(toByteArrayNode.execute(value)); + Object path = createPathFromBytesNode.execute(inliningTarget, context.getPosixSupport(), toByteArrayNode.execute(value)); return new PosixPath(value, checkPath(inliningTarget, path, raiseNode), true); } @@ -3496,6 +3530,8 @@ PosixFileHandle doGeneric(VirtualFrame frame, Object value, @Cached("create(T___FSPATH__)") LookupAndCallUnaryNode callFSPath, @Exclusive @Cached BytesNodes.ToBytesNode toByteArrayNode, @Exclusive @Cached CastToTruffleStringNode castToStringNode, + @Exclusive @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, + @Exclusive @Cached PosixSupportNodes.CreatePathFromBytesNode createPathFromBytesNode, @Bind PythonContext context, @Exclusive @Cached PRaiseNode raiseNode) { Object pathObject; @@ -3508,10 +3544,10 @@ PosixFileHandle doGeneric(VirtualFrame frame, Object value, // 'pathObject' replaces 'value' as the PosixPath.originalObject for auditing purposes // by design if (pathObject instanceof PBytes) { - return doBytes((PBytes) pathObject, inliningTarget, toByteArrayNode, context, raiseNode); + return doBytes((PBytes) pathObject, inliningTarget, toByteArrayNode, context, createPathFromBytesNode, raiseNode); } if (PGuards.isString(pathObject)) { - return doUnicode(pathObject, inliningTarget, castToStringNode, context, raiseNode); + return doUnicode(pathObject, inliningTarget, castToStringNode, context, createPathFromStringNode, raiseNode); } throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.EXPECTED_FSPATH_TO_RETURN_STR_OR_BYTES, value, pathObject); } @@ -3731,8 +3767,8 @@ protected PosixFileHandle(Object originalObject) { * Contains the path converted to the representation used by the {@code PosixSupport} * implementation * - * @see PosixSupport#createPathFromString(TruffleString) - * @see PosixSupport#createPathFromBytes(byte[]) + * @See PosixSupportNodes#CreatePathFromStringNode + * @See PosixSupportNodes#CreatePathFromBytesNode */ public static class PosixPath extends PosixFileHandle { public final Object value; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java index 2e40dd5a0c..d95c6f9a8e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java @@ -54,6 +54,7 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -88,9 +89,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static int shmOpen(VirtualFrame frame, TruffleString path, int flags, int mode, @Bind Node inliningTarget, @Bind PythonContext context, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object name = context.getPosixSupport().createCStringFromString(path); + Object name = createCStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), path); return context.getPosixSupport().shmOpen(name, flags, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); @@ -112,9 +114,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone shmUnlink(VirtualFrame frame, TruffleString path, @Bind Node inliningTarget, @Bind PythonContext context, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object name = context.getPosixSupport().createCStringFromString(path); + Object name = createCStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), path); context.getPosixSupport().shmUnlink(name); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java index 94bda1b824..b3f45dee0f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java @@ -83,6 +83,7 @@ import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupport.Buffer; import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -127,6 +128,7 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, @Cached GetSequenceStorageNode getSequenceStorageNode, @Cached IsBuiltinObjectProfile isBuiltinClassProfile, @Cached ObjectToOpaquePathNode objectToOpaquePathNode, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode, @Cached("createNotNormalized()") GetItemNode getItemNode, @Cached PRaiseNode raiseNode) { PList argsList; @@ -148,7 +150,7 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, } Object o = getItemNode.execute(argsStorage, i); Object path = objectToOpaquePathNode.execute(frame, inliningTarget, o, false); - Buffer bytes = context.getPosixSupport().getPathAsBytes(path); + Buffer bytes = getPathAsBytesNode.execute(inliningTarget, context.getPosixSupport(), path); argsArray[i] = context.getPosixSupport().createCStringFromBytes(bytes.data); } LoopNode.reportLoopCount(inliningTarget, len); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java index 09bc67c816..5633aec2b3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java @@ -70,7 +70,12 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; +import com.oracle.graal.python.nodes.util.PosixSupportNodes.DecodeFilesystemStringNode; +import com.oracle.graal.python.runtime.EmulatedPosixSupport.EmulatedPwdResult; import com.oracle.graal.python.runtime.GilNode; +import com.oracle.graal.python.runtime.NativePosixSupport.NativePwdResult; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupport.Buffer; import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PosixSupport.PwdResult; @@ -79,7 +84,11 @@ import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.GenerateCached; +import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; @@ -120,16 +129,49 @@ public void initialize(Python3Core core) { StructSequence.initType(core, STRUCT_PASSWD_DESC); } - private static Object[] createPwuidObject(Node inliningTarget, PwdResult pwd, PythonLanguage language, InlinedConditionProfile unsignedConversionProfile) { - return new Object[]{ - pwd.name, - T_NOT_AVAILABLE, - PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, pwd.uid), - PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, pwd.gid), - /* gecos: */ T_EMPTY_STRING, - pwd.dir, - pwd.shell - }; + @GenerateUncached + @GenerateInline + @GenerateCached(false) + public abstract static class PwdResultToStructSeqNode extends com.oracle.graal.python.nodes.PNodeWithContext { + public abstract Object[] execute(Node inliningTarget, PosixSupport posixSupport, PwdResult pwd); + + @Specialization + static Object[] doNative(Node inliningTarget, PosixSupport posixSupport, NativePwdResult pwd, + @Bind PythonLanguage language, + @Exclusive @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached DecodeFilesystemStringNode decodeNameNode, + @Cached DecodeFilesystemStringNode decodeDirNode, + @Cached DecodeFilesystemStringNode decodeShellNode) { + return createObject(inliningTarget, language, unsignedConversionProfile, + decodeNameNode.execute(inliningTarget, posixSupport, pwd.name), + pwd.uid, pwd.gid, + decodeDirNode.execute(inliningTarget, posixSupport, pwd.dir), + decodeShellNode.execute(inliningTarget, posixSupport, pwd.shell)); + } + + @Specialization + static Object[] doEmulated(@SuppressWarnings("unused") Node inliningTarget, @SuppressWarnings("unused") PosixSupport posixSupport, EmulatedPwdResult pwd, + @Bind PythonLanguage language, + @Exclusive @Cached InlinedConditionProfile unsignedConversionProfile) { + return createObject(inliningTarget, language, unsignedConversionProfile, + TruffleString.fromJavaStringUncached(pwd.name, com.oracle.graal.python.util.PythonUtils.TS_ENCODING), + pwd.uid, pwd.gid, + TruffleString.fromJavaStringUncached(pwd.dir, com.oracle.graal.python.util.PythonUtils.TS_ENCODING), + TruffleString.fromJavaStringUncached(pwd.shell, com.oracle.graal.python.util.PythonUtils.TS_ENCODING)); + } + + private static Object[] createObject(Node inliningTarget, PythonLanguage language, InlinedConditionProfile unsignedConversionProfile, + TruffleString name, long uid, long gid, TruffleString dir, TruffleString shell) { + return new Object[]{ + name, + T_NOT_AVAILABLE, + PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, uid), + PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, gid), + /* gecos: */ T_EMPTY_STRING, + dir, + shell + }; + } } @Builtin(name = "getpwuid", minNumOfPositionalArgs = 1, parameterNames = {"uid"}) @@ -142,7 +184,7 @@ static Object doGetpwuid(VirtualFrame frame, Object uidObj, @Cached UidConversionNode uidConversionNode, @Cached IsBuiltinObjectProfile classProfile, @Cached GilNode gil, - @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached PwdResultToStructSeqNode resultNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { long uid; @@ -169,7 +211,7 @@ static Object doGetpwuid(VirtualFrame frame, Object uidObj, throw raiseUidNotFound(inliningTarget, raiseNode); } PythonLanguage language = context.getLanguage(inliningTarget); - return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, createPwuidObject(inliningTarget, pwd, language, unsignedConversionProfile)); + return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, resultNode.execute(inliningTarget, context.getPosixSupport(), pwd)); } private static PException raiseUidNotFound(Node inliningTarget, PRaiseNode raiseNode) { @@ -193,14 +235,15 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, @Bind PythonContext context, @Cached GilNode gil, @Cached StringOrBytesToOpaquePathNode encodeFSDefault, - @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode, + @Cached PwdResultToStructSeqNode resultNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language, @Cached PRaiseNode raiseNode) { // Note: CPython also takes only Strings, not bytes, and then encodes the String // StringOrBytesToOpaquePathNode already checks for embedded '\0' Object pathEncoded = encodeFSDefault.execute(inliningTarget, name); - Buffer nameBytes = context.getPosixSupport().getPathAsBytes(pathEncoded); + Buffer nameBytes = getPathAsBytesNode.execute(inliningTarget, context.getPosixSupport(), pathEncoded); Object nameEncoded = context.getPosixSupport().createCStringFromBytes(nameBytes.data); PwdResult pwd; try { @@ -216,7 +259,7 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, if (pwd == null) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.KeyError, ErrorMessages.GETPWNAM_NAME_NOT_FOUND, name); } - return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, createPwuidObject(inliningTarget, pwd, context.getLanguage(inliningTarget), unsignedConversionProfile)); + return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, resultNode.execute(inliningTarget, context.getPosixSupport(), pwd)); } } @@ -227,7 +270,7 @@ public abstract static class GetpwallNode extends PythonBuiltinNode { static Object doGetpall(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached PwdResultToStructSeqNode resultNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // We cannot release the GIL, because the underlying POSIX calls are not thread safe PwdResult[] entries; @@ -239,7 +282,8 @@ static Object doGetpall(VirtualFrame frame, PythonLanguage language = context.getLanguage(inliningTarget); Object[] result = new Object[entries.length]; for (int i = 0; i < result.length; i++) { - result[i] = PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, createPwuidObject(inliningTarget, entries[i], language, unsignedConversionProfile)); + result[i] = PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, + resultNode.execute(inliningTarget, context.getPosixSupport(), entries[i])); } LoopNode.reportLoopCount(inliningTarget, result.length); return PFactory.createList(language, result); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index 3081a68e87..1d1c13f7fc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -105,6 +105,7 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; @@ -247,15 +248,18 @@ static TruffleString doGeneric(VirtualFrame frame, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTNAME); try { + Object hostname; gil.release(true); try { - return context.getPosixSupport().getCStringAsString(context.getPosixSupport().gethostname()); + hostname = context.getPosixSupport().gethostname(); } finally { gil.acquire(); } + return getCStringAsStringNode.execute(inliningTarget, context.getPosixSupport(), hostname); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -273,6 +277,8 @@ static Object doGeneric(VirtualFrame frame, Object ip, @Cached SocketNodes.SetIpAddrNode setIpAddrNode, @Cached SequenceStorageNodes.AppendNode appendNode, @Cached SocketNodes.MakeIpAddrNode makeIpAddrNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil) { @@ -285,15 +291,16 @@ static Object doGeneric(VirtualFrame frame, Object ip, int family = addr.getFamily(); try { Object[] getnameinfoResult = context.getPosixSupport().getnameinfo(addr, NI_NAMEREQD.value); - TruffleString hostname = context.getPosixSupport().getCStringAsString(getnameinfoResult[0]); + TruffleString hostname = getCStringAsStringNode.execute(inliningTarget, context.getPosixSupport(), getnameinfoResult[0]); SequenceStorage storage = new ObjectSequenceStorage(5); try { AddrInfoCursor cursor; + Object zero = createCStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), T_ZERO); gil.release(true); try { - cursor = context.getPosixSupport().getaddrinfo(getnameinfoResult[0], context.getPosixSupport().createCStringFromString(T_ZERO), + cursor = context.getPosixSupport().getaddrinfo(getnameinfoResult[0], zero, family, 0, 0, 0); } finally { gil.acquire(); @@ -336,13 +343,14 @@ static TruffleString getHostByName(VirtualFrame frame, Object nameObj, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached SocketNodes.SetIpAddrNode setIpAddrNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] name = idnaConverter.execute(frame, nameObj); auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYNAME, PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{nameObj})); UniversalSockAddr addr = setIpAddrNode.execute(frame, name, AF_INET.value); Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); try { - return context.getPosixSupport().getCStringAsString(context.getPosixSupport().inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); + return getCStringAsStringNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -363,6 +371,7 @@ static Object get(VirtualFrame frame, Object nameObj, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] name = idnaConverter.execute(frame, nameObj); // The event name is really without the _ex, it's not a copy-paste error @@ -377,9 +386,9 @@ static Object get(VirtualFrame frame, Object nameObj, AddrInfoCursor cursor = posixSupport.getaddrinfo(posixSupport.createCStringFromBytes(name), null, AF_INET.value, 0, 0, AI_CANONNAME.value); try { - TruffleString canonName = posixSupport.getCStringAsString(cursor.getCanonName()); + TruffleString canonName = getCStringAsStringNode.execute(inliningTarget, posixSupport, cursor.getCanonName()); Inet4SockAddr inet4SockAddr = cursor.getSockAddr().asInet4SockAddr(); - TruffleString addr = posixSupport.getCStringAsString(posixSupport.inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); + TruffleString addr = getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); // getaddrinfo doesn't support aliases PList aliases = PFactory.createList(context.getLanguage(inliningTarget)); // we support just one address for now @@ -414,6 +423,7 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec @Cached TruffleString.ToJavaStringNode toJavaStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { TruffleString protocolName; @@ -436,11 +446,12 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec } try { + PosixSupport posixSupport = context.getPosixSupport(); + Object service = createCStringFromStringNode.execute(inliningTarget, posixSupport, serviceName); gil.release(true); AddrInfoCursor cursor; try { - PosixSupport posixSupport = context.getPosixSupport(); - cursor = posixSupport.getaddrinfo(null, posixSupport.createCStringFromString(serviceName), AF_INET.value, 0, protocol, 0); + cursor = posixSupport.getaddrinfo(null, service, AF_INET.value, 0, protocol, 0); } finally { gil.acquire(); } @@ -478,6 +489,7 @@ Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, @Cached TruffleString.EqualNode equalNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { TruffleString protocolName; @@ -498,6 +510,7 @@ Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, auditNode.audit(frame, inliningTarget, T_SOCKET_GETSERVBYPORT, port, protocolName != null ? protocolName : T_EMPTY_STRING); try { + Object[] result; gil.release(true); try { UniversalSockAddr addr = getPosixSupport().createUniversalSockAddrInet4(new Inet4SockAddr(port, INADDR_ANY.value)); @@ -505,13 +518,13 @@ Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, if (protocolName != null && equalNode.execute(protocolName, T_UDP, TS_ENCODING)) { flags |= NI_DGRAM.value; } - Object[] result = getPosixSupport().getnameinfo(addr, flags); - TruffleString name = getPosixSupport().getCStringAsString(result[1]); - checkName(name); - return name; + result = getPosixSupport().getnameinfo(addr, flags); } finally { gil.acquire(); } + TruffleString name = getCStringAsStringNode.execute(inliningTarget, getPosixSupport(), result[1]); + checkName(name); + return name; } catch (GetAddrInfoException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SERVICE_PROTO_NOT_FOUND); } catch (PosixException e) { @@ -547,6 +560,8 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, @Cached SequenceStorageNodes.GetItemScalarNode getItem, @Cached CastToTruffleStringNode castAddress, @Cached PyLongAsIntNode asIntNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TruffleString.FromLongNode fromLongNode, @@ -580,12 +595,13 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, try { UniversalSockAddr resolvedAddr; int family; + PosixSupport posixSupport = context.getPosixSupport(); + Object addressOpaque = createCStringFromStringNode.execute(inliningTarget, posixSupport, address); + Object portOpaque = createCStringFromStringNode.execute(inliningTarget, posixSupport, fromLongNode.execute(port, TS_ENCODING, false)); // TODO getaddrinfo lock? gil.release(true); - PosixSupport posixSupport = context.getPosixSupport(); try { - AddrInfoCursor cursor = posixSupport.getaddrinfo(posixSupport.createCStringFromString(address), - posixSupport.createCStringFromString(fromLongNode.execute(port, TS_ENCODING, false)), + AddrInfoCursor cursor = posixSupport.getaddrinfo(addressOpaque, portOpaque, AF_UNSPEC.value, SOCK_DGRAM.value, 0, AI_NUMERICHOST.value); try { family = cursor.getFamily(); @@ -613,8 +629,8 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, } Object[] getnameinfo = posixSupport.getnameinfo(queryAddr, flags); - TruffleString host = posixSupport.getCStringAsString(getnameinfo[0]); - TruffleString service = posixSupport.getCStringAsString(getnameinfo[1]); + TruffleString host = getCStringAsStringNode.execute(inliningTarget, posixSupport, getnameinfo[0]); + TruffleString service = getCStringAsStringNode.execute(inliningTarget, posixSupport, getnameinfo[1]); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{host, service}); } catch (GetAddrInfoException e) { throw constructAndRaiseNode.get(inliningTarget).executeWithArgsOnly(frame, SocketGAIError, new Object[]{e.getErrorCode(), e.getMessageAsTruffleString()}); @@ -657,6 +673,8 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached SequenceStorageNodes.AppendNode appendNode, @Cached TruffleString.FromLongNode fromLongNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object host = null; @@ -668,9 +686,9 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje Object port; Object portObjectProfiled = profile.profile(inliningTarget, portObject); if (PGuards.canBeInteger(portObjectProfiled)) { - port = posixSupport.createCStringFromString(fromLongNode.execute(asLongNode.execute(frame, inliningTarget, portObjectProfiled), TS_ENCODING, false)); + port = createCStringFromStringNode.execute(inliningTarget, posixSupport, fromLongNode.execute(asLongNode.execute(frame, inliningTarget, portObjectProfiled), TS_ENCODING, false)); } else if (PGuards.isString(portObjectProfiled)) { - port = posixSupport.createCStringFromString(castToString.execute(inliningTarget, portObjectProfiled)); + port = createCStringFromStringNode.execute(inliningTarget, posixSupport, castToString.execute(inliningTarget, portObjectProfiled)); } else if (PGuards.isBytes(portObjectProfiled)) { port = posixSupport.createCStringFromBytes(toBytes.execute(frame, portObjectProfiled)); } else if (portObject == PNone.NONE) { @@ -701,7 +719,7 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje Object addr = makeSockAddrNode.execute(frame, inliningTarget, cursor.getSockAddr()); TruffleString canonName = T_EMPTY_STRING; if (cursor.getCanonName() != null) { - canonName = posixSupport.getCStringAsString(cursor.getCanonName()); + canonName = getCStringAsStringNode.execute(inliningTarget, posixSupport, cursor.getCanonName()); } PTuple tuple = PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{cursor.getFamily(), cursor.getSockType(), cursor.getProtocol(), canonName, addr}); @@ -795,10 +813,11 @@ abstract static class InetAtoNNode extends PythonUnaryClinicBuiltinNode { static PBytes doConvert(TruffleString addr, @Bind Node inliningTarget, @Bind PythonContext context, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - int converted = posixSupport.inet_aton(posixSupport.createCStringFromString(addr)); + int converted = posixSupport.inet_aton(createCStringFromStringNode.execute(inliningTarget, posixSupport, addr)); byte[] bytes = new byte[4]; ByteArraySupport.bigEndian().putInt(bytes, 0, converted); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); @@ -823,6 +842,7 @@ static TruffleString doGeneric(VirtualFrame frame, Object addr, @CachedLibrary("addr") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PRaiseNode raiseNode) { Object buffer = bufferAcquireLib.acquireReadonly(addr, frame, callData); try { @@ -833,7 +853,7 @@ static TruffleString doGeneric(VirtualFrame frame, Object addr, } PosixSupport posixSupport = context.getPosixSupport(); Object result = posixSupport.inet_ntoa(ByteArraySupport.bigEndian().getInt(bytes, 0)); - return posixSupport.getCStringAsString(result); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, result); } finally { bufferLib.release(buffer, frame, callData); } @@ -849,11 +869,12 @@ abstract static class InetPtoNNode extends PythonBinaryClinicBuiltinNode { static PBytes doConvert(VirtualFrame frame, int family, TruffleString addr, @Bind Node inliningTarget, @Bind PythonContext context, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - byte[] bytes = posixSupport.inet_pton(family, posixSupport.createCStringFromString(addr)); + byte[] bytes = posixSupport.inet_pton(family, createCStringFromStringNode.execute(inliningTarget, posixSupport, addr)); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -879,6 +900,7 @@ static TruffleString doGeneric(VirtualFrame frame, int family, Object obj, @CachedLibrary("obj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object buffer = bufferAcquireLib.acquireReadonly(obj, frame, callData); @@ -899,7 +921,7 @@ static TruffleString doGeneric(VirtualFrame frame, int family, Object obj, try { PosixSupport posixSupport = context.getPosixSupport(); Object result = posixSupport.inet_ntop(family, bytes); - return posixSupport.getCStringAsString(result); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, result); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index cce71e3894..21fd8e5789 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -141,6 +141,7 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -236,10 +237,11 @@ private static int open(VirtualFrame frame, TruffleString name, int flags, int m PythonContext ctxt, Node inliningTarget, GilNode gil, + PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, InlinedBranchProfile errorProfile, PRaiseNode raiseNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - Object path = ctxt.getPosixSupport().createPathFromString(name); + Object path = createPathFromStringNode.execute(frame, inliningTarget, ctxt.getPosixSupport(), name); if (path == null) { throw raiseNode.raise(inliningTarget, ValueError, EMBEDDED_NULL_BYTE); } @@ -325,6 +327,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object @Cached InlinedBranchProfile exceptionProfile3, @Cached InlinedConditionProfile errorProfile, @Cached(inline = false) GilNode gil, + @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Cached TruffleString.FromLongNode fromLongNode, @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -360,7 +363,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object } if (opener instanceof PNone) { - self.setFD(open(frame, name, flags, 0666, context, inliningTarget, gil, exceptionProfile, raiseNode, constructAndRaiseNode), context); + self.setFD(open(frame, name, flags, 0666, context, inliningTarget, gil, createPathFromStringNode, exceptionProfile, raiseNode, constructAndRaiseNode), context); } else { Object fdobj = callOpener.execute(frame, opener, nameobj, flags); if (!indexCheckNode.execute(inliningTarget, fdobj)) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java index 6523a0c20b..742883b050 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java @@ -61,6 +61,7 @@ import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -168,9 +169,10 @@ abstract static class SemUnlink extends PythonUnaryBuiltinNode { PNone doit(VirtualFrame frame, TruffleString name, @Bind("getPosixSupport()") PosixSupport posixSupport, @Bind Node inliningTarget, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixSupport.semUnlink(posixSupport.createCStringFromString(name)); + posixSupport.semUnlink(createCStringFromStringNode.execute(inliningTarget, posixSupport, name)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java index 289d9ac5dd..642c6ec633 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java @@ -79,6 +79,7 @@ import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PosixSupport.UnsupportedPosixFeatureException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -118,13 +119,14 @@ abstract static class SemLockNode extends PythonClinicBuiltinNode { static PSemLock construct(VirtualFrame frame, Object cls, int kind, int value, int maxValue, TruffleString name, boolean unlink, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { if (kind != PSemLock.RECURSIVE_MUTEX && kind != PSemLock.SEMAPHORE) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.UNRECOGNIZED_KIND); } - Object posixName = posixSupport.createCStringFromString(name); + Object posixName = createCStringFromStringNode.execute(inliningTarget, posixSupport, name); long handle; try { handle = posixSupport.semOpen(posixName, O_CREAT.value | O_EXCL.value, 0600, value); @@ -415,13 +417,14 @@ abstract static class RebuildNode extends PythonClinicBuiltinNode { static Object rebuild(VirtualFrame frame, Object cls, long origHandle, int kind, int maxValue, Object name, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { return PFactory.createSemLock(cls, getInstanceShape.execute(cls), origHandle, kind, maxValue, null); } TruffleString posixNameString = (TruffleString) name; - Object posixName = posixSupport.createCStringFromString(posixNameString); + Object posixName = createCStringFromStringNode.execute(inliningTarget, posixSupport, posixNameString); long handle; try { handle = posixSupport.semOpen(posixName); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java index 94c84a1156..705fb4c983 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java @@ -40,7 +40,6 @@ */ package com.oracle.graal.python.builtins.objects.posix; -import static com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.opaquePathToBytes; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___CLASS_GETITEM__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___FSPATH__; import static com.oracle.graal.python.runtime.PosixConstants.AT_FDCWD; @@ -67,12 +66,14 @@ import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins; import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.PosixFd; import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.PosixPath; +import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.OpaquePathToBytesNode; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.nodes.PConstructAndRaiseNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; @@ -115,12 +116,14 @@ static Object nameAsBytes(VirtualFrame frame, PDirEntry self, @Bind Node inliningTarget, @Bind PythonContext context, @Cached InlinedConditionProfile produceBytesProfile, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { if (produceBytesProfile.profile(inliningTarget, self.produceBytes())) { - return opaquePathToBytes(context.getPosixSupport().dirEntryGetName(self.dirEntryData), context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().dirEntryGetName(self.dirEntryData), context.getLanguage(inliningTarget)); } else { - return context.getPosixSupport().getPathAsString(context.getPosixSupport().dirEntryGetName(self.dirEntryData)); + return getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().dirEntryGetName(self.dirEntryData)); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -157,6 +160,8 @@ static PosixPath createBytes(VirtualFrame frame, Node inliningTarget, PDirEntry @Bind PythonContext context, @Cached InlinedConditionProfile produceBytesProfile, @Cached InlinedConditionProfile posixPathProfile, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Object opaquePath; try { @@ -169,9 +174,9 @@ static PosixPath createBytes(VirtualFrame frame, Node inliningTarget, PDirEntry throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } if (produceBytesProfile.profile(inliningTarget, self.produceBytes())) { - self.pathCache = new PosixPath(opaquePathToBytes(opaquePath, context.getPosixSupport(), context.getLanguage(inliningTarget)), opaquePath, true); + self.pathCache = new PosixPath(opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), opaquePath, context.getLanguage(inliningTarget)), opaquePath, true); } else { - self.pathCache = new PosixPath(context.getPosixSupport().getPathAsString(opaquePath), opaquePath, false); + self.pathCache = new PosixPath(getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), opaquePath), opaquePath, false); } return self.pathCache; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index 1fc12e6d09..6656fab1cd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -82,6 +82,7 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; @@ -272,6 +273,7 @@ public abstract static class SetIpAddrNode extends Node { static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @Bind Node inliningTarget, @Cached InetPtoNCachedPNode inetPtoNCachedPNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached GilNode gil, @Cached PRaiseNode raiseNode) { @@ -279,10 +281,11 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, PosixSupport posixSupport = context.getPosixSupport(); try { if (name.length == 0) { + Object zero = createCStringFromStringNode.execute(inliningTarget, posixSupport, T_ZERO); gil.release(true); try { // TODO getaddrinfo lock? - AddrInfoCursor cursor = posixSupport.getaddrinfo(null, posixSupport.createCStringFromString(T_ZERO), + AddrInfoCursor cursor = posixSupport.getaddrinfo(null, zero, family, SOCK_DGRAM.value, 0, AI_PASSIVE.value); try { if (cursor.next()) { @@ -394,6 +397,7 @@ static Object makeSockAddr(VirtualFrame frame, Node inliningTarget, UniversalSoc @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PRaiseNode raiseNode) { try { PythonContext context = PythonContext.get(inliningTarget); @@ -402,12 +406,12 @@ static Object makeSockAddr(VirtualFrame frame, Node inliningTarget, UniversalSoc if (family == AF_INET.value) { Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); - TruffleString addressString = posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); + TruffleString addressString = getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); return PFactory.createTuple(language, new Object[]{addressString, inet4SockAddr.getPort()}); } else if (family == AF_INET6.value) { Inet6SockAddr inet6SockAddr = addr.asInet6SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); - TruffleString addressString = posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); + TruffleString addressString = getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); return PFactory.createTuple(language, new Object[]{addressString, inet6SockAddr.getPort(), inet6SockAddr.getFlowInfo(), inet6SockAddr.getScopeId()}); } else if (family == AF_UNIX.value) { UnixSockAddr unixSockAddr = addr.asUnixSockAddr(); @@ -450,6 +454,7 @@ public abstract static class MakeIpAddrNode extends Node { @Specialization static Object makeAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PRaiseNode raiseNode) { try { PythonContext context = PythonContext.get(inliningTarget); @@ -457,11 +462,11 @@ static Object makeAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAdd if (family == AF_INET.value) { Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); - return posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); } else if (family == AF_INET6.value) { Inet6SockAddr inet6SockAddr = addr.asInet6SockAddr(); PosixSupport posixSupport = context.getPosixSupport(); - return posixSupport.getCStringAsString(posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); } else { throw raiseNode.raise(inliningTarget, NotImplementedError, toTruffleStringUncached("makesockaddr: unknown address family")); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java new file mode 100644 index 0000000000..aa39be1654 --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java @@ -0,0 +1,524 @@ +/* + * Copyright (c) 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 + * + * 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.util; + +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.UnicodeDecodeError; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.UnicodeEncodeError; +import static com.oracle.graal.python.util.PythonUtils.SURROGATE_CODE_POINT_SET; +import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; +import static com.oracle.truffle.api.strings.TruffleString.Encoding.UTF_16LE; +import static com.oracle.truffle.api.strings.TruffleString.Encoding.UTF_8; + +import java.nio.charset.StandardCharsets; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.PythonOS; +import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; +import com.oracle.graal.python.lib.PyUnicodeFSDecoderNode; +import com.oracle.graal.python.nodes.PNodeWithContext; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.call.CallNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.CreateCStringFromStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.CreatePathFromStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.CreateWideStringFromStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.GetCStringAsStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.GetPathAsStringNodeGen; +import com.oracle.graal.python.runtime.EmulatedPosixSupport; +import com.oracle.graal.python.runtime.LoggingPosixSupport; +import com.oracle.graal.python.runtime.NativePosixSupport; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PreInitPosixSupport; +import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.GenerateUncached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.AbstractTruffleString; +import com.oracle.truffle.api.strings.TranscodingErrorHandler; +import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.api.strings.TruffleString.FromByteArrayNode; +import com.oracle.truffle.api.strings.TruffleString.IsValidNode; +import com.oracle.truffle.api.strings.TruffleString.SwitchEncodingNode; + +/** + * Conversions at the boundary between Python strings and the representation used by a POSIX + * backend. Keeping these operations here is important: POSIX support methods can then exchange + * only their backend-native representations and do not need to materialize TruffleStrings. + */ +public final class PosixSupportNodes { + + private PosixSupportNodes() { + } + + public static Object createPathFromString(PosixSupport posixSupport, TruffleString path) { + return CreatePathFromStringNodeGen.getUncached().execute(null, null, posixSupport, path); + } + + public static TruffleString getPathAsString(Node inliningTarget, PosixSupport posixSupport, Object path) { + return GetPathAsStringNodeGen.getUncached().execute(inliningTarget, posixSupport, path); + } + + public static Object createCStringFromString(PosixSupport posixSupport, TruffleString string) { + return CreateCStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); + } + + public static Object createWideStringFromString(PosixSupport posixSupport, TruffleString string) { + return CreateWideStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); + } + + public static TruffleString getCStringAsString(PosixSupport posixSupport, Object string) { + return GetCStringAsStringNodeGen.getUncached().execute(null, posixSupport, string); + } + + @TruffleBoundary + private static String newStringFromUTF8(byte[] utf8Bytes) { + return new String(utf8Bytes, StandardCharsets.UTF_8); + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class CreatePathFromStringNode extends PNodeWithContext { + public abstract Object execute(Frame frame, Node inliningTarget, PosixSupport posixSupport, TruffleString path); + + @Specialization + static Object doNative(Frame frame, Node inliningTarget, NativePosixSupport posixSupport, TruffleString path, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode, + @Shared @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { + if (isWindows()) { + TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return posixSupport.createRawPath(copyToByteArrayNode.execute(utf16, UTF_16LE), true); + } + return posixSupport.createRawPath(encodeFSDefaultNode.execute(frame, inliningTarget, path), false); + } + + @Specialization + static Object doEmulated(Frame frame, Node inliningTarget, EmulatedPosixSupport posixSupport, TruffleString path, + @Cached TruffleString.ToJavaStringNode toJavaStringNode, + @Shared @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { + String javaPath; + if (isWindows()) { + javaPath = toJavaStringNode.execute(path); + } else { + javaPath = PosixSupportNodes.newStringFromUTF8(encodeFSDefaultNode.execute(frame, inliningTarget, path)); + } + return posixSupport.createRawPath(javaPath); + } + + @Specialization + static Object doLogging(Frame frame, Node inliningTarget, LoggingPosixSupport posixSupport, TruffleString path, + @Shared @Cached(inline = false) CreatePathFromStringNode delegateNode) { + posixSupport.logConversionEnter("createPathFromString", path); + return posixSupport.logConversionExit("createPathFromString", delegateNode.execute(frame, inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static Object doPreInit(Frame frame, Node inliningTarget, PreInitPosixSupport posixSupport, TruffleString path, + @Shared @Cached(inline = false) CreatePathFromStringNode delegateNode) { + return delegateNode.execute(frame, inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class CreatePathFromBytesNode extends PNodeWithContext { + public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, byte[] path); + + @Specialization + static Object doNative(Node inliningTarget, NativePosixSupport posixSupport, byte[] path, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + if (!isWindows()) { + return posixSupport.createRawPath(path, false); + } + TruffleString utf8 = fromByteArrayNode.execute(path, UTF_8, true); + TruffleString utf16 = switchEncodingNode.execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(inliningTarget, path)); + return posixSupport.createRawPath(copyToByteArrayNode.execute(utf16, UTF_16LE), true); + } + + @Specialization + static Object doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, byte[] path) { + return posixSupport.createRawPath(PosixSupportNodes.newStringFromUTF8(path)); + } + + @Specialization + static Object doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, byte[] path, + @Shared @Cached(inline = false) CreatePathFromBytesNode delegateNode) { + posixSupport.logConversionEnter("createPathFromBytes", path); + return posixSupport.logConversionExit("createPathFromBytes", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, byte[] path, + @Shared @Cached(inline = false) CreatePathFromBytesNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class GetPathAsStringNode extends PNodeWithContext { + public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object path); + + @Specialization + static TruffleString doNative(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.IsValidNode isValidNode) { + byte[] data = posixSupport.getRawPathData(path); + if (posixSupport.isWidePath(path)) { + return switchEncodingNode.execute(fromByteArrayNode.execute(data, UTF_16LE, true), TS_ENCODING, + TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + } + return decodeFilesystemString(data, data.length, fromByteArrayNode, switchEncodingNode, isValidNode); + } + + @Specialization + static TruffleString doEmulated(@SuppressWarnings("unused") Node inliningTarget, EmulatedPosixSupport posixSupport, Object path, + @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + return fromJavaStringNode.execute(posixSupport.getRawPath(path), TS_ENCODING); + } + + @Specialization + static TruffleString doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsStringNode delegateNode) { + posixSupport.logConversionEnter("getPathAsString", path); + return posixSupport.logConversionExit("getPathAsString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class GetPathAsBytesNode extends PNodeWithContext { + public abstract Buffer execute(Node inliningTarget, PosixSupport posixSupport, Object path); + + @Specialization + static Buffer doNative(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + byte[] data = posixSupport.getRawPathData(path); + if (!posixSupport.isWidePath(path)) { + return Buffer.wrap(data); + } + TruffleString utf16 = fromByteArrayNode.execute(data, UTF_16LE, true); + TruffleString utf8 = switchEncodingNode.execute(utf16, UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return Buffer.wrap(copyToByteArrayNode.execute(utf8, UTF_8)); + } + + @Specialization + @TruffleBoundary + static Buffer doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, Object path) { + return Buffer.wrap(posixSupport.getRawPath(path).getBytes(StandardCharsets.UTF_8)); + } + + @Specialization + static Buffer doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsBytesNode delegateNode) { + posixSupport.logConversionEnter("getPathAsBytes", path); + return posixSupport.logConversionExit("getPathAsBytes", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static Buffer doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsBytesNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class CreateCStringFromStringNode extends PNodeWithContext { + public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, TruffleString string); + + @Specialization + static Object doNative(Node inliningTarget, NativePosixSupport posixSupport, TruffleString string, + @Cached TruffleString.IsValidNode isValidNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + return posixSupport.createCStringFromBytes(encodeStrictUtf8(inliningTarget, string, isValidNode, switchEncodingNode, copyToByteArrayNode)); + } + + @Specialization + static Object doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, TruffleString string, + @Cached TruffleString.ToJavaStringNode toJavaStringNode) { + return posixSupport.createRawCString(toJavaStringNode.execute(string)); + } + + @Specialization + static Object doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateCStringFromStringNode delegateNode) { + posixSupport.logConversionEnter("createCStringFromString", string); + return posixSupport.logConversionExit("createCStringFromString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateCStringFromStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class CreateWideStringFromStringNode extends PNodeWithContext { + public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, TruffleString string); + + @Specialization + static Object doNative(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, TruffleString string, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString utf16 = switchEncodingNode.execute(string, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return posixSupport.createRawWideString(copyToByteArrayNode.execute(utf16, UTF_16LE)); + } + + @Specialization + static Object doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, TruffleString string, + @Cached TruffleString.ToJavaStringNode toJavaStringNode) { + return posixSupport.createRawWideString(toJavaStringNode.execute(string)); + } + + @Specialization + static Object doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateWideStringFromStringNode delegateNode) { + posixSupport.logConversionEnter("createWideStringFromString", string); + return posixSupport.logConversionExit("createWideStringFromString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateWideStringFromStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class GetCStringAsStringNode extends PNodeWithContext { + public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object string); + + @Specialization + static TruffleString doNative(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object string, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { + byte[] data = posixSupport.getRawStringData(string); + if (posixSupport.isWideString(string)) { + return switchEncodingNode.execute(fromByteArrayNode.execute(data, UTF_16LE, true), TS_ENCODING, + TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + } + return switchEncodingNode.execute(fromByteArrayNode.execute(data, 0, posixSupport.getRawStringLength(string), UTF_8, true), TS_ENCODING); + } + + @Specialization + static TruffleString doEmulated(@SuppressWarnings("unused") Node inliningTarget, EmulatedPosixSupport posixSupport, Object string, + @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + return fromJavaStringNode.execute(posixSupport.getRawCString(string), TS_ENCODING); + } + + @Specialization + static TruffleString doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsStringNode delegateNode) { + posixSupport.logConversionEnter("getCStringAsString", string); + return posixSupport.logConversionExit("getCStringAsString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class GetCStringAsBytesNode extends PNodeWithContext { + public abstract Buffer execute(Node inliningTarget, PosixSupport posixSupport, Object string); + + @Specialization + static Buffer doNative(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object string, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + byte[] data = posixSupport.getRawStringData(string); + if (!posixSupport.isWideString(string)) { + return (Buffer) string; + } + TruffleString utf16 = fromByteArrayNode.execute(data, UTF_16LE, true); + TruffleString utf8 = switchEncodingNode.execute(utf16, UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return Buffer.wrap(copyToByteArrayNode.execute(utf8, UTF_8)); + } + + @Specialization + @TruffleBoundary + static Buffer doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, Object string) { + return Buffer.wrap(posixSupport.getRawCString(string).getBytes(StandardCharsets.UTF_8)); + } + + @Specialization + static Buffer doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsBytesNode delegateNode) { + posixSupport.logConversionEnter("getCStringAsBytes", string); + return posixSupport.logConversionExit("getCStringAsBytes", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static Buffer doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsBytesNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + /** Decodes a native byte field using the filesystem encoding and surrogateescape on Unix. */ + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class DecodeFilesystemStringNode extends PNodeWithContext { + public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object bytes); + + @Specialization + static TruffleString doNative(@SuppressWarnings("unused") Node inliningTarget, @SuppressWarnings("unused") NativePosixSupport posixSupport, + Buffer bytes, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.IsValidNode isValidNode) { + return decodeFilesystemString(bytes.data, (int) bytes.length, fromByteArrayNode, switchEncodingNode, isValidNode); + } + + @Specialization + static TruffleString doEmulated(@SuppressWarnings("unused") Node inliningTarget, + @SuppressWarnings("unused") EmulatedPosixSupport posixSupport, String bytes, + @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + return fromJavaStringNode.execute(bytes, TS_ENCODING); + } + + @Specialization + static TruffleString doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object bytes, + @Shared @Cached(inline = false) DecodeFilesystemStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getDelegate(), bytes); + } + + @Specialization + static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object bytes, + @Shared @Cached(inline = false) DecodeFilesystemStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), bytes); + } + } + + private static boolean isWindows() { + return PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32; + } + + private static byte[] encodeStrictUtf8(Node inliningTarget, TruffleString string, TruffleString.IsValidNode isValidNode, + TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + if (!isValidNode.execute(string, TS_ENCODING)) { + throw raiseSurrogatesEncodeError(inliningTarget, string); + } + TruffleString utf8 = switchEncodingNode.execute(string, UTF_8); + return copyToByteArrayNode.execute(utf8, UTF_8); + } + + @TruffleBoundary + private static PException raiseSurrogatesEncodeError(Node node, TruffleString string) { + int byteIndex = TruffleString.ByteIndexOfCodePointSetNode.getUncached().execute(string, 0, string.byteLength(TS_ENCODING), SURROGATE_CODE_POINT_SET); + int start = byteIndex < 0 ? 0 : byteIndex / 4; + int length = string.codePointLengthUncached(TS_ENCODING); + int end = Math.min(start + 1, length); + while (end < length) { + int codePoint = string.codePointAtIndexUncached(end, TS_ENCODING); + if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) { + break; + } + end++; + } + Object exception = CallNode.executeUncached(UnicodeEncodeError, TruffleString.fromJavaStringUncached("utf-8", TS_ENCODING), string, start, end, + TruffleString.fromJavaStringUncached("surrogates not allowed", TS_ENCODING)); + return PRaiseNode.raiseExceptionObjectStatic(node, exception); + } + + private static TruffleString decodeFilesystemString(byte[] data, int length, + FromByteArrayNode fromByteArrayNode, SwitchEncodingNode switchEncodingNode, + IsValidNode isValidNode) { + TruffleString utf8 = fromByteArrayNode.execute(data, 0, length, UTF_8, true); + if (isValidNode.execute(utf8, UTF_8)) { + return switchEncodingNode.execute(utf8, TS_ENCODING); + } + TranscodingErrorHandler handler = isWindows() ? TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8 : PyUnicodeFSDecoderNode.SURROGATE_ESCAPE_FROM_UTF8_TRANSCODING_ERROR_HANDLER; + return switchEncodingNode.execute(utf8, TS_ENCODING, handler); + } + + private static TranscodingErrorHandler windowsPathDecodeErrorHandler(Node inliningTarget, byte[] input) { + return (AbstractTruffleString sourceString, int byteIndex, int estimatedByteLength, TruffleString.Encoding sourceEncoding, + TruffleString.Encoding targetEncoding) -> { + if (byteIndex + 2 < input.length && (input[byteIndex] & 0xff) == 0xed && + (input[byteIndex + 1] & 0xe0) == 0xa0 && (input[byteIndex + 2] & 0xc0) == 0x80) { + int codePoint = ((input[byteIndex] & 0x0f) << 12) | ((input[byteIndex + 1] & 0x3f) << 6) | (input[byteIndex + 2] & 0x3f); + return new TranscodingErrorHandler.ReplacementString(TruffleString.fromCodePointUncached(codePoint, UTF_16LE, true), 3); + } + Object exception = CallNode.executeUncached(UnicodeDecodeError, + TruffleString.fromJavaStringUncached("utf-8", TS_ENCODING), + com.oracle.graal.python.runtime.object.PFactory.createBytes(PythonLanguage.get(inliningTarget), input), byteIndex, + Math.min(input.length, byteIndex + Math.max(1, estimatedByteLength)), + TruffleString.fromJavaStringUncached("invalid UTF-8 path", TS_ENCODING)); + throw PRaiseNode.raiseExceptionObjectStatic(inliningTarget, exception); + }; + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 16758ead40..d4239c2924 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -280,6 +280,19 @@ */ public final class EmulatedPosixSupport extends PosixResources { + public static final class EmulatedPwdResult extends PwdResult { + public final String name; + public final String dir; + public final String shell; + + public EmulatedPwdResult(String name, long uid, long gid, String dir, String shell) { + super(uid, gid); + this.name = name; + this.dir = dir; + this.shell = shell; + } + } + private static final int MAX_READ = Integer.MAX_VALUE / 2; private static final PosixFilePermission[][] otherBitsToPermission = new PosixFilePermission[][]{ @@ -312,8 +325,7 @@ public final class EmulatedPosixSupport extends PosixResources { new PosixFilePermission[]{PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE}, new PosixFilePermission[]{PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE}, }; - private static final TruffleString T_BIN_SH = tsLiteral("/bin/sh"); - private static final TruffleString T_DEV_TTY = tsLiteral("/dev/tty"); + private static final String T_DEV_TTY = "/dev/tty"; private static final LinkOption[] NO_LINK_OPTIONS = new LinkOption[0]; private final ConcurrentHashMap environ = new ConcurrentHashMap<>(); @@ -2358,7 +2370,7 @@ public OpenPtyResult openpty() throws PosixException { @Override @TruffleBoundary @SuppressWarnings("static-method") - public TruffleString ctermid() { + public String ctermid() { return T_DEV_TTY; } @@ -2982,7 +2994,7 @@ public boolean semTimedWait(Node location, long handle, long deadlineNs) throws @Override @TruffleBoundary - public PwdResult getpwuid(long uid) throws PosixException { + public EmulatedPwdResult getpwuid(long uid) throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { switch (PythonLanguage.getPythonOS()) { case PLATFORM_LINUX: @@ -3002,7 +3014,7 @@ public PwdResult getpwuid(long uid) throws PosixException { @Override @TruffleBoundary - public PwdResult getpwnam(Object name) throws PosixException { + public EmulatedPwdResult getpwnam(Object name) throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { switch (PythonLanguage.getPythonOS()) { case PLATFORM_LINUX: @@ -3028,13 +3040,12 @@ public boolean hasGetpwentries() { @Override @TruffleBoundary - public PwdResult[] getpwentries() throws PosixException { + public EmulatedPwdResult[] getpwentries() throws PosixException { throw createUnsupportedFeature("getpwent"); } - private static PwdResult createPwdResult(UnixSystem unix) { - TruffleString homeDir = toTruffleStringUncached(System.getProperty("user.home")); - return new PwdResult(toTruffleStringUncached(unix.getUsername()), unix.getUid(), unix.getGid(), homeDir, T_BIN_SH); + private static EmulatedPwdResult createPwdResult(UnixSystem unix) { + return new EmulatedPwdResult(unix.getUsername(), unix.getUid(), unix.getGid(), System.getProperty("user.home"), "/bin/sh"); } @Override @@ -4364,40 +4375,20 @@ private static byte[] mapIPv4toIPv6(byte[] ipv4) { } // ------------------ - // Path conversions - - @Override - @TruffleBoundary - public Object createPathFromString(TruffleString path) { - String javaPath = getPythonOS() == PLATFORM_WIN32 ? path.toJavaStringUncached() : new String(PyUnicodeEncodeFSDefaultNode.executeUncached(path), StandardCharsets.UTF_8); - return checkEmbeddedNulls(javaPath); - } + // Raw Java representations used by PosixSupportNodes. - @Override @TruffleBoundary - @SuppressWarnings("static-method") - public Object createPathFromBytes(byte[] path) { - return checkEmbeddedNulls(new String(path, StandardCharsets.UTF_8)); + public Object createRawPath(String path) { + return checkEmbeddedNulls(path); } - @Override - @TruffleBoundary - @SuppressWarnings("static-method") - public TruffleString getPathAsString(Object path) { - return TruffleString.fromJavaStringUncached((String) path, TS_ENCODING); - } - - @Override - @TruffleBoundary - @SuppressWarnings("static-method") - public Buffer getPathAsBytes(Object path) { - return Buffer.wrap(((String) path).getBytes(StandardCharsets.UTF_8)); + public String getRawPath(Object path) { + return (String) path; } - @Override @TruffleBoundary - public Object createCStringFromString(TruffleString string) { - return checkEmbeddedNulls(string.toJavaStringUncached()); + public Object createRawCString(String string) { + return checkEmbeddedNulls(string); } @Override @@ -4406,22 +4397,13 @@ public Object createCStringFromBytes(byte[] bytes) { return checkEmbeddedNulls(new String(bytes, StandardCharsets.UTF_8)); } - @Override @TruffleBoundary - public Object createWideStringFromString(TruffleString string) { - return checkEmbeddedNulls(string.toJavaStringUncached()); + public Object createRawWideString(String string) { + return checkEmbeddedNulls(string); } - @Override - @TruffleBoundary - public TruffleString getCStringAsString(Object string) { - return TruffleString.fromJavaStringUncached((String) string, TS_ENCODING); - } - - @Override - @TruffleBoundary - public Buffer getCStringAsBytes(Object string) { - return Buffer.wrap(((String) string).getBytes(StandardCharsets.UTF_8)); + public String getRawCString(Object string) { + return (String) string; } private static String checkEmbeddedNulls(String s) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index 529f0a7c38..17f02f7a88 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -46,6 +46,7 @@ import java.util.logging.Level; import com.oracle.graal.python.PythonLanguage; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; @@ -83,10 +84,29 @@ public class LoggingPosixSupport extends PosixSupport { protected final PosixSupport delegate; public LoggingPosixSupport(PosixSupport delegate) { + CompilerAsserts.neverPartOfCompilation(); + if (delegate instanceof LoggingPosixSupport) { + throw new IllegalArgumentException(); + } this.delegate = delegate; LOGGER.log(Level.INFO, "Using " + delegate.getClass()); } + public PosixSupport getDelegate() { + assert !(delegate instanceof LoggingPosixSupport); + return delegate; + } + + @TruffleBoundary + public void logConversionEnter(String name, Object argument) { + logEnter(Level.FINEST, name, "%s", argument); + } + + @TruffleBoundary + public T logConversionExit(String name, T result) { + return logExit(Level.FINEST, name, "%s", result); + } + public static boolean isEnabled() { return LoggingPosixSupport.LOGGER.isLoggable(DEFAULT_LEVEL); } @@ -1133,7 +1153,7 @@ public final OpenPtyResult openpty() throws PosixException { @Override @TruffleBoundary - public final TruffleString ctermid() throws PosixException { + public final Object ctermid() throws PosixException { logEnter("ctermid", ""); try { return logExit("ctermid", "%s", delegate.ctermid()); @@ -1680,64 +1700,12 @@ public final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) thr } } - @Override - @TruffleBoundary - public final Object createPathFromString(TruffleString path) { - logEnter(Level.FINEST, "createPathFromString", "%s", path); - return logExit(Level.FINEST, "createPathFromString", "%s", delegate.createPathFromString(path)); - } - - @Override - @TruffleBoundary - public final Object createPathFromBytes(byte[] path) { - logEnter(Level.FINEST, "createPathFromBytes", "%s", path); - return logExit(Level.FINEST, "createPathFromBytes", "%s", delegate.createPathFromBytes(path)); - } - - @Override - @TruffleBoundary - public final TruffleString getPathAsString(Object path) { - logEnter(Level.FINEST, "getPathAsString", "%s", path); - return logExit(Level.FINEST, "getPathAsString", "%s", delegate.getPathAsString(path)); - } - - @Override - @TruffleBoundary - public final Buffer getPathAsBytes(Object path) { - logEnter(Level.FINEST, "getPathAsBytes", "%s", path); - return logExit(Level.FINEST, "getPathAsBytes", "%s", delegate.getPathAsBytes(path)); - } - - @Override - @TruffleBoundary - public final Object createCStringFromString(TruffleString string) { - return delegate.createCStringFromString(string); - } - @Override @TruffleBoundary public final Object createCStringFromBytes(byte[] bytes) { return delegate.createCStringFromBytes(bytes); } - @Override - @TruffleBoundary - public final Object createWideStringFromString(TruffleString string) { - return delegate.createWideStringFromString(string); - } - - @Override - @TruffleBoundary - public final TruffleString getCStringAsString(Object string) { - return delegate.getCStringAsString(string); - } - - @Override - @TruffleBoundary - public final Buffer getCStringAsBytes(Object string) { - return delegate.getCStringAsBytes(string); - } - @TruffleBoundary private static void logEnter(Level level, String msg, String argFmt, Object... args) { if (LOGGER.isLoggable(level)) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 7e948b12c7..b7da1d6cc2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -98,15 +98,12 @@ import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; -import com.oracle.graal.python.lib.PyUnicodeFSDecoderNode; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary; import com.oracle.graal.python.runtime.nativeaccess.NativeLibraryLoadException; import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; -import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.ArrayUtils; @@ -119,8 +116,6 @@ import com.oracle.truffle.api.TruffleSafepoint; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.strings.AbstractTruffleString; -import com.oracle.truffle.api.strings.InternalByteArray; import com.oracle.truffle.api.strings.TranscodingErrorHandler; import com.oracle.truffle.api.strings.TruffleString; @@ -135,6 +130,19 @@ * avoids unconditional FFM call-state capture on the hot POSIX path. */ public final class NativePosixSupport extends PosixSupport { + public static final class NativePwdResult extends PwdResult { + public final Buffer name; + public final Buffer dir; + public final Buffer shell; + + public NativePwdResult(Buffer name, long uid, long gid, Buffer dir, Buffer shell) { + super(uid, gid); + this.name = name; + this.dir = dir; + this.shell = shell; + } + } + private static final String SUPPORTING_NATIVE_LIB_NAME = "posix"; private static final int UNAME_BUF_LENGTH = 256; private static final int DIRENT_NAME_BUF_LENGTH = 256; @@ -1980,12 +1988,16 @@ public OpenPtyResult openpty() throws PosixException { @Override @TruffleBoundary - public TruffleString ctermid() { + public Buffer ctermid() { long nativeBuf = NativeMemory.mallocByteArray(L_ctermid.value); try { posixNativeFunctionInvoker.call_ctermid(nativeBuf); - // TODO PyUnicode_DecodeFSDefault - return NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(nativeBuf); + int length = 0; + while (length < L_ctermid.value && NativeMemory.readByte(nativeBuf + length) != 0) { + length++; + } + byte[] result = NativeMemory.readByteArrayElements(nativeBuf, 0, length); + return Buffer.wrap(result); } finally { NativeMemory.free(nativeBuf); } @@ -3288,17 +3300,17 @@ public boolean semTimedWait(Node location, long handle, long deadlineNs) throws @Override @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult getpwuid(long uid) throws PosixException { - return getpw(uid, NULLPTR, TruffleString.FromByteArrayNode.getUncached(), TruffleString.SwitchEncodingNode.getUncached()); + public NativePwdResult getpwuid(long uid) throws PosixException { + return getpw(uid, NULLPTR); } @Override @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult getpwnam(Object name) throws PosixException { + public NativePwdResult getpwnam(Object name) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { - return getpw(-1, namePtr, TruffleString.FromByteArrayNode.getUncached(), TruffleString.SwitchEncodingNode.getUncached()); + return getpw(-1, namePtr); } finally { NativeMemory.free(namePtr); } @@ -3314,15 +3326,13 @@ public boolean hasGetpwentries() { @Override @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult[] getpwentries() throws PosixException { - TruffleString.FromByteArrayNode fromByteArrayNode = TruffleString.FromByteArrayNode.getUncached(); - TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node = TruffleString.SwitchEncodingNode.getUncached(); + public NativePwdResult[] getpwentries() throws PosixException { // Note: this is not thread safe, so potentially problematic while running multiple contexts // within one VM int sysConfMax = getSysConfPwdSizeMax(); int initialBufferSize = sysConfMax == -1 ? 1024 : sysConfMax; - ArrayList result = new ArrayList<>(); + ArrayList result = new ArrayList<>(); posixNativeFunctionInvoker.call_setpwent(); long nativeBufferSize = NULLPTR; long nativeOutput = NULLPTR; @@ -3354,7 +3364,7 @@ public PwdResult[] getpwentries() throws PosixException { NativeMemory.readByteArrayElements(nativeBuffer, 0, buffer, 0, buffer.length); long[] output = new long[PWD_OUTPUT_LEN]; NativeMemory.readLongArrayElements(nativeOutput, 0, output, 0, output.length); - result.add(createPwdResult(buffer, output, fromByteArrayNode, switchEncodingFromUtf8Node)); + result.add(createPwdResult(buffer, output)); } } finally { posixNativeFunctionInvoker.call_endpwent(); @@ -3362,11 +3372,10 @@ public PwdResult[] getpwentries() throws PosixException { NativeMemory.free(nativeOutput); NativeMemory.free(nativeBufferSize); } - return result.toArray(new PwdResult[0]); + return result.toArray(new NativePwdResult[0]); } - private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode fromByteArrayNode, - TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + private NativePwdResult getpw(long uid, long namePtr) throws PosixException { int sysConfMax = getSysConfPwdSizeMax(); int bufferSize = sysConfMax == -1 ? 1024 : sysConfMax; while (bufferSize < PWD_BUFFER_MAX_SIZE) { @@ -3386,7 +3395,7 @@ private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode NativeMemory.readByteArrayElements(nativeData, 0, data, 0, data.length); long[] output = new long[PWD_OUTPUT_LEN]; NativeMemory.readLongArrayElements(nativeOutput, 0, output, 0, output.length); - return createPwdResult(data, output, fromByteArrayNode, switchEncodingFromUtf8Node); + return createPwdResult(data, output); } if (result != OSErrorEnum.ERANGE.getNumber()) { // CPython treats failed lookups as missing entries, except for ERANGE, @@ -3402,13 +3411,12 @@ private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode throw outOfMemoryPosixError(); } - private static PwdResult createPwdResult(byte[] data, long[] output, TruffleString.FromByteArrayNode fromByteArrayNode, TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) - throws PosixException { - return new PwdResult( - extractZeroTerminatedString(data, output[0], fromByteArrayNode, switchEncodingFromUtf8Node), + private static NativePwdResult createPwdResult(byte[] data, long[] output) throws PosixException { + return new NativePwdResult( + Buffer.wrap(extractZeroTerminatedBytes(data, output[0])), output[1], output[2], - extractZeroTerminatedString(data, output[3], fromByteArrayNode, switchEncodingFromUtf8Node), - extractZeroTerminatedString(data, output[4], fromByteArrayNode, switchEncodingFromUtf8Node)); + Buffer.wrap(extractZeroTerminatedBytes(data, output[3])), + Buffer.wrap(extractZeroTerminatedBytes(data, output[4]))); } @Override @@ -3443,8 +3451,7 @@ public int ioctlInt(int fd, long request, int arg) throws PosixException { return res; } - private static TruffleString extractZeroTerminatedString(byte[] buffer, long longOffset, TruffleString.FromByteArrayNode fromByteArrayNode, - TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + private static byte[] extractZeroTerminatedBytes(byte[] buffer, long longOffset) throws PosixException { if (longOffset < 0 || longOffset >= buffer.length) { throw outOfMemoryPosixError(); } @@ -3454,7 +3461,7 @@ private static TruffleString extractZeroTerminatedString(byte[] buffer, long lon throw CompilerDirectives.shouldNotReachHere("Could not find the end of the string"); } // TODO PyUnicode_DecodeFSDefault - return createString(buffer, offset, end - offset, true, fromByteArrayNode, switchEncodingFromUtf8Node); + return PythonUtils.arrayCopyOfRange(buffer, offset, end); } private static PosixException outOfMemoryPosixError() throws PosixException { @@ -3475,85 +3482,12 @@ private int getSysConfPwdSizeMax() throws PosixException { } // ------------------ - // Path conversions - - @Override - @TruffleBoundary - @SuppressWarnings("static-method") - public Object createPathFromString(TruffleString path) { - if (WINDOWS) { - TruffleString utf16 = path.switchEncodingUncached(UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - return checkWidePath(utf16.copyToByteArrayUncached(UTF_16LE)); - } - return checkNarrowPath(PyUnicodeEncodeFSDefaultNode.executeUncached(path)); - } - - @Override - @TruffleBoundary - @SuppressWarnings("static-method") - public Object createPathFromBytes(byte[] path) { - if (WINDOWS) { - TruffleString utf8 = TruffleString.fromByteArrayUncached(path, UTF_8); - TruffleString utf16 = utf8.switchEncodingUncached(UTF_16LE, windowsPathDecodeErrorHandler(null, path)); - return checkWidePath(utf16.copyToByteArrayUncached(UTF_16LE)); - } - return checkNarrowPath(path); - } - - @Override - @TruffleBoundary - @SuppressWarnings("static-method") - public TruffleString getPathAsString(Object path) { - NativePath result = (NativePath) path; - TruffleString encoded = TruffleString.fromByteArrayUncached(result.data, result.encoding()); - if (result instanceof WidePath) { - return encoded.switchEncodingUncached(TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - } - TruffleString utf8 = encoded; - if (TruffleString.IsValidNode.getUncached().execute(utf8, UTF_8)) { - return utf8.switchEncodingUncached(TS_ENCODING); - } - TranscodingErrorHandler errorHandler = PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 - ? TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8 - : PyUnicodeFSDecoderNode.SURROGATE_ESCAPE_FROM_UTF8_TRANSCODING_ERROR_HANDLER; - return utf8.switchEncodingUncached(TS_ENCODING, errorHandler); - } + // Raw representations used by PosixSupportNodes. These methods deliberately do not create or + // decode TruffleStrings. - @Override @TruffleBoundary - @SuppressWarnings("static-method") - public Buffer getPathAsBytes(Object path) { - NativePath nativePath = (NativePath) path; - if (nativePath instanceof NarrowPath) { - return Buffer.wrap(nativePath.data); - } - TruffleString utf16 = TruffleString.fromByteArrayUncached(nativePath.data, UTF_16LE); - TruffleString utf8 = utf16.switchEncodingUncached(UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - InternalByteArray bytes = utf8.getInternalByteArrayUncached(UTF_8); - return Buffer.wrap(PythonUtils.arrayCopyOfRange(bytes.getArray(), bytes.getOffset(), bytes.getEnd())); - } - - private static TranscodingErrorHandler windowsPathDecodeErrorHandler(Node inliningTarget, byte[] input) { - return (AbstractTruffleString sourceString, int byteIndex, int estimatedByteLength, TruffleString.Encoding sourceEncoding, - TruffleString.Encoding targetEncoding) -> { - if (byteIndex + 2 < input.length && (input[byteIndex] & 0xff) == 0xed && - (input[byteIndex + 1] & 0xe0) == 0xa0 && (input[byteIndex + 2] & 0xc0) == 0x80) { - int codePoint = ((input[byteIndex] & 0x0f) << 12) | ((input[byteIndex + 1] & 0x3f) << 6) | (input[byteIndex + 2] & 0x3f); - return new TranscodingErrorHandler.ReplacementString(TruffleString.fromCodePointUncached(codePoint, UTF_16LE, true), 3); - } - Object exception = CallNode.executeUncached(PythonBuiltinClassType.UnicodeDecodeError, - PythonUtils.toTruffleStringUncached("utf-8"), PFactory.createBytes(PythonLanguage.get(inliningTarget), input), - byteIndex, Math.min(input.length, byteIndex + Math.max(1, estimatedByteLength)), - PythonUtils.toTruffleStringUncached("invalid UTF-8 path")); - throw PRaiseNode.raiseExceptionObjectStatic(inliningTarget, exception); - }; - } - - @Override - @TruffleBoundary - public Object createCStringFromString(TruffleString string) { - return checkCString(getUTF8StringBytes(null, string, TruffleString.SwitchEncodingNode.getUncached(), TruffleString.IsValidNode.getUncached(), - TruffleString.CopyToByteArrayNode.getUncached())); + public Object createRawPath(byte[] data, boolean wide) { + return wide ? checkWidePath(data) : checkNarrowPath(data); } @Override @@ -3562,72 +3496,28 @@ public Object createCStringFromBytes(byte[] bytes) { return checkCString(bytes); } - @Override - @TruffleBoundary - public Object createWideStringFromString(TruffleString string) { - TruffleString utf16 = string.switchEncodingUncached(UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - byte[] bytes = utf16.copyToByteArrayUncached(UTF_16LE); - return checkWideString(bytes); + public Object createRawWideString(byte[] data) { + return checkWideString(data); } - @Override - @TruffleBoundary - public TruffleString getCStringAsString(Object string) { - if (string instanceof WideString wideString) { - TruffleString utf16 = TruffleString.fromByteArrayUncached(wideString.data, UTF_16LE); - return utf16.switchEncodingUncached(TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - } - Buffer buffer = (Buffer) string; - TruffleString utf8 = TruffleString.fromByteArrayUncached(buffer.data, 0, (int) buffer.length, UTF_8, true); - return utf8.switchEncodingUncached(TS_ENCODING); + public byte[] getRawPathData(Object path) { + return ((NativePath) path).data; } - @Override - @TruffleBoundary - public Buffer getCStringAsBytes(Object string) { - if (string instanceof WideString wideString) { - TruffleString utf16 = TruffleString.fromByteArrayUncached(wideString.data, UTF_16LE); - TruffleString utf8 = utf16.switchEncodingUncached(UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - InternalByteArray bytes = utf8.getInternalByteArrayUncached(UTF_8); - return Buffer.wrap(PythonUtils.arrayCopyOfRange(bytes.getArray(), bytes.getOffset(), bytes.getEnd())); - } - return (Buffer) string; + public boolean isWidePath(Object path) { + return ((NativePath) path) instanceof WidePath; } - private static TruffleString createString(byte[] src, int offset, int length, boolean copy, TruffleString.FromByteArrayNode fromByteArrayNode, - TruffleString.SwitchEncodingNode switchEncodingNode) { - TruffleString utf8 = fromByteArrayNode.execute(src, offset, length, UTF_8, copy); - return switchEncodingNode.execute(utf8, TS_ENCODING); + public byte[] getRawStringData(Object string) { + return string instanceof WideString ? ((WideString) string).data : ((Buffer) string).data; } - private static byte[] getUTF8StringBytes(Node node, TruffleString str, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.IsValidNode isValidNode, - TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - if (!isValidNode.execute(str, TS_ENCODING)) { - throw raiseSurrogatesEncodeError(node, str); - } - TruffleString utf8 = switchEncodingNode.execute(str, UTF_8); - byte[] bytes = new byte[utf8.byteLength(UTF_8)]; - copyToByteArrayNode.execute(utf8, 0, bytes, 0, bytes.length, UTF_8); - return bytes; + public boolean isWideString(Object string) { + return string instanceof WideString; } - @TruffleBoundary - private static PException raiseSurrogatesEncodeError(Node node, TruffleString str) { - int byteIndex = TruffleString.ByteIndexOfCodePointSetNode.getUncached().execute(str, 0, str.byteLength(TS_ENCODING), SURROGATE_CODE_POINT_SET); - int start = byteIndex < 0 ? 0 : byteIndex / 4; - int length = str.codePointLengthUncached(TS_ENCODING); - int end = Math.min(start + 1, length); - while (end < length) { - int codePoint = str.codePointAtIndexUncached(end, TS_ENCODING); - if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) { - break; - } - end++; - } - Object exception = CallNode.executeUncached(PythonBuiltinClassType.UnicodeEncodeError, - PythonUtils.toTruffleStringUncached("utf-8"), str, start, end, - PythonUtils.toTruffleStringUncached("surrogates not allowed")); - return PRaiseNode.raiseExceptionObjectStatic(node, exception); + public int getRawStringLength(Object string) { + return string instanceof WideString ? ((WideString) string).data.length : (int) ((Buffer) string).length; } private static Buffer checkCString(byte[] path) { @@ -3998,6 +3888,37 @@ private static long stringToNativeUTF8CString(Node node, TruffleString input, return NativeMemory.copyToNativeZeroTerminatedByteArray(utf8, 0, utf8.length); } + @TruffleBoundary + private static byte[] getUTF8StringBytes(Node node, TruffleString str, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.IsValidNode isValidNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + if (!isValidNode.execute(str, TS_ENCODING)) { + throw raiseSurrogatesEncodeError(node, str); + } + TruffleString utf8 = switchEncodingNode.execute(str, UTF_8); + byte[] bytes = new byte[utf8.byteLength(UTF_8)]; + copyToByteArrayNode.execute(utf8, 0, bytes, 0, bytes.length, UTF_8); + return bytes; + } + + @TruffleBoundary + private static PException raiseSurrogatesEncodeError(Node node, TruffleString str) { + int byteIndex = TruffleString.ByteIndexOfCodePointSetNode.getUncached().execute(str, 0, str.byteLength(TS_ENCODING), SURROGATE_CODE_POINT_SET); + int start = byteIndex < 0 ? 0 : byteIndex / 4; + int length = str.codePointLengthUncached(TS_ENCODING); + int end = Math.min(start + 1, length); + while (end < length) { + int codePoint = str.codePointAtIndexUncached(end, TS_ENCODING); + if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) { + break; + } + end++; + } + Object exception = CallNode.executeUncached(PythonBuiltinClassType.UnicodeEncodeError, + PythonUtils.toTruffleStringUncached("utf-8"), str, start, end, + PythonUtils.toTruffleStringUncached("surrogates not allowed")); + return PRaiseNode.raiseExceptionObjectStatic(node, exception); + } + private static long stringToNativeUTF16CString(TruffleString input, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 3fbbe446e5..a631c75fc2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -102,8 +102,7 @@ public record RusageResult(double ru_utime, double ru_stime, public record OpenPtyResult(int masterFd, int slaveFd) { } - public static final class PwdResult { - public final TruffleString name; + public abstract static class PwdResult { /** * This value represents unsigned 64 bit integer. */ @@ -112,24 +111,9 @@ public static final class PwdResult { * This value represents unsigned 64 bit integer. */ public final long gid; - public final TruffleString dir; - public final TruffleString shell; - - public PwdResult(TruffleString name, long uid, long gid, TruffleString dir, TruffleString shell) { - this.name = name; + protected PwdResult(long uid, long gid) { this.uid = uid; this.gid = gid; - this.dir = dir; - this.shell = shell; - } - - @Override - public String toString() { - return "PwdResult{name='" + name + '\'' + - ", uid=" + uid + - ", gid=" + gid + - ", dir='" + dir + '\'' + - ", shell='" + shell + "'}"; } } @@ -714,29 +698,10 @@ public final long semOpen(Object name) throws PosixException { */ public abstract PwdResult[] getpwentries() throws PosixException; - /** Returns null if the converted path contains embedded null characters. */ - public abstract Object createPathFromString(TruffleString path); - - /** Returns null if the converted path contains embedded null characters. */ - public abstract Object createPathFromBytes(byte[] path); - - public abstract TruffleString getPathAsString(Object path); - - public abstract Buffer getPathAsBytes(Object path); - - /** Converts a string to strict UTF-8 for non-filesystem APIs that use CPython's {@code s} conversion. */ - public abstract Object createCStringFromString(TruffleString string); /** Wraps already-encoded bytes for narrow native APIs without applying a filesystem conversion. */ public abstract Object createCStringFromBytes(byte[] bytes); - /** Converts a string to the UTF-16 representation used by Windows wide-character APIs. */ - public abstract Object createWideStringFromString(TruffleString string); - - public abstract TruffleString getCStringAsString(Object string); - - public abstract Buffer getCStringAsBytes(Object string); - public abstract int socket(int domain, int type, int protocol) throws PosixException; public abstract AcceptResult accept(int sockfd) throws PosixException; @@ -853,7 +818,7 @@ public abstract AddrInfoCursor getaddrinfo(Object node, Object service, int fami public abstract OpenPtyResult openpty() throws PosixException; - public abstract TruffleString ctermid() throws PosixException; + public abstract Object ctermid() throws PosixException; // note: this leaks memory in native backend and is not synchronized public abstract void setenv(Object name, Object value, boolean overwrite) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index 60eec6e40c..993e875763 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -50,9 +50,9 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; -public class PreInitPosixSupport extends PosixSupport { +public final class PreInitPosixSupport extends PosixSupport { - protected final NativePosixSupport nativePosixSupport; + private final NativePosixSupport nativePosixSupport; private EmulatedPosixSupport emulatedPosixSupport; private HashSet emulatedFds; private IdentityHashMap emulatedDirStreams; @@ -68,6 +68,11 @@ public PreInitPosixSupport(Env env, NativePosixSupport nativePosixSupport, Emula } } + /** Returns the backend appropriate for the current execution phase. */ + public PosixSupport getCurrentBackend() { + return inPreInitialization && emulatedPosixSupport != null ? emulatedPosixSupport : nativePosixSupport; + } + @Override public void setEnv(Env env) { assert !env.isPreInitialization(); @@ -837,7 +842,7 @@ public final OpenPtyResult openpty() throws PosixException { @Override @TruffleBoundary - public final TruffleString ctermid() throws PosixException { + public final Object ctermid() throws PosixException { checkNotInPreInitialization(); return nativePosixSupport.ctermid(); } @@ -1222,84 +1227,9 @@ public final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) thr return nativePosixSupport.createUniversalSockAddrUnix(src); } - @Override - @TruffleBoundary - public final Object createPathFromString(TruffleString path) { - if (inPreInitialization) { - return emulatedPosixSupport.createPathFromString(path); - } - return nativePosixSupport.createPathFromString(path); - } - - @Override - @TruffleBoundary - public final Object createPathFromBytes(byte[] path) { - if (inPreInitialization) { - return emulatedPosixSupport.createPathFromBytes(path); - } - return nativePosixSupport.createPathFromBytes(path); - } - - @Override - @TruffleBoundary - public final TruffleString getPathAsString(Object path) { - if (inPreInitialization) { - return emulatedPosixSupport.getPathAsString(path); - } - return nativePosixSupport.getPathAsString(path); - } - - @Override - @TruffleBoundary - public final Buffer getPathAsBytes(Object path) { - if (inPreInitialization) { - return emulatedPosixSupport.getPathAsBytes(path); - } - return nativePosixSupport.getPathAsBytes(path); - } - - @Override - @TruffleBoundary - public final Object createCStringFromString(TruffleString string) { - if (inPreInitialization) { - return emulatedPosixSupport.createCStringFromString(string); - } - return nativePosixSupport.createCStringFromString(string); - } - @Override @TruffleBoundary public final Object createCStringFromBytes(byte[] bytes) { - if (inPreInitialization) { - return emulatedPosixSupport.createCStringFromBytes(bytes); - } - return nativePosixSupport.createCStringFromBytes(bytes); - } - - @Override - @TruffleBoundary - public final Object createWideStringFromString(TruffleString string) { - if (inPreInitialization) { - return emulatedPosixSupport.createWideStringFromString(string); - } - return nativePosixSupport.createWideStringFromString(string); - } - - @Override - @TruffleBoundary - public final TruffleString getCStringAsString(Object string) { - if (inPreInitialization) { - return emulatedPosixSupport.getCStringAsString(string); - } - return nativePosixSupport.getCStringAsString(string); - } - - @Override - @TruffleBoundary - public final Buffer getCStringAsBytes(Object string) { - if (inPreInitialization) { - return emulatedPosixSupport.getCStringAsBytes(string); - } - return nativePosixSupport.getCStringAsBytes(string); + return getCurrentBackend().createCStringFromBytes(bytes); } } From 96aeb1f1c595d44c259074fa75f939ee3868f800 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Fri, 2 Oct 2026 09:53:18 +0200 Subject: [PATCH 063/129] Fix style (cherry picked from commit 570be18ba6e75e9c67f13e2cf69a007ed4fec178) --- .../python/builtins/modules/io/BufferedReaderBuiltins.java | 2 +- .../oracle/graal/python/runtime/EmulatedPosixSupport.java | 2 -- .../src/com/oracle/graal/python/runtime/PosixSupport.java | 7 +++++-- .../src/com/oracle/graal/python/util/TimeUtils.java | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java index 43ecac6a7e..7d4bf8f95c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index d4239c2924..119db224e2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -128,7 +128,6 @@ import static com.oracle.graal.python.runtime.PosixConstants.W_OK; import static com.oracle.graal.python.runtime.PosixConstants.X_OK; import static com.oracle.graal.python.util.PythonUtils.EMPTY_INT_ARRAY; -import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import static com.oracle.truffle.api.CompilerAsserts.neverPartOfCompilation; @@ -227,7 +226,6 @@ import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.ErrorAndMessagePair; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.OperationWouldBlockException; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.runtime.exception.PythonExitException; import com.oracle.graal.python.util.FileDeleteShutdownHook; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index a631c75fc2..de8dedb401 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -50,16 +50,18 @@ import static com.oracle.graal.python.runtime.PosixConstants.S_IFLNK; import static com.oracle.graal.python.runtime.PosixConstants.S_IFMT; import static com.oracle.graal.python.runtime.PosixConstants.S_IFREG; + import java.nio.ByteBuffer; import java.util.Arrays; + import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.CompilerDirectives.ValueType; -import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.TruffleLanguage.Env; +import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -107,10 +109,12 @@ public abstract static class PwdResult { * This value represents unsigned 64 bit integer. */ public final long uid; + /** * This value represents unsigned 64 bit integer. */ public final long gid; + protected PwdResult(long uid, long gid) { this.uid = uid; this.gid = gid; @@ -698,7 +702,6 @@ public final long semOpen(Object name) throws PosixException { */ public abstract PwdResult[] getpwentries() throws PosixException; - /** Wraps already-encoded bytes for narrow native APIs without applying a filesystem conversion. */ public abstract Object createCStringFromBytes(byte[] bytes); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java index 63c5a502c3..d450438724 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 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 From 20da05a12ea2f30b06c4bec191fc8debd67d4a8e Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Fri, 2 Oct 2026 13:56:54 +0200 Subject: [PATCH 064/129] Disable transiently failing test_os.FwalkTests.test_fd_finalization (cherry picked from commit ed267f9fe68c59879ccf7b891fd8b49dea5c1e86) --- .../src/tests/unittest_tags/test_os.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt index 12bb472039..9bf9d69335 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt @@ -81,7 +81,8 @@ test.test_os.FileTests.test_symlink_keywords @ darwin-arm64,linux-aarch64,linux- test.test_os.FileTests.test_write @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64-github test.test_os.FwalkTests.test_compare_to_walk @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_os.FwalkTests.test_dir_fd @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.test_os.FwalkTests.test_fd_finalization @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github +# Assumes stable lowest available FD; unrelated asynchronous finalizers can close descriptors between probes. +!test.test_os.FwalkTests.test_fd_finalization test.test_os.FwalkTests.test_fd_leak @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_os.FwalkTests.test_file_like_path @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_os.FwalkTests.test_walk_above_recursion_limit @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github From 32b5b7f675441d5b3bc10b440aa36e606ca12368 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 8 Oct 2026 14:12:33 +0200 Subject: [PATCH 065/129] Address review comments (cherry picked from commit 66b223a1a7356320571bca9aa9e4e787cbe3a291) --- .../oracle/graal/python/test/SocketTests.java | 4 +- .../modules/PathConversionNodeTests.java | 2 +- .../builtins/modules/PosixModuleBuiltins.java | 8 +- .../python/nodes/util/PosixSupportNodes.java | 150 +++++++++------ .../graal/python/runtime/PosixSupport.java | 182 +++++++++++++++++- 5 files changed, 271 insertions(+), 75 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index 3ff5eb39fa..a795a5b3d3 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -1070,11 +1070,11 @@ private byte[] getNulTerminatedTempFileName() throws IOException { } private Object s2p(String s) { - return PosixSupportNodes.createCStringFromString(posixSupport, toTruffleStringUncached(s)); + return PosixSupportNodes.CreateCStringFromStringNode.executeUncached(posixSupport, toTruffleStringUncached(s)); } private String p2s(Object p) { - return PosixSupportNodes.getCStringAsString(posixSupport, p).toJavaStringUncached(); + return PosixSupportNodes.GetCStringAsStringNode.executeUncached(posixSupport, p).toJavaStringUncached(); } private static void expectErrno(ThrowingRunnable runnable, OSErrorEnum... expectedErrorCodes) { diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java index 29fd96e092..a94b8c4eac 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java @@ -93,7 +93,7 @@ public void setUp() { org.junit.Assume.assumeTrue(backendName.equals("java") || !IS_WINDOWS); PythonTests.enterContext(Collections.singletonMap("python.PosixModuleBackend", backendName), new String[0]); PosixSupport posixSupport = PythonContext.get(null).getPosixSupport(); - pathToString = p -> PosixSupportNodes.getPathAsString(null, posixSupport, p.value).toJavaStringUncached(); + pathToString = p -> PosixSupportNodes.GetPathAsStringNode.executeUncached(posixSupport, p.value).toJavaStringUncached(); } @After diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 0ad5dc664a..3ad864f859 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -380,11 +380,11 @@ private void populateEnviron(Python3Core core) { Object k; Object v; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { - k = PosixSupportNodes.createWideStringFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); - v = PosixSupportNodes.createWideStringFromString(posixSupport, value); + k = PosixSupportNodes.CreateWideStringFromStringNode.executeUncached(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); + v = PosixSupportNodes.CreateWideStringFromStringNode.executeUncached(posixSupport, value); } else { - k = PosixSupportNodes.createPathFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); - v = PosixSupportNodes.createPathFromString(posixSupport, value); + k = PosixSupportNodes.CreatePathFromStringNode.executeUncached(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); + v = PosixSupportNodes.CreatePathFromStringNode.executeUncached(posixSupport, value); } posixSupport.setenv(k, v, true); } catch (PosixException ignored) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java index aa39be1654..ec910f7a8c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java @@ -73,6 +73,8 @@ import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateUncached; +import com.oracle.truffle.api.dsl.Idempotent; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.nodes.Node; @@ -93,26 +95,6 @@ public final class PosixSupportNodes { private PosixSupportNodes() { } - public static Object createPathFromString(PosixSupport posixSupport, TruffleString path) { - return CreatePathFromStringNodeGen.getUncached().execute(null, null, posixSupport, path); - } - - public static TruffleString getPathAsString(Node inliningTarget, PosixSupport posixSupport, Object path) { - return GetPathAsStringNodeGen.getUncached().execute(inliningTarget, posixSupport, path); - } - - public static Object createCStringFromString(PosixSupport posixSupport, TruffleString string) { - return CreateCStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); - } - - public static Object createWideStringFromString(PosixSupport posixSupport, TruffleString string) { - return CreateWideStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); - } - - public static TruffleString getCStringAsString(PosixSupport posixSupport, Object string) { - return GetCStringAsStringNodeGen.getUncached().execute(null, posixSupport, string); - } - @TruffleBoundary private static String newStringFromUTF8(byte[] utf8Bytes) { return new String(utf8Bytes, StandardCharsets.UTF_8); @@ -120,31 +102,41 @@ private static String newStringFromUTF8(byte[] utf8Bytes) { @GenerateUncached @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) public abstract static class CreatePathFromStringNode extends PNodeWithContext { public abstract Object execute(Frame frame, Node inliningTarget, PosixSupport posixSupport, TruffleString path); - @Specialization - static Object doNative(Frame frame, Node inliningTarget, NativePosixSupport posixSupport, TruffleString path, + @TruffleBoundary + public static Object executeUncached(PosixSupport posixSupport, TruffleString path) { + return CreatePathFromStringNodeGen.getUncached().execute(null, null, posixSupport, path); + } + + @Specialization(guards = "isWindows()") + static Object doNativeWindows(@SuppressWarnings("unused") Frame frame, @SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, TruffleString path, @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return posixSupport.createRawPath(copyToByteArrayNode.execute(utf16, UTF_16LE), true); + } + + @Specialization(guards = "!isWindows()") + static Object doNativePosix(Frame frame, Node inliningTarget, NativePosixSupport posixSupport, TruffleString path, @Shared @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { - if (isWindows()) { - TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - return posixSupport.createRawPath(copyToByteArrayNode.execute(utf16, UTF_16LE), true); - } return posixSupport.createRawPath(encodeFSDefaultNode.execute(frame, inliningTarget, path), false); } - @Specialization - static Object doEmulated(Frame frame, Node inliningTarget, EmulatedPosixSupport posixSupport, TruffleString path, - @Cached TruffleString.ToJavaStringNode toJavaStringNode, + @Specialization(guards = "isWindows()") + static Object doEmulatedWindows(@SuppressWarnings("unused") Frame frame, @SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, TruffleString path, + @Cached TruffleString.ToJavaStringNode toJavaStringNode) { + return posixSupport.createRawPath(toJavaStringNode.execute(path)); + } + + @Specialization(guards = "!isWindows()") + static Object doEmulatedPosix(Frame frame, Node inliningTarget, EmulatedPosixSupport posixSupport, TruffleString path, @Shared @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { - String javaPath; - if (isWindows()) { - javaPath = toJavaStringNode.execute(path); - } else { - javaPath = PosixSupportNodes.newStringFromUTF8(encodeFSDefaultNode.execute(frame, inliningTarget, path)); - } + String javaPath = PosixSupportNodes.newStringFromUTF8(encodeFSDefaultNode.execute(frame, inliningTarget, path)); return posixSupport.createRawPath(javaPath); } @@ -164,17 +156,20 @@ static Object doPreInit(Frame frame, Node inliningTarget, PreInitPosixSupport po @GenerateUncached @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) public abstract static class CreatePathFromBytesNode extends PNodeWithContext { public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, byte[] path); - @Specialization - static Object doNative(Node inliningTarget, NativePosixSupport posixSupport, byte[] path, + @Specialization(guards = "!isWindows()") + static Object doNativePosix(@SuppressWarnings("unused") Node inliningTarget, NativePosixSupport posixSupport, byte[] path) { + return posixSupport.createRawPath(path, false); + } + + @Specialization(guards = "isWindows()") + static Object doNativeWindows(Node inliningTarget, NativePosixSupport posixSupport, byte[] path, @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Cached TruffleString.SwitchEncodingNode switchEncodingNode, @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - if (!isWindows()) { - return posixSupport.createRawPath(path, false); - } TruffleString utf8 = fromByteArrayNode.execute(path, UTF_8, true); TruffleString utf16 = switchEncodingNode.execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(inliningTarget, path)); return posixSupport.createRawPath(copyToByteArrayNode.execute(utf16, UTF_16LE), true); @@ -202,20 +197,32 @@ static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, b @GenerateUncached @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) public abstract static class GetPathAsStringNode extends PNodeWithContext { public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object path); - @Specialization - static TruffleString doNative(@SuppressWarnings("unused") Node inliningTarget, + @TruffleBoundary + public static TruffleString executeUncached(PosixSupport posixSupport, Object path) { + return GetPathAsStringNodeGen.getUncached().execute(null, posixSupport, path); + } + + @Specialization(guards = "isWindows()") + static TruffleString doNativeWindows(@SuppressWarnings("unused") Node inliningTarget, NativePosixSupport posixSupport, Object path, - @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Shared @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Shared @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { + byte[] data = posixSupport.getRawPathData(path); + return switchEncodingNode.execute(fromByteArrayNode.execute(data, UTF_16LE, true), TS_ENCODING, + TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + } + + @Specialization(guards = "!isWindows()") + static TruffleString doNativePosix(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path, + @Shared @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Shared @Cached TruffleString.SwitchEncodingNode switchEncodingNode, @Cached TruffleString.IsValidNode isValidNode) { byte[] data = posixSupport.getRawPathData(path); - if (posixSupport.isWidePath(path)) { - return switchEncodingNode.execute(fromByteArrayNode.execute(data, UTF_16LE, true), TS_ENCODING, - TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - } return decodeFilesystemString(data, data.length, fromByteArrayNode, switchEncodingNode, isValidNode); } @@ -241,19 +248,23 @@ static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSup @GenerateUncached @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) public abstract static class GetPathAsBytesNode extends PNodeWithContext { public abstract Buffer execute(Node inliningTarget, PosixSupport posixSupport, Object path); - @Specialization - static Buffer doNative(@SuppressWarnings("unused") Node inliningTarget, + @Specialization(guards = "!isWindows()") + static Buffer doNativePosix(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path) { + return Buffer.wrap(posixSupport.getRawPathData(path)); + } + + @Specialization(guards = "isWindows()") + static Buffer doNativeWindows(@SuppressWarnings("unused") Node inliningTarget, NativePosixSupport posixSupport, Object path, @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Cached TruffleString.SwitchEncodingNode switchEncodingNode, @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { byte[] data = posixSupport.getRawPathData(path); - if (!posixSupport.isWidePath(path)) { - return Buffer.wrap(data); - } TruffleString utf16 = fromByteArrayNode.execute(data, UTF_16LE, true); TruffleString utf8 = switchEncodingNode.execute(utf16, UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); return Buffer.wrap(copyToByteArrayNode.execute(utf8, UTF_8)); @@ -285,6 +296,11 @@ static Buffer doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, O public abstract static class CreateCStringFromStringNode extends PNodeWithContext { public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, TruffleString string); + @TruffleBoundary + public static Object executeUncached(PosixSupport posixSupport, TruffleString string) { + return CreateCStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); + } + @Specialization static Object doNative(Node inliningTarget, NativePosixSupport posixSupport, TruffleString string, @Cached TruffleString.IsValidNode isValidNode, @@ -319,6 +335,11 @@ static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, T public abstract static class CreateWideStringFromStringNode extends PNodeWithContext { public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, TruffleString string); + @TruffleBoundary + public static Object executeUncached(PosixSupport posixSupport, TruffleString string) { + return CreateWideStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); + } + @Specialization static Object doNative(@SuppressWarnings("unused") Node inliningTarget, NativePosixSupport posixSupport, TruffleString string, @@ -354,6 +375,11 @@ static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, T public abstract static class GetCStringAsStringNode extends PNodeWithContext { public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object string); + @TruffleBoundary + public static TruffleString executeUncached(PosixSupport posixSupport, Object string) { + return GetCStringAsStringNodeGen.getUncached().execute(null, posixSupport, string); + } + @Specialization static TruffleString doNative(@SuppressWarnings("unused") Node inliningTarget, NativePosixSupport posixSupport, Object string, @@ -392,16 +418,19 @@ static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSup public abstract static class GetCStringAsBytesNode extends PNodeWithContext { public abstract Buffer execute(Node inliningTarget, PosixSupport posixSupport, Object string); - @Specialization - static Buffer doNative(@SuppressWarnings("unused") Node inliningTarget, + @Specialization(guards = "!posixSupport.isWideString(string)") + static Buffer doNativeNarrow(@SuppressWarnings("unused") Node inliningTarget, + @SuppressWarnings("unused") NativePosixSupport posixSupport, Object string) { + return (Buffer) string; + } + + @Specialization(guards = "posixSupport.isWideString(string)") + static Buffer doNativeWide(@SuppressWarnings("unused") Node inliningTarget, NativePosixSupport posixSupport, Object string, @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Cached TruffleString.SwitchEncodingNode switchEncodingNode, @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { byte[] data = posixSupport.getRawStringData(string); - if (!posixSupport.isWideString(string)) { - return (Buffer) string; - } TruffleString utf16 = fromByteArrayNode.execute(data, UTF_16LE, true); TruffleString utf8 = switchEncodingNode.execute(utf16, UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); return Buffer.wrap(copyToByteArrayNode.execute(utf8, UTF_8)); @@ -463,7 +492,8 @@ static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSup } } - private static boolean isWindows() { + @Idempotent + static boolean isWindows() { return PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index de8dedb401..97a5f718e1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -67,6 +67,15 @@ public abstract class PosixSupport { + /* + * POSIX operations must have @TruffleBoundary on both their declarations and implementations. + * The declaration prevents partial evaluation of unresolved virtual calls and avoids performance + * warnings. After devirtualization, partial evaluation sees the concrete implementation, which + * needs its own annotation because method annotations are not inherited. TruffleString + * conversions that benefit from partial evaluation belong in PosixSupportNodes, outside these + * boundaries. + */ + public static final int ST_MODE = 0; public static final char POSIX_FILENAME_SEPARATOR = '/'; @@ -121,8 +130,6 @@ protected PwdResult(long uid, long gid) { } } - // region Socket addresses - /** * Base class for addresses specific to a particular socket family. * @@ -152,12 +159,16 @@ public int getFamily() { * */ public interface UniversalSockAddr { + @TruffleBoundary int getFamily(); + @TruffleBoundary Inet4SockAddr asInet4SockAddr(); + @TruffleBoundary Inet6SockAddr asInet6SockAddr(); + @TruffleBoundary UnixSockAddr asUnixSockAddr(); } @@ -284,8 +295,6 @@ public byte[] getPath() { } } - // endregion - public static final class AcceptResult { public final int socketFd; public final UniversalSockAddr sockAddr; @@ -318,8 +327,6 @@ public String toString() { } } - // region Name resolution messages - /** * Represents one or more addrinfos returned by {@code getaddrinfo()}. * @@ -329,20 +336,28 @@ public String toString() { * {@link #next()} method. */ public interface AddrInfoCursor { + @TruffleBoundary void release(); + @TruffleBoundary boolean next(); + @TruffleBoundary int getFlags(); + @TruffleBoundary int getFamily(); + @TruffleBoundary int getSockType(); + @TruffleBoundary int getProtocol(); + @TruffleBoundary Object getCanonName(); + @TruffleBoundary UniversalSockAddr getSockAddr(); } @@ -378,8 +393,6 @@ public final Throwable fillInStackTrace() { } } - // endregion - /** * Base class for exceptions that originate in the POSIX support layer. */ @@ -652,34 +665,46 @@ public static PosixSupport get(Node node) { return PythonContext.get(node).getPosixSupport(); } + @TruffleBoundary public abstract long semOpen(Object name, int openFlags, int mode, int value) throws PosixException; + @TruffleBoundary public final long semOpen(Object name) throws PosixException { return semOpen(name, 0, 0, 0); } + @TruffleBoundary public abstract void semClose(long handle) throws PosixException; + @TruffleBoundary public abstract void semUnlink(Object name) throws PosixException; + @TruffleBoundary public abstract int shmOpen(Object name, int openFlags, int mode) throws PosixException; + @TruffleBoundary public abstract void shmUnlink(Object name) throws PosixException; + @TruffleBoundary public abstract int semGetValue(long handle) throws PosixException; + @TruffleBoundary public abstract void semPost(long handle) throws PosixException; + @TruffleBoundary public abstract void semWait(long handle) throws PosixException; + @TruffleBoundary public abstract boolean semTryWait(long handle) throws PosixException; + @TruffleBoundary public abstract boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException; /** * Equivalent of POSIX {@code getpwuid_r}. On top of the error codes defined by POSIX, this may * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. */ + @TruffleBoundary public abstract PwdResult getpwuid(long uid) throws PosixException; /** @@ -688,236 +713,342 @@ public final long semOpen(Object name) throws PosixException { * * @param name the name encoded the same way as paths */ + @TruffleBoundary public abstract PwdResult getpwnam(Object name) throws PosixException; /** * Availability of {@link #getpwentries()}. If {@code false}, then {@link #getpwentries()} will * throw {@link UnsupportedPosixFeatureException}. */ + @TruffleBoundary public abstract boolean hasGetpwentries(); /** * Returns a list of all entries in the password database. Equivalent of using POSIX functions * {@code setpwent}, {@code getpwent}, and {@code endpwent}. */ + @TruffleBoundary public abstract PwdResult[] getpwentries() throws PosixException; /** Wraps already-encoded bytes for narrow native APIs without applying a filesystem conversion. */ + @TruffleBoundary public abstract Object createCStringFromBytes(byte[] bytes); + @TruffleBoundary public abstract int socket(int domain, int type, int protocol) throws PosixException; + @TruffleBoundary public abstract AcceptResult accept(int sockfd) throws PosixException; + @TruffleBoundary public abstract void bind(int sockfd, UniversalSockAddr addr) throws PosixException; + @TruffleBoundary public abstract void connect(int sockfd, UniversalSockAddr addr) throws PosixException; + @TruffleBoundary public abstract void listen(int sockfd, int backlog) throws PosixException; + @TruffleBoundary public abstract UniversalSockAddr getpeername(int sockfd) throws PosixException; + @TruffleBoundary public abstract UniversalSockAddr getsockname(int sockfd) throws PosixException; + @TruffleBoundary public abstract int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; // Unlike POSIX sendto(), we don't support destAddr == null. Use plain send instead. + @TruffleBoundary public abstract int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException; + @TruffleBoundary public abstract int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; // For STREAM sockets, the returned address will be AF_UNSPEC + @TruffleBoundary public abstract RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; + @TruffleBoundary public abstract void shutdown(int sockfd, int how) throws PosixException; + @TruffleBoundary public abstract int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; + @TruffleBoundary public abstract void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; + @TruffleBoundary public abstract int inet_addr(Object src); + @TruffleBoundary public abstract int inet_aton(Object src) throws InvalidAddressException; + @TruffleBoundary public abstract Object inet_ntoa(int address); + @TruffleBoundary public abstract byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException; + @TruffleBoundary public abstract Object inet_ntop(int family, byte[] src) throws PosixException; + @TruffleBoundary public abstract Object gethostname() throws PosixException; + @TruffleBoundary public abstract Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException; /** The caller must release the returned cursor exactly once. */ + @TruffleBoundary public abstract AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException; + @TruffleBoundary public abstract int ioctlBytes(int fd, long request, byte[] arg) throws PosixException; + @TruffleBoundary public abstract int ioctlInt(int fd, long request, int arg) throws PosixException; + @TruffleBoundary public abstract UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src); + @TruffleBoundary public abstract UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src); + @TruffleBoundary public abstract UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException; + @TruffleBoundary public abstract void raise(int signal) throws PosixException; + @TruffleBoundary public abstract int alarm(int seconds) throws PosixException; + @TruffleBoundary public abstract Timeval[] getitimer(int which) throws PosixException; + @TruffleBoundary public abstract Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException; + @TruffleBoundary public abstract void signalSelf(int signal) throws PosixException; + @TruffleBoundary public abstract void kill(long pid, int signal) throws PosixException; + @TruffleBoundary public abstract void killpg(long pid, int signal) throws PosixException; + @TruffleBoundary public abstract long[] waitpid(Node location, long pid, int options) throws PosixException; + @TruffleBoundary public abstract boolean wcoredump(int status); + @TruffleBoundary public abstract boolean wifcontinued(int status); + @TruffleBoundary public abstract boolean wifstopped(int status); + @TruffleBoundary public abstract boolean wifsignaled(int status); + @TruffleBoundary public abstract boolean wifexited(int status); + @TruffleBoundary public abstract int wexitstatus(int status); + @TruffleBoundary public abstract int wtermsig(int status); + @TruffleBoundary public abstract int wstopsig(int status); + @TruffleBoundary public abstract long getuid(); + @TruffleBoundary public abstract long geteuid() throws UnsupportedPosixFeatureException; + @TruffleBoundary public abstract long getgid(); + @TruffleBoundary public abstract long getegid() throws UnsupportedPosixFeatureException; + @TruffleBoundary public abstract long getppid() throws UnsupportedPosixFeatureException; + @TruffleBoundary public abstract long getpgid(long pid) throws PosixException; + @TruffleBoundary public abstract void setpgid(long pid, long pgid) throws PosixException; + @TruffleBoundary public abstract long getpgrp() throws UnsupportedPosixFeatureException; + @TruffleBoundary public abstract long getsid(long pid) throws PosixException; + @TruffleBoundary public abstract long setsid() throws PosixException; + @TruffleBoundary public abstract long[] getgroups() throws PosixException; + @TruffleBoundary public abstract RusageResult getrusage(int who) throws PosixException; + @TruffleBoundary public abstract OpenPtyResult openpty() throws PosixException; + @TruffleBoundary public abstract Object ctermid() throws PosixException; // note: this leaks memory in native backend and is not synchronized + @TruffleBoundary public abstract void setenv(Object name, Object value, boolean overwrite) throws PosixException; + @TruffleBoundary public abstract void unsetenv(Object name) throws PosixException; + @TruffleBoundary public abstract int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException; // args.length must be > 0 + @TruffleBoundary public abstract void execv(Object pathname, Object[] args) throws PosixException; // does not throw, because posix does not exactly define the return value + @TruffleBoundary public abstract int system(Object command); + @TruffleBoundary public abstract Object mmap(Node location, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException; + @TruffleBoundary public abstract byte mmapReadByte(Object mmap, long index) throws PosixException; + @TruffleBoundary public abstract void mmapWriteByte(Object mmap, long index, byte value) throws PosixException; + @TruffleBoundary public abstract int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException; + @TruffleBoundary public abstract void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException; + @TruffleBoundary public abstract void mmapFlush(Object mmap, long offset, long length) throws PosixException; + @TruffleBoundary public abstract void mmapUnmap(Object mmap, long length) throws PosixException; + @TruffleBoundary public abstract long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureException; + @TruffleBoundary public abstract TruffleString getBackend(); + @TruffleBoundary public abstract TruffleString strerror(int errorCode); + @TruffleBoundary public abstract long getpid(); + @TruffleBoundary public abstract int umask(int mask) throws PosixException; + @TruffleBoundary public abstract int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException; + @TruffleBoundary public abstract int close(int fd) throws PosixException; + @TruffleBoundary public abstract long getOsfHandle(int fd) throws PosixException; + @TruffleBoundary public abstract int openOsfHandle(long handle, int flags) throws PosixException; + @TruffleBoundary public abstract int setMode(int fd, int mode) throws PosixException; + @TruffleBoundary public abstract void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException; + @TruffleBoundary public abstract int[] pipe() throws PosixException; + @TruffleBoundary public abstract SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException; + @TruffleBoundary public abstract void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException; + @TruffleBoundary public abstract long lseek(int fd, long offset, int how) throws PosixException; + @TruffleBoundary public abstract void ftruncate(int fd, long length) throws PosixException; + @TruffleBoundary public abstract void truncate(Object path, long length) throws PosixException; + @TruffleBoundary public abstract void fsync(int fd) throws PosixException; + @TruffleBoundary public abstract void flock(int fd, int operation) throws PosixException; + @TruffleBoundary public abstract void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException; + @TruffleBoundary public abstract boolean getBlocking(int fd) throws PosixException; + @TruffleBoundary public abstract void setBlocking(int fd, boolean blocking) throws PosixException; + @TruffleBoundary public abstract int[] getTerminalSize(int fd) throws PosixException; + @TruffleBoundary public abstract long sysconf(int name) throws PosixException; + @TruffleBoundary public abstract Buffer read(int fd, long length) throws PosixException; + @TruffleBoundary public abstract long write(int fd, Buffer data) throws PosixException; /** Returns {@code 'r'}, {@code 'w'}, or zero when {@code fd} is not a Windows console. */ + @TruffleBoundary public abstract int getWindowsConsoleType(int fd); + @TruffleBoundary public abstract long writeWindowsConsole(int fd, Buffer data) throws PosixException; + @TruffleBoundary public abstract int dup(int fd) throws PosixException; + @TruffleBoundary public abstract int dup2(int fd, int fd2, boolean inheritable) throws PosixException; + @TruffleBoundary public abstract boolean getInheritable(int fd) throws PosixException; + @TruffleBoundary public abstract void setInheritable(int fd, boolean inheritable) throws PosixException; // see stat_struct_to_longs in posix.c for the layout of the array + @TruffleBoundary public abstract long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException; /** @@ -928,12 +1059,16 @@ public abstract int forkExec(Object[] executables, Object[] args, Object cwd, Ob * constants for some of the indices, e.g., {@link #ST_MODE}. * @throws PosixException if an error occurs */ + @TruffleBoundary public abstract long[] fstat(int fd) throws PosixException; + @TruffleBoundary public abstract long[] statvfs(Object path) throws PosixException; + @TruffleBoundary public abstract long[] fstatvfs(int fd) throws PosixException; + @TruffleBoundary public abstract Object[] uname() throws PosixException; public record WindowsVersion(int major, int minor, int build, int platform, TruffleString servicePack, @@ -942,72 +1077,103 @@ public record WindowsVersion(int major, int minor, int build, int platform, Truf } /** Returns the Windows version and product information. */ + @TruffleBoundary public abstract WindowsVersion getWindowsVersion() throws PosixException; + @TruffleBoundary public abstract void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException; + @TruffleBoundary public abstract void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException; + @TruffleBoundary public abstract void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException; + @TruffleBoundary public abstract void mkdirat(int dirFd, Object pathname, int mode) throws PosixException; + @TruffleBoundary public abstract Object getcwd() throws PosixException; + @TruffleBoundary public abstract void chdir(Object path) throws PosixException; + @TruffleBoundary public abstract void fchdir(int fd) throws PosixException; + @TruffleBoundary public abstract boolean isatty(int fd); /** Caller is responsible for closing the returned directory stream with {@link #closedir(Object)}. */ + @TruffleBoundary public abstract Object opendir(Object path) throws PosixException; + @TruffleBoundary public abstract Object fdopendir(int fd) throws PosixException; /** Implementations must deal with this being called more than once. */ + @TruffleBoundary public abstract void closedir(Object dirStream) throws PosixException; /** Returns null when there are no more entries or the stream has been closed. */ + @TruffleBoundary public abstract Object readdir(Object dirStream) throws PosixException; + @TruffleBoundary public abstract void rewinddir(Object dirStream); /** Returns an opaque directory-entry name suitable for path conversion. */ + @TruffleBoundary public abstract Object dirEntryGetName(Object dirEntry) throws PosixException; /** Returns the entry name joined to the path originally passed to {@link #opendir(Object)}. */ + @TruffleBoundary public abstract Object dirEntryGetPath(Object dirEntry, Object scandirPath) throws PosixException; + @TruffleBoundary public abstract long dirEntryGetInode(Object dirEntry) throws PosixException; + @TruffleBoundary public abstract int dirEntryGetType(Object dirEntry); /** The timespec contains access seconds/nanoseconds, then modification seconds/nanoseconds, or is null for now. */ + @TruffleBoundary public abstract void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException; + @TruffleBoundary public abstract void futimens(int fd, long[] timespec) throws PosixException; /** The timeval is null or contains access and modification times. */ + @TruffleBoundary public abstract void futimes(int fd, Timeval[] timeval) throws PosixException; + @TruffleBoundary public abstract void lutimes(Object filename, Timeval[] timeval) throws PosixException; + @TruffleBoundary public abstract void utimes(Object filename, Timeval[] timeval) throws PosixException; + @TruffleBoundary public abstract void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; + @TruffleBoundary public abstract void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; + @TruffleBoundary public abstract boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException; + @TruffleBoundary public abstract void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException; + @TruffleBoundary public abstract void fchmod(int fd, int mode) throws PosixException; + @TruffleBoundary public abstract void fchownat(int dirFd, Object pathname, long owner, long group, boolean followSymlinks) throws PosixException; + @TruffleBoundary public abstract void fchown(int fd, long owner, long group) throws PosixException; + @TruffleBoundary public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } From 0063860b0e5d58a4325187dd51b70eaea47a7812 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 9 Oct 2026 10:21:34 +0200 Subject: [PATCH 066/129] Fix swapped failed and unknown states on compatibility page (cherry picked from commit 213c26e78a3c04a8a733fa205e4b68c940a7270a) --- docs/site/_includes/compatibility.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/site/_includes/compatibility.html b/docs/site/_includes/compatibility.html index 6c22511b7c..0b506ae571 100644 --- a/docs/site/_includes/compatibility.html +++ b/docs/site/_includes/compatibility.html @@ -310,10 +310,10 @@ countCompatible++; break; case 1: - countUntested++; + countIncompatible++; break; case 2: - countIncompatible++; + countUntested++; break; case 3: countNotSupported++; From 821d66ede3619ecfaaa16fa201f2b31efdb374cc Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 9 Oct 2026 10:26:30 +0200 Subject: [PATCH 067/129] Fix threshold value in tooltips (cherry picked from commit 4eb4ef478cd87f08e56ba643f073efdb13c17959) --- docs/site/_includes/compatibility.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/site/_includes/compatibility.html b/docs/site/_includes/compatibility.html index 0b506ae571..a15b949970 100644 --- a/docs/site/_includes/compatibility.html +++ b/docs/site/_includes/compatibility.html @@ -543,14 +543,14 @@

    Over 600 Python packages tested for compatibility
    Compatible: loading...
    + title="More than 75% of the package's tests run successfully on GraalPy">Compatible: loading...
    Currently Untested: loading...
    Currently + title="Fewer than 75% of the package's tests run successfully on GraalPy">Currently Incompatible: loading...
    Not From 6396a5d351f4fc586b179678a7ef0eb8fc7e215c Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 9 Oct 2026 10:36:57 +0200 Subject: [PATCH 068/129] Change wording of Incompatible category (cherry picked from commit cedf51156daa2f38be9459a02a0efd48726d921b) --- docs/site/_includes/compatibility.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/site/_includes/compatibility.html b/docs/site/_includes/compatibility.html index a15b949970..ca1560f265 100644 --- a/docs/site/_includes/compatibility.html +++ b/docs/site/_includes/compatibility.html @@ -551,7 +551,7 @@

    Over 600 Python packages tested for compatibility
    Currently - Incompatible: loading...
    + Failing Tests: loading...
    Not Supported: loading...
    From 8495ef6ba5af1117793bb17ca4f72d2163a425ab Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 9 Oct 2026 10:50:09 +0200 Subject: [PATCH 069/129] Don't include metadata entries in aggregate test results (cherry picked from commit c9121ec536fefa2523a2d7bce49d45d22fe3b69e) --- docs/site/_includes/compatibility.html | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/site/_includes/compatibility.html b/docs/site/_includes/compatibility.html index ca1560f265..c2f273b10f 100644 --- a/docs/site/_includes/compatibility.html +++ b/docs/site/_includes/compatibility.html @@ -87,7 +87,7 @@ const parts = item.name.split('.'); const package_name = parts[0]; const version = parts.slice(1, -1).join('.') || DB.ANY_VERSION; - packages.push(`${package_name},${version},0,${BUILD_SCRIPT_AVAILABLE(item.html_url)}`); + packages.push(`${package_name},${version},,${BUILD_SCRIPT_AVAILABLE(item.html_url)}`); } resolve(packages.join("\n")); } else { @@ -116,7 +116,7 @@ patches.push( [currentPatch.name, currentPatch.version, - 0, + '', currentPatch.comment || PATCH_AVAILABLE].join(",") ) } @@ -143,7 +143,7 @@ patches.push( [currentPatch.name, currentPatch.version, - 0, + '', currentPatch.comment || PATCH_AVAILABLE].join(",") ) } @@ -285,11 +285,11 @@ load_db(graalpyModuleValue).then(function (db_contents) { database = new DB("python", db_contents); const rowsPerPage = getRowsPerPage(); - let count = 0; let countCompatible = 0; let countUntested = 0; let countIncompatible = 0; let countNotSupported = 0; + let tableRowCount = 0; $('#dataTable tbody').empty(); for (let package in database.db) { const versions = database.db[package]; @@ -300,7 +300,7 @@ if (versionA > versionB) return 1; return 0; }); - versions_loop: for (const version of version_keys) { + for (const version of version_keys) { if (version.startsWith('~')) { continue; } @@ -318,10 +318,8 @@ case 3: countNotSupported++; break; - default: - continue versions_loop; } - const styling = count++ < rowsPerPage ? '' : ' style="display: none;"'; + const styling = tableRowCount++ < rowsPerPage ? '' : ' style="display: none;"'; const highlight = ''.repeat(Math.ceil(info.highlight)); $('#dataTable tbody').append(` @@ -332,6 +330,7 @@ } } $('#compatibility_page__search-field').trigger("input"); + const count = countCompatible + countUntested + countIncompatible + countNotSupported; updateStatistics(count, countCompatible, countUntested, countIncompatible, countNotSupported); updatePagination(true); }); From 3f5ee7f37a0443e4e5cf059a7988289fbe69e7be Mon Sep 17 00:00:00 2001 From: Graeme Rocher Date: Fri, 9 Oct 2026 13:02:59 +0200 Subject: [PATCH 070/129] Set sysconfig TZPATH on POSIX so zoneinfo finds system time zones zoneinfo falls back to sysconfig's TZPATH, which CPython's configure sets to /usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/etc/zoneinfo by default. GraalPy did not define it, so zoneinfo.TZPATH was empty and ZoneInfo needed the tzdata package. Windows keeps an empty TZPATH. Fixes #1206 Signed-off-by: Graeme Rocher (cherry picked from commit ecdd07c6117e7e14f12ffad363415f982ccc302b) --- .../src/tests/test_sysconfig.py | 12 ++++++++++++ graalpython/lib-graalpython/_sysconfig.py | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py b/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py index fdf49f6847..1434e5a962 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py @@ -60,6 +60,18 @@ def test_platform_sysconfigdata(): assert sys.abiflags in sysconfig.get_config_var("INCLUDEPY") +@unittest.skipIf(sys.platform == "win32", "Windows has no system time zone database") +def test_tzpath_searches_system_time_zones(): + import sysconfig + tzpath = sysconfig.get_config_var("TZPATH") + assert tzpath == "/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/etc/zoneinfo", tzpath + import os + import subprocess + env = {k: v for k, v in os.environ.items() if k != "PYTHONTZPATH"} + out = subprocess.check_output([sys.executable, "-c", "import zoneinfo; print(':'.join(zoneinfo.TZPATH))"], env=env, text=True) + assert out.strip() == tzpath, out + + @unittest.skipUnless(sys.platform == "win32", "Windows-specific sysconfig behavior") def test_windows_libpython_is_not_exposed(): import sysconfig diff --git a/graalpython/lib-graalpython/_sysconfig.py b/graalpython/lib-graalpython/_sysconfig.py index f8bfb242ea..916e3de2ba 100644 --- a/graalpython/lib-graalpython/_sysconfig.py +++ b/graalpython/lib-graalpython/_sysconfig.py @@ -38,6 +38,9 @@ # SOFTWARE. +_DEFAULT_TZPATH = "/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/etc/zoneinfo" + + def _append_flags(g, key, flags): value = g.get(key, "") parts = value.split() @@ -102,4 +105,8 @@ def _update_posix_vars(config_vars=None): _setdefault(config_vars, 'LIBDIR', __graalpython__.capi_home) _setdefault(config_vars, 'LIBDEST', __graalpython__.capi_home) _setdefault(config_vars, 'LIBPL', __graalpython__.capi_home.replace(os.path.sep, '/')) + if not win32_native: + # zoneinfo searches the system time zone database in TZPATH; use the + # locations CPython's configure uses by default (--with-tzpath) + _setdefault(config_vars, 'TZPATH', _DEFAULT_TZPATH) return config_vars From 6001bb25d1c2e3d009d3ad9bd16454718203c24f Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 24 Sep 2026 16:53:29 +0200 Subject: [PATCH 071/129] Reduce temporary bytearray allocations in PPickler (cherry picked from commit 5edd93e7e83e6169324384746c75e22b8a06092b) --- .../builtins/modules/pickle/PPickler.java | 513 +++++++++--------- .../builtins/modules/pickle/PickleUtils.java | 76 --- 2 files changed, 246 insertions(+), 343 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index de1e0508e8..b27219e9f2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -49,7 +49,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE__; import static com.oracle.graal.python.nodes.StringLiterals.T_NEWLINE; -import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; @@ -71,6 +70,7 @@ import com.oracle.graal.python.builtins.objects.PNotImplemented; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAcquireLibrary; +import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.common.HashingStorage; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIterator; @@ -124,6 +124,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; +import com.oracle.truffle.api.strings.TranscodingErrorHandler; import com.oracle.truffle.api.strings.TruffleString; public class PPickler extends PythonBuiltinObject { @@ -471,12 +472,85 @@ public static void handleError(PPickler pickler) { protected void writeASCII(PPickler pickler, TruffleString string) { assert string.getCodeRangeUncached(TS_ENCODING) == TruffleString.CodeRange.ASCII; - final byte[] bytes = PythonUtils.getAsciiBytes(string, ensureTsCopyToByteArrayNode(), ensureTsSwitchEncodingNode()); - write(pickler, bytes, bytes.length); + TruffleString encoded = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.US_ASCII); + int length = encoded.byteLength(TruffleString.Encoding.US_ASCII); + ensureBufferSpace(pickler, length); + ensureTsCopyToByteArrayNode().execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.US_ASCII); + pickler.outputLen += length; + } + + protected void writeUtf8(PPickler pickler, TruffleString string) { + TruffleString encoded = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + int length = encoded.byteLength(TruffleString.Encoding.UTF_8); + ensureBufferSpace(pickler, length); + ensureTsCopyToByteArrayNode().execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.UTF_8); + pickler.outputLen += length; + } + + protected void writeLongAsString(PPickler pickler, byte opcode, long value) { + TruffleString string = ensureTsFromLongNode().execute(value, TruffleString.Encoding.US_ASCII, true); + TruffleString.Encoding encoding = TruffleString.Encoding.US_ASCII; + int length = string.byteLength(encoding); + ensureBufferSpace(pickler, length + 2); + pickler.outputBuffer[pickler.outputLen++] = opcode; + ensureTsCopyToByteArrayNode().execute(string, 0, pickler.outputBuffer, pickler.outputLen, length, encoding); + pickler.outputLen += length; + pickler.outputBuffer[pickler.outputLen++] = NEW_LINE_BYTE; + } + + protected void write(PPickler pickler, byte b) { + ensureBufferSpace(pickler, 1); + pickler.outputBuffer[pickler.outputLen++] = b; + } + + protected void write(PPickler pickler, byte b1, byte b2) { + ensureBufferSpace(pickler, 2); + pickler.outputBuffer[pickler.outputLen++] = b1; + pickler.outputBuffer[pickler.outputLen++] = b2; + } + + protected void writeBuffer(PPickler pickler, Object buffer, int size, PythonBufferAccessLibrary bufferLib) { + ensureBufferSpace(pickler, size); + bufferLib.readIntoByteArray(buffer, 0, pickler.outputBuffer, pickler.outputLen, size); + pickler.outputLen += size; + } + + protected static byte intByte1(long value) { + return (byte) (value & 0xff); + } + + protected static byte intByte2(long value) { + return (byte) ((value >> 8) & 0xff); + } + + protected static byte intByte3(long value) { + return (byte) ((value >> 16) & 0xff); + } + + protected static byte intByte4(long value) { + return (byte) ((value >> 24) & 0xff); + } + + protected void writeByteOp(PPickler pickler, byte opcode, long value) { + ensureBufferSpace(pickler, 2); + pickler.outputBuffer[pickler.outputLen++] = opcode; + pickler.outputBuffer[pickler.outputLen++] = intByte1(value); + } + + protected void writeShortOp(PPickler pickler, byte opcode, long value) { + ensureBufferSpace(pickler, 3); + pickler.outputBuffer[pickler.outputLen++] = opcode; + pickler.outputBuffer[pickler.outputLen++] = intByte1(value); + pickler.outputBuffer[pickler.outputLen++] = intByte2(value); } - protected void write(PPickler pickler, byte oneByte) { - write(pickler, new byte[]{oneByte}, 1); + protected void writeIntOp(PPickler pickler, byte opcode, long value) { + ensureBufferSpace(pickler, 5); + pickler.outputBuffer[pickler.outputLen++] = opcode; + pickler.outputBuffer[pickler.outputLen++] = intByte1(value); + pickler.outputBuffer[pickler.outputLen++] = intByte2(value); + pickler.outputBuffer[pickler.outputLen++] = intByte3(value); + pickler.outputBuffer[pickler.outputLen++] = intByte4(value); } protected void write(PPickler pickler, byte[] bytes) { @@ -484,6 +558,12 @@ protected void write(PPickler pickler, byte[] bytes) { } protected void write(PPickler pickler, byte[] bytes, int dataLen) { + ensureBufferSpace(pickler, dataLen); + PythonUtils.arraycopy(bytes, 0, pickler.outputBuffer, pickler.outputLen, dataLen); + pickler.outputLen += dataLen; + } + + public void ensureBufferSpace(PPickler pickler, int dataLen) { boolean needNewFrame = pickler.isFraming() && pickler.frameStart == -1; int n = (needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; int required = pickler.outputLen + n; @@ -495,7 +575,7 @@ protected void write(PPickler pickler, byte[] bytes, int dataLen) { throw raise(PythonBuiltinClassType.MemoryError); } pickler.maxOutputLen = (pickler.outputLen + n) / 2 * 3; - pickler.outputBuffer = PickleUtils.resize(pickler.outputBuffer, pickler.maxOutputLen); + pickler.outputBuffer = PythonUtils.arrayCopyOf(pickler.outputBuffer, pickler.maxOutputLen); } if (needNewFrame) { int frameStart = pickler.outputLen; @@ -506,13 +586,10 @@ protected void write(PPickler pickler, byte[] bytes, int dataLen) { } pickler.outputLen += PickleUtils.FRAME_HEADER_SIZE; } - PythonUtils.arraycopy(bytes, 0, pickler.outputBuffer, pickler.outputLen, dataLen); - pickler.outputLen += dataLen; } - protected void writeBytes(VirtualFrame frame, PPickler pickler, byte[] header, int headerSize, byte[] data, int dataSize, Object payload) { + protected boolean bypassBuffer(PPickler pickler, int dataSize) { boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; - boolean framing = pickler.framing; if (bypassBuffer) { assert pickler.outputBuffer != null; @@ -521,28 +598,7 @@ protected void writeBytes(VirtualFrame frame, PPickler pickler, byte[] header, i // Disable framing temporarily pickler.framing = false; } - - write(pickler, header, headerSize); - - if (bypassBuffer && pickler.write != null) { - // Dump the output buffer to the file. - flushToFile(frame, pickler); - // Stream write the payload into the file without going through the output buffer. - Object pld = payload; - if (pld == null) { - // TODO: It would be better to use a memoryview with a linked original string if - // this is possible. - pld = PFactory.createBytes(PythonLanguage.get(this), data, dataSize); - } - getCallNode().execute(frame, pickler.write, pld); - // Reinitialize the buffer for subsequent calls to _Pickler_Write. - pickler.clearBuffer(); - } else { - write(pickler, data, dataSize); - } - - // Re-enable framing for subsequent calls to _Pickler_Write. - pickler.framing = framing; + return bypassBuffer; } protected PTuple createTuple(Object... items) { @@ -880,32 +936,19 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, Object obj) { // memo methods private void memoGet(PPickler pickler, int value) { - int len; - byte[] pdata; if (pickler.isBin()) { - pdata = new byte[5]; if (value < 256) { - pdata[0] = PickleUtils.OPCODE_BINGET; - pdata[1] = (byte) (value & 0xff); - len = 2; + writeByteOp(pickler, PickleUtils.OPCODE_BINGET, value); } else if (Long.compareUnsigned(value, 0xffffffffL) <= 0) { - pdata[0] = PickleUtils.OPCODE_LONG_BINGET; - pdata[1] = (byte) (value & 0xff); - pdata[2] = (byte) ((value >> 8) & 0xff); - pdata[3] = (byte) ((value >> 16) & 0xff); - pdata[4] = (byte) ((value >> 24) & 0xff); - len = 5; + writeIntOp(pickler, PickleUtils.OPCODE_LONG_BINGET, value); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINGET"); } } else { - pdata = new byte[30]; - pdata[0] = PickleUtils.OPCODE_GET; - len = PickleUtils.toAsciiBytesWithNewLine(pdata, 1, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + writeLongAsString(pickler, PickleUtils.OPCODE_GET, value); } - write(pickler, pdata, len); } private void memoPut(PPickler pickler, Object obj) { @@ -918,33 +961,19 @@ private void memoPut(PPickler pickler, Object obj) { if (pickler.proto >= 4) { write(pickler, PickleUtils.OPCODE_MEMOIZE); - return; } else { - byte[] pdata; - int len; if (!pickler.isBin()) { - pdata = new byte[30]; - pdata[0] = PickleUtils.OPCODE_PUT; - len = PickleUtils.toAsciiBytesWithNewLine(pdata, 1, idx, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + writeLongAsString(pickler, PickleUtils.OPCODE_PUT, idx); } else { - pdata = new byte[5]; if (idx < 256) { - pdata[0] = PickleUtils.OPCODE_BINPUT; - pdata[1] = (byte) idx; - len = 2; + writeByteOp(pickler, PickleUtils.OPCODE_BINPUT, idx); } else if (Long.compareUnsigned(idx, 0xffffffffL) <= 0) { - pdata[0] = PickleUtils.OPCODE_LONG_BINPUT; - pdata[1] = (byte) (idx & 0xff); - pdata[2] = (byte) ((idx >> 8) & 0xff); - pdata[3] = (byte) ((idx >> 16) & 0xff); - pdata[4] = (byte) ((idx >> 24) & 0xff); - len = 5; + writeIntOp(pickler, PickleUtils.OPCODE_LONG_BINPUT, idx); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINPUT"); } } - write(pickler, pdata, len); } } @@ -1205,41 +1234,20 @@ private void saveBool(VirtualFrame frame, PPickler pickler, Object obj) { private void saveLong(VirtualFrame frame, PPickler pickler, Object obj) { TruffleString repr; try { - long value = asLong(frame, obj); - if (value <= 0x7fffffffL && value >= (-0x7fffffffL - 1)) { - // result fits in a signed 4-byte integer. Note: we can't use -0x80000000L in - // the above condition because some compilers (e.g., MSVC) will promote - // 0x80000000L to an unsigned type before applying the unary minus when - // sizeof(long) <= 4. The resulting value stays unsigned which is commonly not - // what we want, so MSVC happily warns us about it. However, that result would - // have been fine because we guard for sizeof(long) <= 4 which turns the - // condition true in that particular case. - byte[] pdata; - int len; - + long longValue = asLong(frame, obj); + int value = (int) longValue; + if (value == longValue) { if (pickler.isBin()) { - pdata = new byte[5]; - pdata[1] = (byte) (value & 0xff); - pdata[2] = (byte) ((value >> 8) & 0xff); - pdata[3] = (byte) ((value >> 16) & 0xff); - pdata[4] = (byte) ((value >> 24) & 0xff); - - if ((pdata[4] != 0) || (pdata[3] != 0)) { - pdata[0] = PickleUtils.OPCODE_BININT; - len = 5; - } else if (pdata[2] != 0) { - pdata[0] = PickleUtils.OPCODE_BININT2; - len = 3; + if (value >= 0 && value < (1 << 8)) { + writeByteOp(pickler, PickleUtils.OPCODE_BININT1, value); + } else if (value >= 0 && value < (1 << 16)) { + writeShortOp(pickler, PickleUtils.OPCODE_BININT2, value); } else { - pdata[0] = PickleUtils.OPCODE_BININT1; - len = 2; + writeIntOp(pickler, PickleUtils.OPCODE_BININT, value); } } else { - pdata = new byte[32]; - pdata[0] = PickleUtils.OPCODE_INT; - len = PickleUtils.toAsciiBytesWithNewLine(pdata, 1, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + writeLongAsString(pickler, PickleUtils.OPCODE_INT, longValue); } - write(pickler, pdata, len); return; } } catch (PException e) { @@ -1247,14 +1255,9 @@ private void saveLong(VirtualFrame frame, PPickler pickler, Object obj) { } if (pickler.proto >= 2) { - byte[] header = new byte[5]; // Linear-time pickling. final int sign = getSign(obj); - if (sign == 0) { - header[0] = PickleUtils.OPCODE_LONG1; - header[1] = 0; - write(pickler, header, 2); - } + assert sign != 0; // Zero was handled by the int code above final int nbits = getNumBits(obj); // How many bytes do we need? There are nbits >> 3 full bytes of data, and nbits & 7 @@ -1276,22 +1279,12 @@ private void saveLong(VirtualFrame frame, PPickler pickler, Object obj) { if (sign < 0 && nbytes > 1 && pdata[nbytes - 1] == (byte) 0xff && (pdata[nbytes - 2] & 0x80) != 0) { nbytes--; } - int size; if (nbytes < 256) { - header[0] = PickleUtils.OPCODE_LONG1; - header[1] = (byte) nbytes; - size = 2; + writeByteOp(pickler, PickleUtils.OPCODE_LONG1, nbytes); } else { - header[0] = PickleUtils.OPCODE_LONG4; - size = nbytes; - for (int i = 1; i < 5; i++) { - header[i] = (byte) (size & 0xff); - size >>= 8; - } - size = 5; + writeIntOp(pickler, PickleUtils.OPCODE_LONG4, nbytes); } - write(pickler, header, size); write(pickler, pdata, nbytes); } else { @@ -1305,10 +1298,10 @@ private void saveLong(VirtualFrame frame, PPickler pickler, Object obj) { private void saveFloat(VirtualFrame frame, PPickler pickler, Object obj, Node inliningTarget, PyFloatAsDoubleNode asDoubleNode) { final double value = asDoubleNode.execute(frame, inliningTarget, obj); if (pickler.isBin()) { - byte[] pdata = new byte[9]; - pdata[0] = PickleUtils.OPCODE_BINFLOAT; - NumericSupport.bigEndian().putDouble(pdata, 1, value); - write(pickler, pdata, 9); + write(pickler, PickleUtils.OPCODE_BINFLOAT); + ensureBufferSpace(pickler, 8); + NumericSupport.bigEndian().putDouble(pickler.outputBuffer, pickler.outputLen, value); + pickler.outputLen += 8; } else { write(pickler, PickleUtils.OPCODE_FLOAT); TruffleString repr = PickleUtils.doubleToAsciiString(value); @@ -1319,6 +1312,7 @@ private void saveFloat(VirtualFrame frame, PPickler pickler, Object obj, Node in private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj, InteropCallData interopCallData) { Object buffer = getBufferAcquireLibrary().acquireReadonly(obj, frame, interopCallData); + PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { if (pickler.proto < 3) { // Older pickle protocols do not have an opcode for pickling bytes objects. @@ -1333,107 +1327,119 @@ private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, // need to do this with newer protocols. Object reduceValue; - if (getBufferLibrary().getBufferLength(buffer) == 0) { + if (bufferLib.getBufferLength(buffer) == 0) { reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PBytes), createTuple()); } else { PickleState st = getGlobalState(ctx.getCore()); - final TruffleString unicodeStr = PickleUtils.decodeLatin1Strict(getBufferLibrary().getCopiedByteArray(buffer), ensureTsFromByteArrayWithCompaction()); + final TruffleString unicodeStr = PickleUtils.decodeLatin1Strict(bufferLib.getCopiedByteArray(buffer), ensureTsFromByteArrayWithCompaction()); reduceValue = createTuple(st.codecsEncode, createTuple(unicodeStr, LATIN1)); } // save_reduce() will memoize the object automatically. saveReduce(frame, ctx, pickler, reduceValue, obj); } else { - byte[] bytes = getBufferLibrary().getCopiedByteArray(buffer); - saveBytesData(frame, pickler, obj, bytes, bytes.length); + saveBytesData(frame, pickler, obj, buffer, bufferLib); } } finally { - getBufferLibrary().release(buffer, frame, interopCallData); + bufferLib.release(buffer, frame, interopCallData); } } - private void saveBytesData(VirtualFrame frame, PPickler pickler, Object obj, byte[] data, int size) { + private void saveBytesData(VirtualFrame frame, PPickler pickler, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { assert pickler.proto >= 3; - byte[] header = new byte[9]; - int len; + int size = bufferLib.getBufferLength(buffer); + boolean wasFraming = pickler.framing; + boolean bypassBuffer = bypassBuffer(pickler, size); if (size <= 0xff) { - header[0] = PickleUtils.OPCODE_SHORT_BINBYTES; - header[1] = (byte) size; - len = 2; - } else if (Long.compareUnsigned(size, 0xffffffffL) < 0) { - header[0] = PickleUtils.OPCODE_BINBYTES; - header[1] = (byte) (size & 0xff); - header[2] = (byte) ((size >> 8) & 0xff); - header[3] = (byte) ((size >> 16) & 0xff); - header[4] = (byte) ((size >> 24) & 0xff); - len = 5; - } else if (pickler.proto >= 4) { - header[0] = PickleUtils.OPCODE_BINBYTES8; - PickleUtils.writeSize64(header, 1, size); - len = 9; + writeByteOp(pickler, PickleUtils.OPCODE_SHORT_BINBYTES, size); } else { - throw raise(OverflowError, ErrorMessages.SER_OVER_4GB); + writeIntOp(pickler, PickleUtils.OPCODE_BINBYTES, size); } - writeBytes(frame, pickler, header, len, data, size, obj); + if (bypassBuffer && pickler.write != null) { + flushToFile(frame, pickler); + getCallNode().execute(frame, pickler.write, obj); + pickler.clearBuffer(); + } else { + writeBuffer(pickler, buffer, size, bufferLib); + } + + if (bypassBuffer && wasFraming) { + pickler.framing = true; + } memoPut(pickler, obj); } private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, Object obj) { - Object encoded = null; - byte[] header = new byte[9]; - int len; - byte[] data = PickleUtils.encodeUTF8Strict(asStringStrict(obj), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - - if (data == null) { - // Issue #8383: for strings with lone surrogates, fallback on the "surrogatepass" - // error handler. - encoded = getItem(frame, encode(frame, obj, T_UTF8, T_ERRORS_SURROGATEPASS), 0); - // Checkstyle: stop - //@formatter:off - // data = PickleUtils.encodeUTF8Strict(asStringStrict(encoded), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - // Checkstyle: start - //@formatter:on - // TODO: [GR-39571] TruffleStrings: allow preservation of UTF-16 surrogate - data = toBytes(frame, encoded); - } - - int size = data.length; - - if (size <= 0xff && pickler.proto >= 4) { - header[0] = PickleUtils.OPCODE_SHORT_BINUNICODE; - header[1] = (byte) (size & 0xff); - len = 2; - } else if (Long.compareUnsigned(size, 0xffffffffL) <= 0) { - header[0] = PickleUtils.OPCODE_BINUNICODE; - header[1] = (byte) (size & 0xff); - header[2] = (byte) ((size >> 8) & 0xff); - header[3] = (byte) ((size >> 16) & 0xff); - header[4] = (byte) ((size >> 24) & 0xff); - len = 5; - } else if (pickler.proto >= 4) { - header[0] = PickleUtils.OPCODE_BINUNICODE8; - PickleUtils.writeSize64(header, 1, size); - len = 9; + TruffleString string = asStringStrict(obj); + TruffleString utf8 = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + int size = utf8.byteLength(TruffleString.Encoding.UTF_8); + boolean wasFraming = pickler.framing; + boolean bypassBuffer = bypassBuffer(pickler, size); + + if (bypassBuffer && pickler.write != null) { + writeIntOp(pickler, PickleUtils.OPCODE_BINUNICODE, size); + byte[] data = new byte[size]; + ensureTsCopyToByteArrayNode().execute(utf8, 0, data, 0, size, TruffleString.Encoding.UTF_8); + flushToFile(frame, pickler); + getCallNode().execute(frame, pickler.write, PFactory.createBytes(PythonLanguage.get(this), data, size)); + pickler.clearBuffer(); } else { - throw raise(OverflowError, ErrorMessages.SER_OVER_4GB); + if (size <= 0xff && pickler.proto >= 4) { + writeByteOp(pickler, PickleUtils.OPCODE_SHORT_BINUNICODE, size); + } else { + writeIntOp(pickler, PickleUtils.OPCODE_BINUNICODE, size); + } + writeUtf8(pickler, utf8); } - writeBytes(frame, pickler, header, len, data, size, encoded); + if (bypassBuffer && wasFraming) { + pickler.framing = true; + } } private void saveUnicode(VirtualFrame frame, PPickler pickler, Object obj) { if (pickler.isBin()) { writeUnicodeBinary(frame, pickler, obj); } else { - byte[] encoded = PickleUtils.rawUnicodeEscape(asStringStrict(obj), ensureTsCodePointLengthNode(), ensureTsCodePointAtIndexUTF32Node()); write(pickler, PickleUtils.OPCODE_UNICODE); - write(pickler, encoded); + writeRawUnicodeEscape(pickler, asStringStrict(obj)); writeASCII(pickler, T_NEWLINE); } memoPut(pickler, obj); } + private void writeRawUnicodeEscape(PPickler pickler, TruffleString string) { + int codePointLength = ensureTsCodePointLengthNode().execute(string, TS_ENCODING); + long escapedLength = 0; + for (int i = 0; i < codePointLength; i++) { + int ch = ensureTsCodePointAtIndexUTF32Node().execute(string, i); + escapedLength += ch >= 0x10000 ? 10 : ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a ? 6 : 1; + } + if (escapedLength > Integer.MAX_VALUE) { + throw raise(PythonBuiltinClassType.MemoryError); + } + ensureBufferSpace(pickler, (int) escapedLength); + for (int i = 0; i < codePointLength; i++) { + int ch = ensureTsCodePointAtIndexUTF32Node().execute(string, i); + if (ch >= 0x10000) { + pickler.outputBuffer[pickler.outputLen++] = '\\'; + pickler.outputBuffer[pickler.outputLen++] = 'U'; + for (int shift = 28; shift >= 0; shift -= 4) { + pickler.outputBuffer[pickler.outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; + } + } else if (ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a) { + pickler.outputBuffer[pickler.outputLen++] = '\\'; + pickler.outputBuffer[pickler.outputLen++] = 'u'; + for (int shift = 12; shift >= 0; shift -= 4) { + pickler.outputBuffer[pickler.outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; + } + } else { + pickler.outputBuffer[pickler.outputLen++] = (byte) ch; + } + } + } + private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { final HashingStorage storage = dict.getDictStorage(); final int length = getHashingStorageLength(storage); @@ -1466,24 +1472,17 @@ private void batchDict(VirtualFrame frame, PPickler pickler, Object iterator) { } private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMethodObjArgs callMethod, PPickler pickler, Object obj) { - byte[] header = new byte[3]; - int len; - if (pickler.isFast()) { fastSaveEnter(pickler, obj); } // Create an empty dict. if (pickler.isBin()) { - header[0] = PickleUtils.OPCODE_EMPTY_DICT; - len = 1; + write(pickler, PickleUtils.OPCODE_EMPTY_DICT); } else { - header[0] = PickleUtils.OPCODE_MARK; - header[1] = PickleUtils.OPCODE_DICT; - len = 2; + write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_DICT); } - write(pickler, header, len); memoPut(pickler, obj); if (length(frame, obj) > 0) { @@ -1630,25 +1629,18 @@ private void batchList(VirtualFrame frame, PPickler pickler, Object iterator) { } private void saveList(VirtualFrame frame, PPickler pickler, Object obj) { - byte[] header = new byte[3]; - int len; - if (pickler.isFast()) { fastSaveEnter(pickler, obj); } // Create an empty list. if (pickler.isBin()) { - header[0] = PickleUtils.OPCODE_EMPTY_LIST; - len = 1; + write(pickler, PickleUtils.OPCODE_EMPTY_LIST); } else { - header[0] = PickleUtils.OPCODE_MARK; - header[1] = PickleUtils.OPCODE_LIST; - len = 2; + write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); } - write(pickler, header, len); - len = length(frame, obj); + int len = length(frame, obj); memoPut(pickler, obj); if (len != 0) { @@ -1678,18 +1670,11 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj) { int len = length(frame, obj); if (len == 0) { - byte[] pdata = new byte[2]; - if (pickler.proto != 0) { - pdata[0] = PickleUtils.OPCODE_EMPTY_TUPLE; - len = 1; + write(pickler, PickleUtils.OPCODE_EMPTY_TUPLE); } else { - pdata[0] = PickleUtils.OPCODE_MARK; - pdata[1] = PickleUtils.OPCODE_TUPLE; - len = 2; + write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_TUPLE); } - - write(pickler, pdata, len); return; } @@ -1744,56 +1729,65 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj) { memoPut(pickler, obj); } - private void saveBytearrayData(VirtualFrame frame, PPickler pickler, Object obj, byte[] data, int size) { + private void saveBytearrayData(VirtualFrame frame, PPickler pickler, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { assert pickler.proto >= 5; - if (size < 0) { - return; - } - byte[] header = new byte[9]; + int size = bufferLib.getBufferLength(buffer); + boolean wasFraming = pickler.framing; + boolean bypassBuffer = bypassBuffer(pickler, size); + + // Our sizes are ints, but the protocol expects 8 bytes + ensureBufferSpace(pickler, 9); + writeIntOp(pickler, PickleUtils.OPCODE_BYTEARRAY8, size); + pickler.outputLen += 4; - header[0] = PickleUtils.OPCODE_BYTEARRAY8; - PickleUtils.writeSize64(header, 1, size); + if (bypassBuffer && pickler.write != null) { + flushToFile(frame, pickler); + getCallNode().execute(frame, pickler.write, obj); + pickler.clearBuffer(); + } else { + writeBuffer(pickler, buffer, size, bufferLib); + } - int len = 9; - writeBytes(frame, pickler, header, len, data, size, obj); + if (bypassBuffer && wasFraming) { + pickler.framing = true; + } memoPut(pickler, obj); } private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PPickler pickler, Object obj, InteropCallData interopCallData) { Object buffer = getBufferAcquireLibrary().acquireReadonly(obj, frame, interopCallData); + PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { if (pickler.proto < 5) { // Older pickle protocols do not have an opcode for pickling bytearrays. Object reduceValue; final PythonBuiltinClass byteArrayClass = ctx.getCore().lookupType(PythonBuiltinClassType.PByteArray); - if (getBufferLibrary().getBufferLength(buffer) == 0) { + if (bufferLib.getBufferLength(buffer) == 0) { reduceValue = createTuple(byteArrayClass, createTuple()); } else { - byte[] bytes = getBufferLibrary().getCopiedByteArray(buffer); + byte[] bytes = bufferLib.getCopiedByteArray(buffer); reduceValue = createTuple(byteArrayClass, createTuple(PFactory.createBytes(ctx.getLanguage(inliningTarget), bytes))); } // save_reduce() will memoize the object automatically. saveReduce(frame, ctx, pickler, reduceValue, obj); } else { - saveBytearrayData(frame, pickler, obj, getBufferLibrary().getCopiedByteArray(buffer), length(frame, obj)); + saveBytearrayData(frame, pickler, obj, buffer, bufferLib); } } finally { - getBufferLibrary().release(buffer, frame, interopCallData); + bufferLib.release(buffer, frame, interopCallData); } } - private void savePicklebuffer(VirtualFrame frame, PPickler pickler, PPickleBuffer obj) { + private void savePickleBuffer(VirtualFrame frame, PPickler pickler, PPickleBuffer obj) { if (pickler.proto < 5) { throw raise(PicklingError, ErrorMessages.PICKLEBUFF_CANNOT_PICKLE_WITH_PROTO5); } Object buffer = obj.getView(); PythonBufferAccessLibrary bufferLib = getBufferLibrary(); - int bytesLen = bufferLib.getBufferLength(buffer); - byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); boolean inBand = true; if (pickler.bufferCallback != null) { @@ -1805,9 +1799,9 @@ private void savePicklebuffer(VirtualFrame frame, PPickler pickler, PPickleBuffe if (inBand) { // Write data in-band if (readOnly) { - saveBytesData(frame, pickler, obj, bytes, bytesLen); + saveBytesData(frame, pickler, obj, buffer, bufferLib); } else { - saveBytearrayData(frame, pickler, obj, bytes, bytesLen); + saveBytearrayData(frame, pickler, obj, buffer, bufferLib); } } else { // Write data out-of-band @@ -1872,14 +1866,9 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P if (pickler.proto >= 2) { genGlobal = false; // See whether this is in the extension registry, and if so generate an EXT opcode. - PTuple extensionKey; - Object codeObj; - long code; - byte[] pdata = new byte[5]; - int n; - - extensionKey = createTuple(moduleName, globalName); - codeObj = getDictItem(frame, st.extensionRegistry, extensionKey); + + PTuple extensionKey = createTuple(moduleName, globalName); + Object codeObj = getDictItem(frame, st.extensionRegistry, extensionKey); // The object is not registered in the extension registry. This is the most likely // code path. if (codeObj == null) { @@ -1892,38 +1881,25 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_EXT_CODE_P_NOT_AN_INT, obj, codeObj); } - code = asLong(frame, codeObj); + long code = asLong(frame, codeObj); if (code <= 0 || code > 0x7fffffffL) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_EXT_CODE_OO_RANGE, obj, code); } // Generate an EXT opcode if (code <= 0xff) { - pdata[0] = PickleUtils.OPCODE_EXT1; - pdata[1] = (byte) code; - n = 2; + writeByteOp(pickler, PickleUtils.OPCODE_EXT1, code); } else if (code <= 0xffff) { - pdata[0] = PickleUtils.OPCODE_EXT2; - pdata[1] = (byte) (code & 0xff); - pdata[2] = (byte) ((code >> 8) & 0xff); - n = 3; + writeShortOp(pickler, PickleUtils.OPCODE_EXT2, code); } else { - pdata[0] = PickleUtils.OPCODE_EXT4; - pdata[1] = (byte) (code & 0xff); - pdata[2] = (byte) ((code >> 8) & 0xff); - pdata[3] = (byte) ((code >> 16) & 0xff); - pdata[4] = (byte) ((code >> 24) & 0xff); - n = 5; + writeIntOp(pickler, PickleUtils.OPCODE_EXT4, code); } - - write(pickler, pdata, n); } } else { genGlobal = true; } if (genGlobal) { - byte[] encoded; TruffleString lastname = dottedPath[dottedPath.length - 1]; if (parent == module) { @@ -1953,20 +1929,24 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P // module name and the global name using UTF-8. We do so only when we are using // the pickle protocol newer than version 3. This is to ensure compatibility // with older Unpickler running on Python 2.x. - TruffleString.Encoding encoding = (pickler.proto == 3) ? TruffleString.Encoding.UTF_8 : TruffleString.Encoding.US_ASCII; - encoded = PickleUtils.encodeStrict(moduleName, ensureTsSwitchEncodingNode(), encoding, ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - if (encoded == null) { - throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); - } - write(pickler, encoded); - writeASCII(pickler, T_NEWLINE); - // Save the name of the module - encoded = PickleUtils.encodeStrict(globalName, ensureTsSwitchEncodingNode(), encoding, ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - if (encoded == null) { - throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); + if (pickler.proto >= 3) { + if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) == TruffleString.CodeRange.BROKEN || ensureTsGetCodeRangeNode().execute(globalName, + TS_ENCODING) == TruffleString.CodeRange.BROKEN) { + throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); + } + writeUtf8(pickler, moduleName); + write(pickler, (byte) '\n'); + writeUtf8(pickler, globalName); + } else { + if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) != TruffleString.CodeRange.ASCII || ensureTsGetCodeRangeNode().execute(globalName, + TS_ENCODING) != TruffleString.CodeRange.ASCII) { + throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); + } + writeASCII(pickler, moduleName); + write(pickler, (byte) '\n'); + writeASCII(pickler, globalName); } - write(pickler, encoded); - writeASCII(pickler, T_NEWLINE); + write(pickler, (byte) '\n'); } // Memoize the object memoPut(pickler, obj); @@ -2052,7 +2032,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa saveBytearray(frame, inliningTarget, ctx, pickler, obj, interopCallData); return; } else if (obj instanceof PPickleBuffer buffer) { - savePicklebuffer(frame, pickler, buffer); + savePickleBuffer(frame, pickler, buffer); return; } @@ -2137,10 +2117,9 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, if (pickler.proto >= 2) { assert pickler.proto <= 256; - byte[] header = new byte[]{PickleUtils.OPCODE_PROTO, (byte) pickler.proto}; try { - write(pickler, header, 2); + write(pickler, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); } catch (Exception e) { handleError(pickler); throw e; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java index 276a5c3d0c..772d2abc95 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java @@ -40,7 +40,6 @@ */ package com.oracle.graal.python.builtins.modules.pickle; -import static com.oracle.graal.python.builtins.modules.pickle.PPickler.BasePickleWriteNode.NEW_LINE_BYTE; import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; @@ -53,8 +52,6 @@ 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.bytes.ByteArrayBuffer; -import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod; import com.oracle.graal.python.builtins.objects.method.PMethod; import com.oracle.graal.python.builtins.objects.str.StringUtils; @@ -62,7 +59,6 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.runtime.object.PFactory; -import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; @@ -229,28 +225,6 @@ public static void writeSize64(byte[] out, int start, int value) { } } - public static byte[] resize(byte[] src, int newSize) { - byte[] newBytes = new byte[newSize]; - if (src != null) { - PythonUtils.arraycopy(src, 0, newBytes, 0, Math.min(newSize, src.length)); - } - return newBytes; - } - - private static int arrayCopyWithNewLine(byte[] dst, int offset, byte[] src) { - PythonUtils.arraycopy(src, 0, dst, offset, src.length); - int len = src.length + 2; - dst[len - 1] = NEW_LINE_BYTE; - return len; - } - - public static int toAsciiBytesWithNewLine(byte[] dst, int offset, long value, TruffleString.FromLongNode fromLongNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - TruffleString s = fromLongNode.execute(value, TruffleString.Encoding.US_ASCII, true); - byte[] buf = new byte[s.byteLength(TruffleString.Encoding.US_ASCII)]; - copyToByteArrayNode.execute(s, 0, buf, 0, buf.length, TruffleString.Encoding.US_ASCII); - return arrayCopyWithNewLine(dst, offset, buf); - } - public static int getStringSize(byte[] bytes) { int len = bytes.length > 0 && bytes[bytes.length - 1] == '\n' ? bytes.length - 1 : bytes.length; return len > 0 && bytes[len - 1] == 0 ? len - 1 : len; @@ -295,23 +269,6 @@ public static double asciiBytesToDouble(Node node, byte[] bytes, PythonBuiltinCl } } - public static byte[] encodeUTF8Strict(TruffleString str, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode, - TruffleString.GetCodeRangeNode getCodeRangeNode) { - return encodeStrict(str, switchEncodingNode, TruffleString.Encoding.UTF_8, copyToByteArrayNode, getCodeRangeNode); - } - - public static byte[] encodeStrict(TruffleString ts, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.Encoding encoding, TruffleString.CopyToByteArrayNode copyToByteArrayNode, - TruffleString.GetCodeRangeNode getCodeRangeNode) { - // TODO: [GR-39571] TruffleStrings: allow preservation of UTF-16 surrogate - if (getCodeRangeNode.execute(ts, TS_ENCODING) == TruffleString.CodeRange.BROKEN) { - return null; - } - TruffleString s = switchEncodingNode.execute(ts, encoding); - byte[] buf = new byte[s.byteLength(encoding)]; - copyToByteArrayNode.execute(s, 0, buf, 0, buf.length, encoding); - return buf; - } - public static TruffleString decodeUTF8Strict(byte[] data, int len, TruffleString.FromByteArrayNode fromByteArrayNode, TruffleString.SwitchEncodingNode switchEncodingNode) { return decodeStrict(data, len, fromByteArrayNode, TruffleString.Encoding.UTF_8, switchEncodingNode); } @@ -326,39 +283,6 @@ private static TruffleString decodeStrict(byte[] data, int len, TruffleString.Fr return switchEncodingNode.execute(ret, TS_ENCODING); } - public static byte[] rawUnicodeEscape(TruffleString unicode, TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexUTF32Node codePointAtIndexNode) { - int len = codePointLengthNode.execute(unicode, TS_ENCODING); - ByteArrayBuffer buffer = new ByteArrayBuffer(len); - for (int i = 0; i < len; i++) { - final int ch = codePointAtIndexNode.execute(unicode, i); - if (ch >= 0x10000) { - // Map 32-bit characters to \Uxxxxxxxx - buffer.append('\\'); - buffer.append('U'); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 28) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 24) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 20) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 16) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 12) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 8) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 4) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[ch & 15]); - } else if (ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a) { - // Map 16-bit characters, \\ and \n to \Uxxxx - buffer.append('\\'); - buffer.append('u'); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 12) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 8) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 4) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[ch & 15]); - } else { - // Copy everything else as-is - buffer.append((char) ch); - } - } - return buffer.getByteArray(); - } - public static Pair initMethodRef(VirtualFrame frame, Node inliningTarget, PyObjectLookupAttr lookup, Object receiver, TruffleString identifier) { final Object func = lookup.execute(frame, inliningTarget, receiver, identifier); if (func == PNone.NO_VALUE) { From b754b7bddb8c8b2fe7626dd4aa8737ca8800ed8c Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 25 Sep 2026 09:34:01 +0200 Subject: [PATCH 072/129] Lazily initialize fastMemo table (cherry picked from commit 34df922e10dd50867b3bd8b80ad1830a2203a536) --- .../python/builtins/modules/pickle/PPickler.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index b27219e9f2..372811a2af 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -163,7 +163,7 @@ public class PPickler extends PythonBuiltinObject { private int fastNesting; // Indicate whether Pickler should fix the name of globals for Python 2.x. private boolean fixImports; - private final Map fastMemo = createFastMemoTable(); + private Map fastMemo; // Callback for out-of-band buffers, or NULL private Object bufferCallback; @@ -261,18 +261,28 @@ public void setPersFuncSelf(Object persFuncSelf) { this.persFuncSelf = persFuncSelf; } + @TruffleBoundary + private void ensureFastMemo() { + if (fastMemo == null) { + fastMemo = createFastMemoTable(); + } + } + @TruffleBoundary private boolean fastMemoContains(Object object) { + ensureFastMemo(); return this.fastMemo.containsKey(object); } @TruffleBoundary private void fastMemoPut(Object object) { + ensureFastMemo(); this.fastMemo.put(object, true); } @TruffleBoundary private void fastMemoRemove(Object object) { + ensureFastMemo(); this.fastMemo.remove(object); } From 6c2400284f9a78c5a55725f4f301bc48b3bfd83c Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 24 Sep 2026 23:46:29 +0200 Subject: [PATCH 073/129] Simplify pickling builtins (cherry picked from commit 58067cbc9f5ae52add7656401845c2da5e06e74a) --- .../builtins/modules/pickle/PPickler.java | 296 +++++++++--------- .../oracle/graal/python/nodes/PGuards.java | 4 + 2 files changed, 154 insertions(+), 146 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 372811a2af..0db29d7729 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -71,7 +71,9 @@ import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAcquireLibrary; import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; +import com.oracle.graal.python.builtins.objects.bytes.PByteArray; import com.oracle.graal.python.builtins.objects.bytes.PBytes; +import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass; import com.oracle.graal.python.builtins.objects.common.HashingStorage; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIterator; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorKey; @@ -80,24 +82,28 @@ import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageLen; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis; +import com.oracle.graal.python.builtins.objects.floats.PFloat; +import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.ints.IntNodes; import com.oracle.graal.python.builtins.objects.ints.IntNodesFactory; +import com.oracle.graal.python.builtins.objects.ints.PInt; +import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.builtins.objects.set.PFrozenSet; import com.oracle.graal.python.builtins.objects.set.PSet; +import com.oracle.graal.python.builtins.objects.str.PString; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; +import com.oracle.graal.python.builtins.objects.type.PythonManagedClass; import com.oracle.graal.python.builtins.objects.type.TypeNodes; import com.oracle.graal.python.lib.IteratorExhausted; import com.oracle.graal.python.lib.PyCallableCheckNode; -import com.oracle.graal.python.lib.PyFloatAsDoubleNode; import com.oracle.graal.python.lib.PyLongAsLongNode; import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectIsTrueNode; import com.oracle.graal.python.lib.PyObjectLookupAttr; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; -import com.oracle.graal.python.lib.PyObjectSizeNode; import com.oracle.graal.python.lib.PyObjectStrAsObjectNode; import com.oracle.graal.python.lib.PyTupleCheckNode; import com.oracle.graal.python.nodes.ErrorMessages; @@ -108,13 +114,13 @@ import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.IsNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; -import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; 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.runtime.sequence.storage.SequenceStorage; import com.oracle.graal.python.util.Consumer; import com.oracle.graal.python.util.NumericSupport; +import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -900,11 +906,6 @@ private void saveListIterator(VirtualFrame frame, PPickler pickler, Object itera (Object item) -> save(frame, pickler, item, 0)); } - private void saveFrozenSetIterator(VirtualFrame frame, PPickler pickler, Object iterator) { - saveIterator(frame, pickler, iterator, PickleUtils.NO_OPCODE, - (Object item) -> save(frame, pickler, item, 0)); - } - private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object iterator) { saveIterator(frame, pickler, iterator, PickleUtils.OPCODE_SETITEM, (Object item) -> { @@ -1225,45 +1226,54 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, } } - private void saveNone(PPickler pickler, @SuppressWarnings("unused") Object obj) { + private void saveNone(PPickler pickler) { write(pickler, PickleUtils.OPCODE_NONE); } - private void saveBool(VirtualFrame frame, PPickler pickler, Object obj) { + private void saveBool(PPickler pickler, boolean value) { if (pickler.proto >= 2) { - write(pickler, isTrue(frame, obj) ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); + write(pickler, value ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); } else { // These aren't opcodes -- they're ways to pickle bools before protocol 2 so that // unpicklers written before bools were introduced unpickle them as ints, but // unpicklers after can recognize that bools were intended. Note that protocol 2 // added direct ways to pickle bools. - writeASCII(pickler, isTrue(frame, obj) ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE); + writeASCII(pickler, value ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE); } } - private void saveLong(VirtualFrame frame, PPickler pickler, Object obj) { - TruffleString repr; - try { - long longValue = asLong(frame, obj); - int value = (int) longValue; - if (value == longValue) { - if (pickler.isBin()) { - if (value >= 0 && value < (1 << 8)) { - writeByteOp(pickler, PickleUtils.OPCODE_BININT1, value); - } else if (value >= 0 && value < (1 << 16)) { - writeShortOp(pickler, PickleUtils.OPCODE_BININT2, value); - } else { - writeIntOp(pickler, PickleUtils.OPCODE_BININT, value); - } - } else { - writeLongAsString(pickler, PickleUtils.OPCODE_INT, longValue); - } - return; + private void saveLong(PPickler pickler, int value) { + if (pickler.isBin()) { + if (value >= 0 && value < (1 << 8)) { + writeByteOp(pickler, PickleUtils.OPCODE_BININT1, value); + } else if (value >= 0 && value < (1 << 16)) { + writeShortOp(pickler, PickleUtils.OPCODE_BININT2, value); + } else { + writeIntOp(pickler, PickleUtils.OPCODE_BININT, value); } - } catch (PException e) { - e.expectCached(OverflowError, ensureErrProfile()); + } else { + writeLongAsString(pickler, PickleUtils.OPCODE_INT, value); + } + } + + private void saveLong(VirtualFrame frame, PPickler pickler, long value) { + int intValue = (int) value; + if (intValue == value) { + saveLong(pickler, intValue); + } else { + saveLongLarge(frame, pickler, value); } + } + + private void saveLong(VirtualFrame frame, PPickler pickler, PInt value) { + try { + saveLong(frame, pickler, value.longValueExact()); + } catch (OverflowException e) { + saveLongLarge(frame, pickler, value); + } + } + private void saveLongLarge(VirtualFrame frame, PPickler pickler, Object obj) { if (pickler.proto >= 2) { // Linear-time pickling. final int sign = getSign(obj); @@ -1298,15 +1308,14 @@ private void saveLong(VirtualFrame frame, PPickler pickler, Object obj) { write(pickler, pdata, nbytes); } else { - repr = repr(frame, obj); + TruffleString repr = repr(frame, obj); write(pickler, PickleUtils.OPCODE_LONG); writeASCII(pickler, asStringStrict(repr)); writeASCII(pickler, T_L_NEW_LINE); } } - private void saveFloat(VirtualFrame frame, PPickler pickler, Object obj, Node inliningTarget, PyFloatAsDoubleNode asDoubleNode) { - final double value = asDoubleNode.execute(frame, inliningTarget, obj); + private void saveFloat(PPickler pickler, double value) { if (pickler.isBin()) { write(pickler, PickleUtils.OPCODE_BINFLOAT); ensureBufferSpace(pickler, 8); @@ -1320,8 +1329,8 @@ private void saveFloat(VirtualFrame frame, PPickler pickler, Object obj, Node in } } - private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj, InteropCallData interopCallData) { - Object buffer = getBufferAcquireLibrary().acquireReadonly(obj, frame, interopCallData); + private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, PBytes obj) { + Object buffer = getBufferAcquireLibrary().acquireReadonly(obj); PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { if (pickler.proto < 3) { @@ -1350,7 +1359,7 @@ private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, saveBytesData(frame, pickler, obj, buffer, bufferLib); } } finally { - bufferLib.release(buffer, frame, interopCallData); + bufferLib.release(buffer); } } @@ -1380,8 +1389,7 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, Object obj, Obj memoPut(pickler, obj); } - private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, Object obj) { - TruffleString string = asStringStrict(obj); + private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, TruffleString string) { TruffleString utf8 = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); int size = utf8.byteLength(TruffleString.Encoding.UTF_8); boolean wasFraming = pickler.framing; @@ -1408,12 +1416,20 @@ private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, Object obj } } - private void saveUnicode(VirtualFrame frame, PPickler pickler, Object obj) { + private void saveUnicode(VirtualFrame frame, PPickler pickler, TruffleString obj) { + saveUnicode(frame, pickler, obj, obj); + } + + private void saveUnicode(VirtualFrame frame, PPickler pickler, PString obj) { + saveUnicode(frame, pickler, obj, asStringStrict(obj)); + } + + private void saveUnicode(VirtualFrame frame, PPickler pickler, Object obj, TruffleString string) { if (pickler.isBin()) { - writeUnicodeBinary(frame, pickler, obj); + writeUnicodeBinary(frame, pickler, string); } else { write(pickler, PickleUtils.OPCODE_UNICODE); - writeRawUnicodeEscape(pickler, asStringStrict(obj)); + writeRawUnicodeEscape(pickler, string); writeASCII(pickler, T_NEWLINE); } memoPut(pickler, obj); @@ -1481,7 +1497,7 @@ private void batchDict(VirtualFrame frame, PPickler pickler, Object iterator) { } } - private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMethodObjArgs callMethod, PPickler pickler, Object obj) { + private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMethodObjArgs callMethod, PPickler pickler, PDict obj) { if (pickler.isFast()) { fastSaveEnter(pickler, obj); } @@ -1495,9 +1511,9 @@ private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMetho memoPut(pickler, obj); - if (length(frame, obj) > 0) { - if (PGuards.isDict(obj) && pickler.proto > 0) { - batchDictExact(frame, pickler, (PDict) obj); + if (getHashingStorageLength(obj.getDictStorage()) > 0) { + if (pickler.proto > 0) { + batchDictExact(frame, pickler, obj); } else { final Object items = callMethod.execute(frame, inliningTarget, obj, T_ITEMS); batchDict(frame, pickler, getIter(frame, items)); @@ -1513,33 +1529,7 @@ private void batchSetExact(VirtualFrame frame, PPickler pickler, PSet set) { saveSetHashingStorageBatched(frame, pickler, set.getDictStorage()); } - private void batchSet(VirtualFrame frame, PPickler pickler, Object obj) { - Object iterator = getIter(frame, obj); - int setSize = length(frame, obj); - int i; - do { - i = 0; - write(pickler, PickleUtils.OPCODE_MARK); - while (true) { - Object item; - try { - item = getNextItem(frame, iterator); - } catch (IteratorExhausted e) { - break; - } - save(frame, pickler, item, 0); - if (++i == PickleUtils.BATCHSIZE) { - break; - } - } - write(pickler, PickleUtils.OPCODE_ADDITEMS); - if (length(frame, obj) != setSize) { - throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.CHANGED_SIZE_DURING_ITERATION, "set"); - } - } while (i == PickleUtils.BATCHSIZE); - } - - private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj) { + private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, PSet obj) { Object reduceValue; if (pickler.proto < 4) { Object items = createList(frame, obj); @@ -1558,14 +1548,10 @@ private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, Ob } // Write in batches of BATCHSIZE. - if (obj instanceof PSet set) { - batchSetExact(frame, pickler, set); - } else { - batchSet(frame, pickler, obj); - } + batchSetExact(frame, pickler, obj); } - private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj) { + private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickler, PFrozenSet obj) { if (pickler.isFast()) { fastSaveEnter(pickler, obj); } @@ -1579,12 +1565,7 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl write(pickler, PickleUtils.OPCODE_MARK); - if (obj instanceof PFrozenSet set) { - saveSetHashingStorage(frame, pickler, set.getDictStorage()); - } else { - final Object iterator = getIter(frame, obj); - saveFrozenSetIterator(frame, pickler, iterator); - } + saveSetHashingStorage(frame, pickler, obj.getDictStorage()); // If the object is already in the memo, this means it is recursive. In this case, throw // away everything we put on the stack, and fetch the object back from the memo. @@ -1599,10 +1580,10 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl memoPut(pickler, obj); } - private void batchListExact(VirtualFrame frame, PPickler pickler, Object obj) { - final SequenceStorage storage = getSequenceStorage(obj); + private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { + final SequenceStorage storage = obj.getSequenceStorage(); Object item; - if (length(frame, obj) == 1) { + if (storage.length() == 1) { item = getItem(frame, storage, 0); save(frame, pickler, item, 0); write(pickler, PickleUtils.OPCODE_APPEND); @@ -1615,7 +1596,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, Object obj) { do { thisBatch = 0; write(pickler, PickleUtils.OPCODE_MARK); - while (total < length(frame, obj)) { + while (total < storage.length()) { item = getItem(frame, storage, total); save(frame, pickler, item, 0); total++; @@ -1624,7 +1605,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, Object obj) { } } write(pickler, PickleUtils.OPCODE_APPENDS); - } while (total < length(frame, obj)); + } while (total < storage.length()); } private void batchList(VirtualFrame frame, PPickler pickler, Object iterator) { @@ -1638,7 +1619,7 @@ private void batchList(VirtualFrame frame, PPickler pickler, Object iterator) { } } - private void saveList(VirtualFrame frame, PPickler pickler, Object obj) { + private void saveList(VirtualFrame frame, PPickler pickler, PList obj) { if (pickler.isFast()) { fastSaveEnter(pickler, obj); } @@ -1650,12 +1631,11 @@ private void saveList(VirtualFrame frame, PPickler pickler, Object obj) { write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); } - int len = length(frame, obj); + int len = obj.getSequenceStorage().length(); memoPut(pickler, obj); if (len != 0) { - // Materialize the list elements. - if (PGuards.isList(obj) && pickler.proto > 0) { + if (pickler.proto > 0) { batchListExact(frame, pickler, obj); } else { batchList(frame, pickler, getIter(frame, obj)); @@ -1667,17 +1647,30 @@ private void saveList(VirtualFrame frame, PPickler pickler, Object obj) { } } - private void storeTupleElements(VirtualFrame frame, PPickler pickler, Object obj, int len) { + private void storeTupleElements(VirtualFrame frame, PPickler pickler, Object obj, SequenceStorage storage, int len) { // A helper for save_tuple. Push the len elements in tuple t on the stack - assert PyObjectSizeNode.executeUncached(obj) == len; - for (int i = 0; i < len; i++) { - Object element = getItem(frame, obj, i); - save(frame, pickler, element, 0); + if (storage == null) { + for (int i = 0; i < len; i++) { + save(frame, pickler, getItem(frame, obj, i), 0); + } + } else { + assert storage.length() == len; + for (int i = 0; i < len; i++) { + save(frame, pickler, getItem(frame, storage, i), 0); + } } } - private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj) { - int len = length(frame, obj); + private void saveTuple(VirtualFrame frame, PPickler pickler, PTuple obj) { + SequenceStorage storage = obj.getSequenceStorage(); + saveTuple(frame, pickler, obj, storage, storage.length()); + } + + private void saveNativeTuple(VirtualFrame frame, PPickler pickler, Object obj) { + saveTuple(frame, pickler, obj, null, length(frame, obj)); + } + + private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj, SequenceStorage storage, int len) { if (len == 0) { if (pickler.proto != 0) { @@ -1693,7 +1686,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj) { // the stack, and fetch its value from the memo. if (len <= 3 && pickler.proto >= 2) { // Use TUPLE{1,2,3} opcodes. - storeTupleElements(frame, pickler, obj, len); + storeTupleElements(frame, pickler, obj, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { @@ -1715,7 +1708,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj) { // proto < 2 and len > 0, or proto >= 2 and len > 3. Generate MARK e1 e2 ... TUPLE write(pickler, PickleUtils.OPCODE_MARK); - storeTupleElements(frame, pickler, obj, len); + storeTupleElements(frame, pickler, obj, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { @@ -1765,8 +1758,8 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, Object obj, memoPut(pickler, obj); } - private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PPickler pickler, Object obj, InteropCallData interopCallData) { - Object buffer = getBufferAcquireLibrary().acquireReadonly(obj, frame, interopCallData); + private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PPickler pickler, PByteArray obj) { + Object buffer = getBufferAcquireLibrary().acquireReadonly(obj); PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { if (pickler.proto < 5) { @@ -1787,7 +1780,7 @@ private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContex saveBytearrayData(frame, pickler, obj, buffer, bufferLib); } } finally { - bufferLib.release(buffer, frame, interopCallData); + bufferLib.release(buffer); } } @@ -1827,16 +1820,15 @@ private void saveSingletonType(VirtualFrame frame, PythonContext ctx, PPickler p saveReduce(frame, ctx, pickler, reduceValue, obj); } - private void saveType(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, Object obj) { - if (isBuiltinClass(obj, PythonBuiltinClassType.PNone)) { + private void saveType(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, PythonManagedClass obj) { + if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNone) { saveSingletonType(frame, ctx, pickler, obj, PNone.NONE); - } else if (isBuiltinClass(obj, PythonBuiltinClassType.PEllipsis)) { + } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PEllipsis) { saveSingletonType(frame, ctx, pickler, obj, PEllipsis.INSTANCE); - } else if (isBuiltinClass(obj, PythonBuiltinClassType.PNotImplemented)) { + } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNotImplemented) { saveSingletonType(frame, ctx, pickler, obj, PNotImplemented.NOT_IMPLEMENTED); } else { - Object type = (obj instanceof PythonBuiltinClassType) ? ctx.getCore().lookupType((PythonBuiltinClassType) obj) : obj; - saveGlobal(frame, boundaryCallData, ctx, pickler, type, null); + saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); } } @@ -1967,8 +1959,6 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSave, @Bind Node inliningTarget, @Cached("createFor($node)") BoundaryCallData boundaryCallData, - @Cached("createFor($node)") InteropCallData interopCallData, - @Cached PyFloatAsDoubleNode asDoubleNode, @Cached CallNode callNode, @Cached PyObjectCallMethodObjArgs callMethod) { Object obj = objArg; @@ -1982,23 +1972,27 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa } } - final Object type = getClass(obj); - // The old cPickle had an optimization that used switch-case statement dispatching on - // the first letter of the type name. This has was removed since benchmarks shown that - // this optimization was actually slowing things down. - // Atom types; these aren't memoized, so don't check the memo. if (obj == PNone.NONE) { - saveNone(pickler, obj); + saveNone(pickler); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.Boolean)) { - saveBool(frame, pickler, obj); + } else if (obj instanceof Boolean value) { + saveBool(pickler, value); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PInt)) { - saveLong(frame, pickler, obj); + } else if (obj instanceof Integer value) { + saveLong(pickler, value); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PFloat)) { - saveFloat(frame, pickler, obj, inliningTarget, asDoubleNode); + } else if (obj instanceof Long value) { + saveLong(frame, pickler, value); + return; + } else if (obj instanceof PInt value && PGuards.isBuiltinPInt(value)) { + saveLong(frame, pickler, value); + return; + } else if (obj instanceof Double value) { + saveFloat(pickler, value); + return; + } else if (obj instanceof PFloat value && PGuards.isBuiltinPFloat(value)) { + saveFloat(pickler, value.getValue()); return; } @@ -2017,29 +2011,35 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa PythonContext ctx = PythonContext.get(this); - if (isBuiltinClass(type, PythonBuiltinClassType.PBytes)) { - saveBytes(frame, ctx, pickler, obj, interopCallData); + if (obj instanceof PBytes bytes && PGuards.isBuiltinBytes(bytes)) { + saveBytes(frame, ctx, pickler, bytes); + return; + } else if (obj instanceof TruffleString string) { + saveUnicode(frame, pickler, string); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PString)) { - saveUnicode(frame, pickler, obj); + } else if (obj instanceof PString string && PGuards.isBuiltinPString(string)) { + saveUnicode(frame, pickler, string); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PDict)) { - saveDict(frame, inliningTarget, callMethod, pickler, obj); + } else if (obj instanceof PDict dict && PGuards.isBuiltinDict(dict)) { + saveDict(frame, inliningTarget, callMethod, pickler, dict); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PSet)) { - saveSet(frame, ctx, pickler, obj); + } else if (obj instanceof PSet set && PGuards.isBuiltinSet(set)) { + saveSet(frame, ctx, pickler, set); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PFrozenSet)) { - saveFrozenset(frame, ctx, pickler, obj); + } else if (obj instanceof PFrozenSet frozenSet && PGuards.isBuiltinFrozenSet(frozenSet)) { + saveFrozenset(frame, ctx, pickler, frozenSet); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PList)) { - saveList(frame, pickler, obj); + } else if (obj instanceof PList list && PGuards.isBuiltinList(list)) { + saveList(frame, pickler, list); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PTuple)) { - saveTuple(frame, pickler, obj); + } else if (obj instanceof PTuple tuple && PGuards.isBuiltinTuple(tuple)) { + saveTuple(frame, pickler, tuple); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PByteArray)) { - saveBytearray(frame, inliningTarget, ctx, pickler, obj, interopCallData); + } else if (PGuards.isNativeObject(obj) && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PTuple)) { + saveNativeTuple(frame, pickler, obj); + return; + } else if (obj instanceof PByteArray byteArray && PGuards.isBuiltinByteArray(byteArray)) { + saveBytearray(frame, inliningTarget, ctx, pickler, byteArray); return; } else if (obj instanceof PPickleBuffer buffer) { savePickleBuffer(frame, pickler, buffer); @@ -2056,10 +2056,13 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa } } - if (isBuiltinClass(type, PythonBuiltinClassType.PythonClass)) { - saveType(frame, boundaryCallData, ctx, pickler, obj); + if (obj instanceof PythonManagedClass clazz && clazz.getPythonClass() == PythonBuiltinClassType.PythonClass) { + saveType(frame, boundaryCallData, ctx, pickler, clazz); + return; + } else if (obj instanceof PythonNativeClass && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PythonClass)) { + saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PFunction)) { + } else if (obj instanceof PFunction) { saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); return; } @@ -2067,6 +2070,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa // Get a reduction callable, and call it. This may come from self.dispatch_table, // copyreg.dispatch_table, the object's __reduce_ex__ method, or the object's __reduce__ // method. + Object type = getClass(obj); Object reduceFunc = null; if (pickler.dispatchTable == null) { PickleState state = getGlobalState(ctx.getCore()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java index 2f2a5daa95..f86db3fc36 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java @@ -309,6 +309,10 @@ public static boolean isBuiltinPInt(PInt obj) { return obj.getPythonClass() == PythonBuiltinClassType.PInt; } + public static boolean isBuiltinPFloat(PFloat obj) { + return obj.getPythonClass() == PythonBuiltinClassType.PFloat; + } + public static boolean isPString(Object obj) { return obj instanceof PString; } From e3433174e351aa7705dd82dbe9b32ba754a1f47c Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 25 Sep 2026 09:28:16 +0200 Subject: [PATCH 074/129] Profile version and fast mode when pickling (cherry picked from commit ce1f410d4dee3c396d7fb0ab489f3ff2da437c52) --- .../builtins/modules/pickle/PPickler.java | 296 +++++++++--------- 1 file changed, 153 insertions(+), 143 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 0db29d7729..a569141a3f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -130,6 +130,8 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; +import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import com.oracle.truffle.api.profiles.InlinedIntValueProfile; import com.oracle.truffle.api.strings.TranscodingErrorHandler; import com.oracle.truffle.api.strings.TruffleString; @@ -767,6 +769,10 @@ private PythonBufferAccessLibrary getBufferLibrary() { public abstract void execute(VirtualFrame frame, PPickler pickler, Object obj, int persSave); + private static boolean isBin(int proto) { + return proto > 0; + } + // collections private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, HashingStorage storage, byte opcodeBatch, TruffleString name, boolean saveValues) { @@ -919,7 +925,7 @@ private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object itera // save methods - private boolean savePers(VirtualFrame frame, PPickler pickler, Object obj) { + private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object obj) { Object pid; if (pickler.persFuncSelf == null) { pid = getCallNode().execute(frame, pickler.persFunc, obj); @@ -927,7 +933,7 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, Object obj) { pid = getCallNode().execute(frame, pickler.persFunc, pickler.persFuncSelf, obj); } if (pid != PNone.NONE) { - if (pickler.isBin()) { + if (isBin(proto)) { save(frame, pickler, pid, 1); write(pickler, PickleUtils.OPCODE_BINPERSID); } else { @@ -946,8 +952,8 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, Object obj) { } // memo methods - private void memoGet(PPickler pickler, int value) { - if (pickler.isBin()) { + private void memoGet(PPickler pickler, int proto, int value) { + if (isBin(proto)) { if (value < 256) { writeByteOp(pickler, PickleUtils.OPCODE_BINGET, value); } else if (Long.compareUnsigned(value, 0xffffffffL) <= 0) { @@ -962,18 +968,18 @@ private void memoGet(PPickler pickler, int value) { } - private void memoPut(PPickler pickler, Object obj) { - if (pickler.isFast()) { + private void memoPut(PPickler pickler, int proto, boolean fastMode, Object obj) { + if (fastMode) { return; } int idx = pickler.memo.size(); pickler.memo.set(obj, idx); - if (pickler.proto >= 4) { + if (proto >= 4) { write(pickler, PickleUtils.OPCODE_MEMOIZE); } else { - if (!pickler.isBin()) { + if (!isBin(proto)) { writeLongAsString(pickler, PickleUtils.OPCODE_PUT, idx); } else { if (idx < 256) { @@ -989,9 +995,9 @@ private void memoPut(PPickler pickler, Object obj) { } // save methods - private void handleReduce(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, Object obj, Object reduceValue) { + private void handleReduce(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object reduceValue) { if (PGuards.isString(reduceValue)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, reduceValue); + saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, reduceValue); return; } @@ -999,10 +1005,10 @@ private void handleReduce(VirtualFrame frame, BoundaryCallData boundaryCallData, throw raise(PicklingError, ErrorMessages.S_MUST_RETURN_S_OR_S, T___REDUCE__, "string", "tuple"); } - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } - private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object arguments, Object obj) { + private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object arguments, Object obj) { // We're saving obj, and args is the 2-thru-5 tuple returned by the appropriate // __reduce__ method for obj. @@ -1053,7 +1059,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, throw raise(PicklingError, ErrorMessages.S_ELEM_REDUCE_MUST_BE_S_NOT_P, "sixth", "a function", stateSetter); } - if (pickler.proto >= 2) { + if (proto >= 2) { Object name = lookupAttribute(frame, callable, T___NAME__); if (name != PNone.NO_VALUE) { final TruffleString stringName = asString(name); @@ -1092,7 +1098,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, throw raise(PicklingError, ErrorMessages.S_ITEM_FROM_S_MUST_BE_S_NOT_P, "third", "NEWOBJ_EX", "a dict", kwargs); } - if (pickler.proto >= 4) { + if (proto >= 4) { save(frame, pickler, cls, 0); save(frame, pickler, args, 0); save(frame, pickler, kwargs, 0); @@ -1190,18 +1196,18 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { write(pickler, PickleUtils.OPCODE_POP); - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); } else { - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } } if (listitems != null) { - batchList(frame, pickler, listitems); + batchList(frame, pickler, proto, listitems); } if (dictitems != null) { - batchDict(frame, pickler, dictitems); + batchDict(frame, pickler, proto, dictitems); } if (state != null) { @@ -1230,8 +1236,8 @@ private void saveNone(PPickler pickler) { write(pickler, PickleUtils.OPCODE_NONE); } - private void saveBool(PPickler pickler, boolean value) { - if (pickler.proto >= 2) { + private void saveBool(PPickler pickler, int proto, boolean value) { + if (proto >= 2) { write(pickler, value ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); } else { // These aren't opcodes -- they're ways to pickle bools before protocol 2 so that @@ -1242,8 +1248,8 @@ private void saveBool(PPickler pickler, boolean value) { } } - private void saveLong(PPickler pickler, int value) { - if (pickler.isBin()) { + private void saveLong(PPickler pickler, int proto, int value) { + if (isBin(proto)) { if (value >= 0 && value < (1 << 8)) { writeByteOp(pickler, PickleUtils.OPCODE_BININT1, value); } else if (value >= 0 && value < (1 << 16)) { @@ -1256,25 +1262,25 @@ private void saveLong(PPickler pickler, int value) { } } - private void saveLong(VirtualFrame frame, PPickler pickler, long value) { + private void saveLong(VirtualFrame frame, PPickler pickler, int proto, long value) { int intValue = (int) value; if (intValue == value) { - saveLong(pickler, intValue); + saveLong(pickler, proto, intValue); } else { - saveLongLarge(frame, pickler, value); + saveLongLarge(frame, pickler, proto, value); } } - private void saveLong(VirtualFrame frame, PPickler pickler, PInt value) { + private void saveLong(VirtualFrame frame, PPickler pickler, int proto, PInt value) { try { - saveLong(frame, pickler, value.longValueExact()); + saveLong(frame, pickler, proto, value.longValueExact()); } catch (OverflowException e) { - saveLongLarge(frame, pickler, value); + saveLongLarge(frame, pickler, proto, value); } } - private void saveLongLarge(VirtualFrame frame, PPickler pickler, Object obj) { - if (pickler.proto >= 2) { + private void saveLongLarge(VirtualFrame frame, PPickler pickler, int proto, Object obj) { + if (proto >= 2) { // Linear-time pickling. final int sign = getSign(obj); assert sign != 0; // Zero was handled by the int code above @@ -1315,8 +1321,8 @@ private void saveLongLarge(VirtualFrame frame, PPickler pickler, Object obj) { } } - private void saveFloat(PPickler pickler, double value) { - if (pickler.isBin()) { + private void saveFloat(PPickler pickler, int proto, double value) { + if (isBin(proto)) { write(pickler, PickleUtils.OPCODE_BINFLOAT); ensureBufferSpace(pickler, 8); NumericSupport.bigEndian().putDouble(pickler.outputBuffer, pickler.outputLen, value); @@ -1329,11 +1335,11 @@ private void saveFloat(PPickler pickler, double value) { } } - private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, PBytes obj) { + private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PBytes obj) { Object buffer = getBufferAcquireLibrary().acquireReadonly(obj); PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { - if (pickler.proto < 3) { + if (proto < 3) { // Older pickle protocols do not have an opcode for pickling bytes objects. // Therefore, we need to fake the copy protocol (i.e., the __reduce__ method) to // permit bytes object unpickling. Here we use a hack to be compatible with @@ -1354,17 +1360,17 @@ private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, reduceValue = createTuple(st.codecsEncode, createTuple(unicodeStr, LATIN1)); } // save_reduce() will memoize the object automatically. - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } else { - saveBytesData(frame, pickler, obj, buffer, bufferLib); + saveBytesData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } } finally { bufferLib.release(buffer); } } - private void saveBytesData(VirtualFrame frame, PPickler pickler, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { - assert pickler.proto >= 3; + private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { + assert proto >= 3; int size = bufferLib.getBufferLength(buffer); boolean wasFraming = pickler.framing; boolean bypassBuffer = bypassBuffer(pickler, size); @@ -1386,10 +1392,10 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, Object obj, Obj if (bypassBuffer && wasFraming) { pickler.framing = true; } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } - private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, TruffleString string) { + private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, int proto, TruffleString string) { TruffleString utf8 = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); int size = utf8.byteLength(TruffleString.Encoding.UTF_8); boolean wasFraming = pickler.framing; @@ -1403,7 +1409,7 @@ private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, TruffleStr getCallNode().execute(frame, pickler.write, PFactory.createBytes(PythonLanguage.get(this), data, size)); pickler.clearBuffer(); } else { - if (size <= 0xff && pickler.proto >= 4) { + if (size <= 0xff && proto >= 4) { writeByteOp(pickler, PickleUtils.OPCODE_SHORT_BINUNICODE, size); } else { writeIntOp(pickler, PickleUtils.OPCODE_BINUNICODE, size); @@ -1416,23 +1422,23 @@ private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, TruffleStr } } - private void saveUnicode(VirtualFrame frame, PPickler pickler, TruffleString obj) { - saveUnicode(frame, pickler, obj, obj); + private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, TruffleString obj) { + saveUnicode(frame, pickler, proto, fastMode, obj, obj); } - private void saveUnicode(VirtualFrame frame, PPickler pickler, PString obj) { - saveUnicode(frame, pickler, obj, asStringStrict(obj)); + private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PString obj) { + saveUnicode(frame, pickler, proto, fastMode, obj, asStringStrict(obj)); } - private void saveUnicode(VirtualFrame frame, PPickler pickler, Object obj, TruffleString string) { - if (pickler.isBin()) { - writeUnicodeBinary(frame, pickler, string); + private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, TruffleString string) { + if (isBin(proto)) { + writeUnicodeBinary(frame, pickler, proto, string); } else { write(pickler, PickleUtils.OPCODE_UNICODE); writeRawUnicodeEscape(pickler, string); writeASCII(pickler, T_NEWLINE); } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } private void writeRawUnicodeEscape(PPickler pickler, TruffleString string) { @@ -1486,9 +1492,9 @@ private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { } } - private void batchDict(VirtualFrame frame, PPickler pickler, Object iterator) { + private void batchDict(VirtualFrame frame, PPickler pickler, int proto, Object iterator) { assert iterator != null; - if (pickler.proto == 0) { + if (proto == 0) { // SETITEMS isn't available; do one at a time. saveDictIterator(frame, pickler, iterator); } else { @@ -1497,30 +1503,30 @@ private void batchDict(VirtualFrame frame, PPickler pickler, Object iterator) { } } - private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMethodObjArgs callMethod, PPickler pickler, PDict obj) { - if (pickler.isFast()) { + private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMethodObjArgs callMethod, PPickler pickler, int proto, boolean fastMode, PDict obj) { + if (fastMode) { fastSaveEnter(pickler, obj); } // Create an empty dict. - if (pickler.isBin()) { + if (isBin(proto)) { write(pickler, PickleUtils.OPCODE_EMPTY_DICT); } else { write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_DICT); } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); if (getHashingStorageLength(obj.getDictStorage()) > 0) { - if (pickler.proto > 0) { + if (proto > 0) { batchDictExact(frame, pickler, obj); } else { final Object items = callMethod.execute(frame, inliningTarget, obj, T_ITEMS); - batchDict(frame, pickler, getIter(frame, items)); + batchDict(frame, pickler, proto, getIter(frame, items)); } } - if (pickler.isFast()) { + if (fastMode) { fastSaveLeave(pickler, obj); } } @@ -1529,17 +1535,17 @@ private void batchSetExact(VirtualFrame frame, PPickler pickler, PSet set) { saveSetHashingStorageBatched(frame, pickler, set.getDictStorage()); } - private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, PSet obj) { + private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PSet obj) { Object reduceValue; - if (pickler.proto < 4) { + if (proto < 4) { Object items = createList(frame, obj); reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PSet), createTuple(items)); - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); return; } write(pickler, PickleUtils.OPCODE_EMPTY_SET); - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); final int setSize = length(frame, obj); if (setSize == 0) { @@ -1551,15 +1557,15 @@ private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, PS batchSetExact(frame, pickler, obj); } - private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickler, PFrozenSet obj) { - if (pickler.isFast()) { + private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PFrozenSet obj) { + if (fastMode) { fastSaveEnter(pickler, obj); } - if (pickler.proto < 4) { + if (proto < 4) { Object items = createList(frame, obj); Object reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PFrozenSet), createTuple(items)); - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); return; } @@ -1572,12 +1578,12 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { write(pickler, PickleUtils.OPCODE_POP_MARK); - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); return; } write(pickler, PickleUtils.OPCODE_FROZENSET); - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { @@ -1608,9 +1614,9 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { } while (total < storage.length()); } - private void batchList(VirtualFrame frame, PPickler pickler, Object iterator) { + private void batchList(VirtualFrame frame, PPickler pickler, int proto, Object iterator) { assert iterator != null; - if (pickler.proto == 0) { + if (proto == 0) { // APPENDS isn't available; do one at a time. saveListIterator(frame, pickler, iterator); } else { @@ -1619,30 +1625,30 @@ private void batchList(VirtualFrame frame, PPickler pickler, Object iterator) { } } - private void saveList(VirtualFrame frame, PPickler pickler, PList obj) { - if (pickler.isFast()) { + private void saveList(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PList obj) { + if (fastMode) { fastSaveEnter(pickler, obj); } // Create an empty list. - if (pickler.isBin()) { + if (isBin(proto)) { write(pickler, PickleUtils.OPCODE_EMPTY_LIST); } else { write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); } int len = obj.getSequenceStorage().length(); - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); if (len != 0) { - if (pickler.proto > 0) { + if (proto > 0) { batchListExact(frame, pickler, obj); } else { - batchList(frame, pickler, getIter(frame, obj)); + batchList(frame, pickler, proto, getIter(frame, obj)); } } - if (pickler.isFast()) { + if (fastMode) { fastSaveLeave(pickler, obj); } } @@ -1661,19 +1667,19 @@ private void storeTupleElements(VirtualFrame frame, PPickler pickler, Object obj } } - private void saveTuple(VirtualFrame frame, PPickler pickler, PTuple obj) { + private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PTuple obj) { SequenceStorage storage = obj.getSequenceStorage(); - saveTuple(frame, pickler, obj, storage, storage.length()); + saveTuple(frame, pickler, proto, fastMode, obj, storage, storage.length()); } - private void saveNativeTuple(VirtualFrame frame, PPickler pickler, Object obj) { - saveTuple(frame, pickler, obj, null, length(frame, obj)); + private void saveNativeTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj) { + saveTuple(frame, pickler, proto, fastMode, obj, null, length(frame, obj)); } - private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj, SequenceStorage storage, int len) { + private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, SequenceStorage storage, int len) { if (len == 0) { - if (pickler.proto != 0) { + if (proto != 0) { write(pickler, PickleUtils.OPCODE_EMPTY_TUPLE); } else { write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_TUPLE); @@ -1684,7 +1690,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj, Sequenc // The tuple isn't in the memo now. If it shows up there after saving the tuple // elements, the tuple must be recursive, in which case we'll pop everything we put on // the stack, and fetch its value from the memo. - if (len <= 3 && pickler.proto >= 2) { + if (len <= 3 && proto >= 2) { // Use TUPLE{1,2,3} opcodes. storeTupleElements(frame, pickler, obj, storage, len); @@ -1695,14 +1701,14 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj, Sequenc write(pickler, PickleUtils.OPCODE_POP); } // fetch from memo - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); return; } else { // Not recursive. write(pickler, TUPLE_LEN_2_OPCODE[len]); } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); return; } @@ -1713,7 +1719,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj, Sequenc int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { // pop the stack stuff we pushed - if (pickler.isBin()) { + if (isBin(proto)) { write(pickler, PickleUtils.OPCODE_POP_MARK); } else { // Note that we pop one more than len, to remove the MARK too. @@ -1722,18 +1728,18 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj, Sequenc } } // fetch from memo - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); return; } else { // Not recursive. write(pickler, PickleUtils.OPCODE_TUPLE); } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } - private void saveBytearrayData(VirtualFrame frame, PPickler pickler, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { - assert pickler.proto >= 5; + private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { + assert proto >= 5; int size = bufferLib.getBufferLength(buffer); boolean wasFraming = pickler.framing; @@ -1755,14 +1761,14 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, Object obj, if (bypassBuffer && wasFraming) { pickler.framing = true; } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } - private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PPickler pickler, PByteArray obj) { + private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PByteArray obj) { Object buffer = getBufferAcquireLibrary().acquireReadonly(obj); PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { - if (pickler.proto < 5) { + if (proto < 5) { // Older pickle protocols do not have an opcode for pickling bytearrays. Object reduceValue; @@ -1775,17 +1781,17 @@ private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContex } // save_reduce() will memoize the object automatically. - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } else { - saveBytearrayData(frame, pickler, obj, buffer, bufferLib); + saveBytearrayData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } } finally { bufferLib.release(buffer); } } - private void savePickleBuffer(VirtualFrame frame, PPickler pickler, PPickleBuffer obj) { - if (pickler.proto < 5) { + private void savePickleBuffer(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PPickleBuffer obj) { + if (proto < 5) { throw raise(PicklingError, ErrorMessages.PICKLEBUFF_CANNOT_PICKLE_WITH_PROTO5); } @@ -1802,9 +1808,9 @@ private void savePickleBuffer(VirtualFrame frame, PPickler pickler, PPickleBuffe if (inBand) { // Write data in-band if (readOnly) { - saveBytesData(frame, pickler, obj, buffer, bufferLib); + saveBytesData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } else { - saveBytearrayData(frame, pickler, obj, buffer, bufferLib); + saveBytearrayData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } } else { // Write data out-of-band @@ -1815,24 +1821,24 @@ private void savePickleBuffer(VirtualFrame frame, PPickler pickler, PPickleBuffe } } - private void saveSingletonType(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj, Object singleton) { + private void saveSingletonType(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object singleton) { Object reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PythonClass), createTuple(singleton)); - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } - private void saveType(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, PythonManagedClass obj) { + private void saveType(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PythonManagedClass obj) { if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNone) { - saveSingletonType(frame, ctx, pickler, obj, PNone.NONE); + saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PNone.NONE); } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PEllipsis) { - saveSingletonType(frame, ctx, pickler, obj, PEllipsis.INSTANCE); + saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PEllipsis.INSTANCE); } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNotImplemented) { - saveSingletonType(frame, ctx, pickler, obj, PNotImplemented.NOT_IMPLEMENTED); + saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PNotImplemented.NOT_IMPLEMENTED); } else { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); + saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); } } - private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, Object obj, Object name) { + private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object name) { PickleState st = getGlobalState(ctx.getCore()); Object gName; if (name != null) { @@ -1865,7 +1871,7 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P } boolean genGlobal; - if (pickler.proto >= 2) { + if (proto >= 2) { genGlobal = false; // See whether this is in the extension registry, and if so generate an EXT opcode. @@ -1908,20 +1914,20 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P globalName = lastname; } - if (pickler.proto >= 4) { + if (proto >= 4) { save(frame, pickler, moduleName, 0); save(frame, pickler, globalName, 0); write(pickler, PickleUtils.OPCODE_STACK_GLOBAL); } else if (parent != module) { Object reduceValue = createTuple(st.getattr, createTuple(parent, lastname)); - saveReduce(frame, ctx, pickler, reduceValue, null); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, null); } else { // Generate a normal global opcode if we are using a pickle protocol < 4, or if // the object is not registered in the extension registry write(pickler, PickleUtils.OPCODE_GLOBAL); // For protocol < 3 and if the user didn't request against doing so, we convert // module names to the old 2.x module names. - if (pickler.proto < 3 && pickler.fixImports) { + if (proto < 3 && pickler.fixImports) { final Pair to2Mapping = get3to2Mapping(frame, ctx.getCore(), moduleName, globalName); moduleName = to2Mapping.getLeft(); globalName = to2Mapping.getRight(); @@ -1931,10 +1937,10 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P // module name and the global name using UTF-8. We do so only when we are using // the pickle protocol newer than version 3. This is to ensure compatibility // with older Unpickler running on Python 2.x. - if (pickler.proto >= 3) { + if (proto >= 3) { if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) == TruffleString.CodeRange.BROKEN || ensureTsGetCodeRangeNode().execute(globalName, TS_ENCODING) == TruffleString.CodeRange.BROKEN) { - throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); + throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); } writeUtf8(pickler, moduleName); write(pickler, (byte) '\n'); @@ -1942,7 +1948,7 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P } else { if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) != TruffleString.CodeRange.ASCII || ensureTsGetCodeRangeNode().execute(globalName, TS_ENCODING) != TruffleString.CodeRange.ASCII) { - throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); + throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); } writeASCII(pickler, moduleName); write(pickler, (byte) '\n'); @@ -1951,7 +1957,7 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P write(pickler, (byte) '\n'); } // Memoize the object - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } } @@ -1960,14 +1966,18 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa @Bind Node inliningTarget, @Cached("createFor($node)") BoundaryCallData boundaryCallData, @Cached CallNode callNode, - @Cached PyObjectCallMethodObjArgs callMethod) { + @Cached PyObjectCallMethodObjArgs callMethod, + @Cached InlinedIntValueProfile protoProfile, + @Cached InlinedConditionProfile fastModeProfile) { Object obj = objArg; + int proto = protoProfile.profile(inliningTarget, pickler.getProto()); + boolean fastMode = fastModeProfile.profile(inliningTarget, pickler.isFast()); opcodeBoundary(frame, pickler); // The extra pers_save argument is necessary to avoid calling save_pers() // on its returned object. if (persSave == 0 && pickler.persFunc != null) { - if (savePers(frame, pickler, obj)) { + if (savePers(frame, pickler, proto, obj)) { return; } } @@ -1977,22 +1987,22 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa saveNone(pickler); return; } else if (obj instanceof Boolean value) { - saveBool(pickler, value); + saveBool(pickler, proto, value); return; } else if (obj instanceof Integer value) { - saveLong(pickler, value); + saveLong(pickler, proto, value); return; } else if (obj instanceof Long value) { - saveLong(frame, pickler, value); + saveLong(frame, pickler, proto, value); return; } else if (obj instanceof PInt value && PGuards.isBuiltinPInt(value)) { - saveLong(frame, pickler, value); + saveLong(frame, pickler, proto, value); return; } else if (obj instanceof Double value) { - saveFloat(pickler, value); + saveFloat(pickler, proto, value); return; } else if (obj instanceof PFloat value && PGuards.isBuiltinPFloat(value)) { - saveFloat(pickler, value.getValue()); + saveFloat(pickler, proto, value.getValue()); return; } @@ -2005,44 +2015,44 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa // instead of pickling the object once again. int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); return; } PythonContext ctx = PythonContext.get(this); if (obj instanceof PBytes bytes && PGuards.isBuiltinBytes(bytes)) { - saveBytes(frame, ctx, pickler, bytes); + saveBytes(frame, ctx, pickler, proto, fastMode, bytes); return; } else if (obj instanceof TruffleString string) { - saveUnicode(frame, pickler, string); + saveUnicode(frame, pickler, proto, fastMode, string); return; } else if (obj instanceof PString string && PGuards.isBuiltinPString(string)) { - saveUnicode(frame, pickler, string); + saveUnicode(frame, pickler, proto, fastMode, string); return; } else if (obj instanceof PDict dict && PGuards.isBuiltinDict(dict)) { - saveDict(frame, inliningTarget, callMethod, pickler, dict); + saveDict(frame, inliningTarget, callMethod, pickler, proto, fastMode, dict); return; } else if (obj instanceof PSet set && PGuards.isBuiltinSet(set)) { - saveSet(frame, ctx, pickler, set); + saveSet(frame, ctx, pickler, proto, fastMode, set); return; } else if (obj instanceof PFrozenSet frozenSet && PGuards.isBuiltinFrozenSet(frozenSet)) { - saveFrozenset(frame, ctx, pickler, frozenSet); + saveFrozenset(frame, ctx, pickler, proto, fastMode, frozenSet); return; } else if (obj instanceof PList list && PGuards.isBuiltinList(list)) { - saveList(frame, pickler, list); + saveList(frame, pickler, proto, fastMode, list); return; } else if (obj instanceof PTuple tuple && PGuards.isBuiltinTuple(tuple)) { - saveTuple(frame, pickler, tuple); + saveTuple(frame, pickler, proto, fastMode, tuple); return; } else if (PGuards.isNativeObject(obj) && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PTuple)) { - saveNativeTuple(frame, pickler, obj); + saveNativeTuple(frame, pickler, proto, fastMode, obj); return; } else if (obj instanceof PByteArray byteArray && PGuards.isBuiltinByteArray(byteArray)) { - saveBytearray(frame, inliningTarget, ctx, pickler, byteArray); + saveBytearray(frame, inliningTarget, ctx, pickler, proto, fastMode, byteArray); return; } else if (obj instanceof PPickleBuffer buffer) { - savePickleBuffer(frame, pickler, buffer); + savePickleBuffer(frame, pickler, proto, fastMode, buffer); return; } @@ -2051,19 +2061,19 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa if (pickler.reducerOverride != null) { Object reduceValue = callNode.execute(frame, pickler.reducerOverride, obj); if (reduceValue != PNotImplemented.NOT_IMPLEMENTED) { - handleReduce(frame, boundaryCallData, ctx, pickler, obj, reduceValue); + handleReduce(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, reduceValue); return; } } if (obj instanceof PythonManagedClass clazz && clazz.getPythonClass() == PythonBuiltinClassType.PythonClass) { - saveType(frame, boundaryCallData, ctx, pickler, clazz); + saveType(frame, boundaryCallData, ctx, pickler, proto, fastMode, clazz); return; } else if (obj instanceof PythonNativeClass && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PythonClass)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); + saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); return; } else if (obj instanceof PFunction) { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); + saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); return; } @@ -2087,7 +2097,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa if (reduceFunc != null) { reduceValue = callNode.execute(frame, reduceFunc, obj); } else if (isSubType(type, PythonBuiltinClassType.PythonClass)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); + saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); return; } else { // XXX: If the __reduce__ method is defined, __reduce_ex__ is automatically defined @@ -2099,7 +2109,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa // Check for a __reduce_ex__ method. reduceFunc = lookupAttribute(frame, obj, T___REDUCE_EX__); if (reduceFunc != PNone.NO_VALUE) { - reduceValue = callNode.execute(frame, reduceFunc, pickler.proto); + reduceValue = callNode.execute(frame, reduceFunc, proto); } else { // Check for a __reduce__ method. reduceFunc = lookupAttribute(frame, obj, T___REDUCE__); @@ -2111,7 +2121,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa } } - handleReduce(frame, boundaryCallData, ctx, pickler, obj, reduceValue); + handleReduce(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, reduceValue); } } From 3fc5f9d4621bdc3deb6b2c1cf37c00a3014cea88 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 25 Sep 2026 11:51:34 +0200 Subject: [PATCH 075/129] Add a recursion limit to PPickler (cherry picked from commit 964bd5ed2e54fabaef8860faefc70fca75226551) --- .../builtins/modules/pickle/PPickler.java | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index a569141a3f..b17836e755 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -113,6 +113,7 @@ import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.IsNode; +import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; @@ -658,7 +659,11 @@ public void flush(VirtualFrame frame, PPickler pickler, } public abstract static class SaveNode extends BasePickleWriteNode { + private static final int MAX_RECURSION_DEPTH = 3; + + private final int depth; @Child private SaveNode recursiveSaveNode; + @Child private BoundaryCallData boundaryCallData; @Child private PyLongAsLongNode pyLongAsLongNode; @Child private PyObjectStrAsObjectNode pyObjectStrAsObjectNode; @Child private PyObjectIsTrueNode isTrueNode; @@ -671,6 +676,18 @@ public abstract static class SaveNode extends BasePickleWriteNode { @Child private HashingStorageLen hashingStorageLenNode; @Child private PyTupleCheckNode.CachedNode tupleCheckNode; + protected SaveNode(int depth) { + this.depth = depth; + } + + private BoundaryCallData getBoundaryCallData() { + if (boundaryCallData == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + boundaryCallData = insert(BoundaryCallData.createFor(this)); + } + return boundaryCallData; + } + private int getHashingStorageLength(HashingStorage storage) { if (hashingStorageLenNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -688,11 +705,32 @@ private boolean isTuple(Object object) { } private void save(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { + if (depth < 0) { + // This should never be reached for compilation, but native-image can't prove it + CompilerDirectives.transferToInterpreterAndInvalidate(); + execute(frame, pickler, obj, persSave); + return; + } if (recursiveSaveNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveSaveNode = insert(PPicklerFactory.SaveNodeGen.create()); + recursiveSaveNode = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + } + if (depth < MAX_RECURSION_DEPTH) { + recursiveSaveNode.execute(frame, pickler, obj, persSave); + } else { + BoundaryCallData callData = getBoundaryCallData(); + Object savedState = BoundaryCallContext.enter(frame, callData); + try { + saveBoundary(pickler, obj, persSave); + } finally { + BoundaryCallContext.exit(frame, callData, savedState); + } } - recursiveSaveNode.execute(frame, pickler, obj, persSave); + } + + @TruffleBoundary + private void saveBoundary(PPickler pickler, Object obj, int persSave) { + recursiveSaveNode.execute(null, pickler, obj, persSave); } private long asLong(VirtualFrame frame, Object object) { @@ -995,9 +1033,9 @@ private void memoPut(PPickler pickler, int proto, boolean fastMode, Object obj) } // save methods - private void handleReduce(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object reduceValue) { + private void handleReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object reduceValue) { if (PGuards.isString(reduceValue)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, reduceValue); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, reduceValue); return; } @@ -1826,7 +1864,7 @@ private void saveSingletonType(VirtualFrame frame, PythonContext ctx, PPickler p saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } - private void saveType(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PythonManagedClass obj) { + private void saveType(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PythonManagedClass obj) { if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNone) { saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PNone.NONE); } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PEllipsis) { @@ -1834,11 +1872,11 @@ private void saveType(VirtualFrame frame, BoundaryCallData boundaryCallData, Pyt } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNotImplemented) { saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PNotImplemented.NOT_IMPLEMENTED); } else { - saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); } } - private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object name) { + private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object name) { PickleState st = getGlobalState(ctx.getCore()); Object gName; if (name != null) { @@ -1856,7 +1894,7 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P Object module; try { - module = importModule(frame, boundaryCallData, moduleName); + module = importModule(frame, getBoundaryCallData(), moduleName); } catch (PException e) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_IMPORT_OF_MODULE_S_FAILED, obj, moduleName); } @@ -1964,7 +2002,6 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P @Specialization void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSave, @Bind Node inliningTarget, - @Cached("createFor($node)") BoundaryCallData boundaryCallData, @Cached CallNode callNode, @Cached PyObjectCallMethodObjArgs callMethod, @Cached InlinedIntValueProfile protoProfile, @@ -2061,19 +2098,19 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa if (pickler.reducerOverride != null) { Object reduceValue = callNode.execute(frame, pickler.reducerOverride, obj); if (reduceValue != PNotImplemented.NOT_IMPLEMENTED) { - handleReduce(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, reduceValue); + handleReduce(frame, ctx, pickler, proto, fastMode, obj, reduceValue); return; } } if (obj instanceof PythonManagedClass clazz && clazz.getPythonClass() == PythonBuiltinClassType.PythonClass) { - saveType(frame, boundaryCallData, ctx, pickler, proto, fastMode, clazz); + saveType(frame, ctx, pickler, proto, fastMode, clazz); return; } else if (obj instanceof PythonNativeClass && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PythonClass)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } else if (obj instanceof PFunction) { - saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } @@ -2097,7 +2134,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa if (reduceFunc != null) { reduceValue = callNode.execute(frame, reduceFunc, obj); } else if (isSubType(type, PythonBuiltinClassType.PythonClass)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, null); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } else { // XXX: If the __reduce__ method is defined, __reduce_ex__ is automatically defined @@ -2121,7 +2158,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa } } - handleReduce(frame, boundaryCallData, ctx, pickler, proto, fastMode, obj, reduceValue); + handleReduce(frame, ctx, pickler, proto, fastMode, obj, reduceValue); } } @@ -2130,7 +2167,7 @@ public abstract static class DumpNode extends BasePickleWriteNode { @Specialization public void dump(VirtualFrame frame, PPickler pickler, Object obj, - @Cached SaveNode saveNode) { + @Cached("create(0)") SaveNode saveNode) { try { final Object tmp = getLookupAttrNode().executeCached(frame, pickler, REDUCE_OVERRIDE); if (tmp != PNone.NO_VALUE) { From 1c908d120ade75747f33c9f91a33037d36811ec9 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 25 Sep 2026 13:38:14 +0200 Subject: [PATCH 076/129] Add more profiling to PPickler (cherry picked from commit 1011631ac95883157242b98cd1d727023c629d53) --- .../builtins/modules/pickle/PPickler.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index b17836e755..6b2b64986d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -124,6 +124,7 @@ import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -661,6 +662,33 @@ public void flush(VirtualFrame frame, PPickler pickler, public abstract static class SaveNode extends BasePickleWriteNode { private static final int MAX_RECURSION_DEPTH = 3; + private static final int SEEN_NONE = 1 << 0; + private static final int SEEN_BOOLEAN = 1 << 1; + private static final int SEEN_INTEGER = 1 << 2; + private static final int SEEN_LONG = 1 << 3; + private static final int SEEN_PINT = 1 << 4; + private static final int SEEN_DOUBLE = 1 << 5; + private static final int SEEN_PFLOAT = 1 << 6; + private static final int SEEN_BUILTIN_CLASS_TYPE = 1 << 7; + private static final int SEEN_BYTES = 1 << 8; + private static final int SEEN_TRUFFLE_STRING = 1 << 9; + private static final int SEEN_PSTRING = 1 << 10; + private static final int SEEN_DICT = 1 << 11; + private static final int SEEN_SET = 1 << 12; + private static final int SEEN_FROZENSET = 1 << 13; + private static final int SEEN_LIST = 1 << 14; + private static final int SEEN_TUPLE = 1 << 15; + private static final int SEEN_NATIVE_TUPLE = 1 << 16; + private static final int SEEN_BYTE_ARRAY = 1 << 17; + private static final int SEEN_PICKLE_BUFFER = 1 << 18; + private static final int SEEN_MANAGED_CLASS = 1 << 19; + private static final int SEEN_NATIVE_CLASS = 1 << 20; + private static final int SEEN_FUNCTION = 1 << 21; + private static final int SEEN_TYPE = 1 << 22; + private static final int SEEN_OBJECT = 1 << 23; + + @CompilationFinal private int seenTypes; + private final int depth; @Child private SaveNode recursiveSaveNode; @Child private BoundaryCallData boundaryCallData; @@ -680,6 +708,13 @@ protected SaveNode(int depth) { this.depth = depth; } + private void profileSeen(int seen) { + if ((seenTypes & seen) == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenTypes |= seen; + } + } + private BoundaryCallData getBoundaryCallData() { if (boundaryCallData == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -2021,30 +2056,38 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa // Atom types; these aren't memoized, so don't check the memo. if (obj == PNone.NONE) { + profileSeen(SEEN_NONE); saveNone(pickler); return; } else if (obj instanceof Boolean value) { + profileSeen(SEEN_BOOLEAN); saveBool(pickler, proto, value); return; } else if (obj instanceof Integer value) { + profileSeen(SEEN_INTEGER); saveLong(pickler, proto, value); return; } else if (obj instanceof Long value) { + profileSeen(SEEN_LONG); saveLong(frame, pickler, proto, value); return; } else if (obj instanceof PInt value && PGuards.isBuiltinPInt(value)) { + profileSeen(SEEN_PINT); saveLong(frame, pickler, proto, value); return; } else if (obj instanceof Double value) { + profileSeen(SEEN_DOUBLE); saveFloat(pickler, proto, value); return; } else if (obj instanceof PFloat value && PGuards.isBuiltinPFloat(value)) { + profileSeen(SEEN_PFLOAT); saveFloat(pickler, proto, value.getValue()); return; } // to avoid misses in memo for the class: if (obj instanceof PythonBuiltinClassType classType) { + profileSeen(SEEN_BUILTIN_CLASS_TYPE); obj = PythonContext.get(this).getCore().lookupType(classType); } @@ -2059,36 +2102,47 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa PythonContext ctx = PythonContext.get(this); if (obj instanceof PBytes bytes && PGuards.isBuiltinBytes(bytes)) { + profileSeen(SEEN_BYTES); saveBytes(frame, ctx, pickler, proto, fastMode, bytes); return; } else if (obj instanceof TruffleString string) { + profileSeen(SEEN_TRUFFLE_STRING); saveUnicode(frame, pickler, proto, fastMode, string); return; } else if (obj instanceof PString string && PGuards.isBuiltinPString(string)) { + profileSeen(SEEN_PSTRING); saveUnicode(frame, pickler, proto, fastMode, string); return; } else if (obj instanceof PDict dict && PGuards.isBuiltinDict(dict)) { + profileSeen(SEEN_DICT); saveDict(frame, inliningTarget, callMethod, pickler, proto, fastMode, dict); return; } else if (obj instanceof PSet set && PGuards.isBuiltinSet(set)) { + profileSeen(SEEN_SET); saveSet(frame, ctx, pickler, proto, fastMode, set); return; } else if (obj instanceof PFrozenSet frozenSet && PGuards.isBuiltinFrozenSet(frozenSet)) { + profileSeen(SEEN_FROZENSET); saveFrozenset(frame, ctx, pickler, proto, fastMode, frozenSet); return; } else if (obj instanceof PList list && PGuards.isBuiltinList(list)) { + profileSeen(SEEN_LIST); saveList(frame, pickler, proto, fastMode, list); return; } else if (obj instanceof PTuple tuple && PGuards.isBuiltinTuple(tuple)) { + profileSeen(SEEN_TUPLE); saveTuple(frame, pickler, proto, fastMode, tuple); return; } else if (PGuards.isNativeObject(obj) && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PTuple)) { + profileSeen(SEEN_NATIVE_TUPLE); saveNativeTuple(frame, pickler, proto, fastMode, obj); return; } else if (obj instanceof PByteArray byteArray && PGuards.isBuiltinByteArray(byteArray)) { + profileSeen(SEEN_BYTE_ARRAY); saveBytearray(frame, inliningTarget, ctx, pickler, proto, fastMode, byteArray); return; } else if (obj instanceof PPickleBuffer buffer) { + profileSeen(SEEN_PICKLE_BUFFER); savePickleBuffer(frame, pickler, proto, fastMode, buffer); return; } @@ -2104,16 +2158,21 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa } if (obj instanceof PythonManagedClass clazz && clazz.getPythonClass() == PythonBuiltinClassType.PythonClass) { + profileSeen(SEEN_MANAGED_CLASS); saveType(frame, ctx, pickler, proto, fastMode, clazz); return; } else if (obj instanceof PythonNativeClass && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PythonClass)) { + profileSeen(SEEN_NATIVE_CLASS); saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } else if (obj instanceof PFunction) { + profileSeen(SEEN_FUNCTION); saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } + profileSeen(SEEN_OBJECT); + // Get a reduction callable, and call it. This may come from self.dispatch_table, // copyreg.dispatch_table, the object's __reduce_ex__ method, or the object's __reduce__ // method. @@ -2134,6 +2193,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa if (reduceFunc != null) { reduceValue = callNode.execute(frame, reduceFunc, obj); } else if (isSubType(type, PythonBuiltinClassType.PythonClass)) { + profileSeen(SEEN_TYPE); saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } else { From 09a5e1021f48870d8b641d3191705679cc164ba1 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 25 Sep 2026 15:22:04 +0200 Subject: [PATCH 077/129] Add fast path for pickling sequences of primitives (cherry picked from commit f1044d3caf42abb3fa9864742e75b631144d8c4f) --- .../builtins/modules/pickle/PPickler.java | 132 +++++++++++++++++- .../builtins/modules/pickle/PicklerNodes.java | 8 +- 2 files changed, 133 insertions(+), 7 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 6b2b64986d..2733245bfb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -118,6 +118,9 @@ 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.runtime.sequence.storage.DoubleSequenceStorage; +import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage; +import com.oracle.graal.python.runtime.sequence.storage.LongSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; import com.oracle.graal.python.util.Consumer; import com.oracle.graal.python.util.NumericSupport; @@ -686,6 +689,10 @@ public abstract static class SaveNode extends BasePickleWriteNode { private static final int SEEN_FUNCTION = 1 << 21; private static final int SEEN_TYPE = 1 << 22; private static final int SEEN_OBJECT = 1 << 23; + private static final int SEEN_INT_STORAGE = 1 << 24; + private static final int SEEN_LONG_STORAGE = 1 << 25; + private static final int SEEN_DOUBLE_STORAGE = 1 << 26; + private static final int SEEN_GENERIC_STORAGE = 1 << 27; @CompilationFinal private int seenTypes; @@ -1661,9 +1668,25 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { final SequenceStorage storage = obj.getSequenceStorage(); + if (pickler.persFunc == null) { + if (storage instanceof IntSequenceStorage intStorage) { + profileSeen(SEEN_INT_STORAGE); + batchIntList(frame, pickler, intStorage); + return; + } else if (storage instanceof LongSequenceStorage longStorage) { + profileSeen(SEEN_LONG_STORAGE); + batchLongList(frame, pickler, longStorage); + return; + } else if (storage instanceof DoubleSequenceStorage doubleStorage) { + profileSeen(SEEN_DOUBLE_STORAGE); + batchDoubleList(frame, pickler, doubleStorage); + return; + } + } + profileSeen(SEEN_GENERIC_STORAGE); Object item; if (storage.length() == 1) { - item = getItem(frame, storage, 0); + item = getItem(storage, 0); save(frame, pickler, item, 0); write(pickler, PickleUtils.OPCODE_APPEND); return; @@ -1676,7 +1699,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { thisBatch = 0; write(pickler, PickleUtils.OPCODE_MARK); while (total < storage.length()) { - item = getItem(frame, storage, total); + item = getItem(storage, total); save(frame, pickler, item, 0); total++; if (++thisBatch == PickleUtils.BATCHSIZE) { @@ -1687,6 +1710,69 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { } while (total < storage.length()); } + private void batchIntList(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { + int proto = pickler.getProto(); + if (storage.length() == 1) { + opcodeBoundary(frame, pickler); + saveLong(pickler, proto, storage.getIntItemNormalized(0)); + write(pickler, PickleUtils.OPCODE_APPEND); + return; + } + + int length = storage.length(); + for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { + int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + write(pickler, PickleUtils.OPCODE_MARK); + for (int i = batchStart; i < batchEnd; i++) { + opcodeBoundary(frame, pickler); + saveLong(pickler, proto, storage.getIntItemNormalized(i)); + } + write(pickler, PickleUtils.OPCODE_APPENDS); + } + } + + private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceStorage storage) { + int proto = pickler.getProto(); + if (storage.length() == 1) { + opcodeBoundary(frame, pickler); + saveLong(frame, pickler, proto, storage.getLongItemNormalized(0)); + write(pickler, PickleUtils.OPCODE_APPEND); + return; + } + + int length = storage.length(); + for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { + int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + write(pickler, PickleUtils.OPCODE_MARK); + for (int i = batchStart; i < batchEnd; i++) { + opcodeBoundary(frame, pickler); + saveLong(frame, pickler, proto, storage.getLongItemNormalized(i)); + } + write(pickler, PickleUtils.OPCODE_APPENDS); + } + } + + private void batchDoubleList(VirtualFrame frame, PPickler pickler, DoubleSequenceStorage storage) { + int proto = pickler.getProto(); + if (storage.length() == 1) { + opcodeBoundary(frame, pickler); + saveFloat(pickler, proto, storage.getDoubleItemNormalized(0)); + write(pickler, PickleUtils.OPCODE_APPEND); + return; + } + + int length = storage.length(); + for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { + int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + write(pickler, PickleUtils.OPCODE_MARK); + for (int i = batchStart; i < batchEnd; i++) { + opcodeBoundary(frame, pickler); + saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); + } + write(pickler, PickleUtils.OPCODE_APPENDS); + } + } + private void batchList(VirtualFrame frame, PPickler pickler, int proto, Object iterator) { assert iterator != null; if (proto == 0) { @@ -1734,12 +1820,52 @@ private void storeTupleElements(VirtualFrame frame, PPickler pickler, Object obj } } else { assert storage.length() == len; + if (pickler.persFunc == null) { + if (storage instanceof IntSequenceStorage intStorage) { + profileSeen(SEEN_INT_STORAGE); + storeIntTupleElements(frame, pickler, intStorage); + return; + } else if (storage instanceof LongSequenceStorage longStorage) { + profileSeen(SEEN_LONG_STORAGE); + storeLongTupleElements(frame, pickler, longStorage); + return; + } else if (storage instanceof DoubleSequenceStorage doubleStorage) { + profileSeen(SEEN_DOUBLE_STORAGE); + storeDoubleTupleElements(frame, pickler, doubleStorage); + return; + } + } + profileSeen(SEEN_GENERIC_STORAGE); for (int i = 0; i < len; i++) { - save(frame, pickler, getItem(frame, storage, i), 0); + save(frame, pickler, getItem(storage, i), 0); } } } + private void storeIntTupleElements(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { + int proto = pickler.getProto(); + for (int i = 0; i < storage.length(); i++) { + opcodeBoundary(frame, pickler); + saveLong(pickler, proto, storage.getIntItemNormalized(i)); + } + } + + private void storeLongTupleElements(VirtualFrame frame, PPickler pickler, LongSequenceStorage storage) { + int proto = pickler.getProto(); + for (int i = 0; i < storage.length(); i++) { + opcodeBoundary(frame, pickler); + saveLong(frame, pickler, proto, storage.getLongItemNormalized(i)); + } + } + + private void storeDoubleTupleElements(VirtualFrame frame, PPickler pickler, DoubleSequenceStorage storage) { + int proto = pickler.getProto(); + for (int i = 0; i < storage.length(); i++) { + opcodeBoundary(frame, pickler); + saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); + } + } + private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PTuple obj) { SequenceStorage storage = obj.getSequenceStorage(); saveTuple(frame, pickler, proto, fastMode, obj, storage, storage.length()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 8ac0b1339e..419ec3a8b6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -135,7 +135,7 @@ abstract static class BasePickleNode extends Node { @Child private HashingStorageSetItem setHashingStorageItemNode; @Child private PyObjectSetItem pyObjectSetItemNode; @Child private CachedHashingStorageGetItem getHashingStorageItemNode; - @Child private SequenceStorageNodes.GetItemNode getSeqStorageItemNode; + @Child private SequenceStorageNodes.GetItemScalarNode getSeqStorageItemNode; @Child private PyNumberAsSizeNode asSizeNode; @Child private CastToTruffleStringNode castToTruffleStringNode; @Child private SequenceNodes.GetSequenceStorageNode getSequenceStorageNode; @@ -556,12 +556,12 @@ public Object getNextItem(VirtualFrame frame, Object iterator) { return getNextNode.executeCached(frame, iterator); } - public Object getItem(VirtualFrame frame, SequenceStorage storage, int i) { + public Object getItem(SequenceStorage storage, int i) { if (getSeqStorageItemNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - getSeqStorageItemNode = insert(SequenceStorageNodes.GetItemNode.create()); + getSeqStorageItemNode = insert(SequenceStorageNodes.GetItemScalarNode.create()); } - return getSeqStorageItemNode.execute(frame, storage, i); + return getSeqStorageItemNode.executeCached(storage, i); } public Object getItem(VirtualFrame frame, Object obj, Object slice) { From ae1b2b156e14d8a600438dc5a1d21b402e643367 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 29 Sep 2026 11:31:27 +0200 Subject: [PATCH 078/129] Add more pickler optimizations (cherry picked from commit ba662f23aea95192447a2e288595b760da57b3dc) --- .../builtins/modules/pickle/PPickler.java | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 2733245bfb..75d1e8b08e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -504,6 +504,10 @@ protected void writeASCII(PPickler pickler, TruffleString string) { protected void writeUtf8(PPickler pickler, TruffleString string) { TruffleString encoded = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + writeUtf8Converted(pickler, encoded); + } + + public void writeUtf8Converted(PPickler pickler, TruffleString encoded) { int length = encoded.byteLength(TruffleString.Encoding.UTF_8); ensureBufferSpace(pickler, length); ensureTsCopyToByteArrayNode().execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.UTF_8); @@ -588,25 +592,20 @@ protected void write(PPickler pickler, byte[] bytes, int dataLen) { public void ensureBufferSpace(PPickler pickler, int dataLen) { boolean needNewFrame = pickler.isFraming() && pickler.frameStart == -1; - int n = (needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; + int n = CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; int required = pickler.outputLen + n; - if (required > pickler.maxOutputLen) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, required > pickler.maxOutputLen)) { // Make place in buffer for the pickle chunk // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX - if (pickler.outputLen >= Integer.MAX_VALUE / 2 - n) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, pickler.outputLen >= Integer.MAX_VALUE / 2 - n)) { throw raise(PythonBuiltinClassType.MemoryError); } pickler.maxOutputLen = (pickler.outputLen + n) / 2 * 3; pickler.outputBuffer = PythonUtils.arrayCopyOf(pickler.outputBuffer, pickler.maxOutputLen); } - if (needNewFrame) { - int frameStart = pickler.outputLen; - pickler.frameStart = frameStart; - for (int i = 0; i < PickleUtils.FRAME_HEADER_SIZE; i++) { - // Write an invalid value, for debugging - pickler.outputBuffer[frameStart + i] = (byte) 0xFE; - } + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame)) { + pickler.frameStart = pickler.outputLen; pickler.outputLen += PickleUtils.FRAME_HEADER_SIZE; } } @@ -693,6 +692,10 @@ public abstract static class SaveNode extends BasePickleWriteNode { private static final int SEEN_LONG_STORAGE = 1 << 25; private static final int SEEN_DOUBLE_STORAGE = 1 << 26; private static final int SEEN_GENERIC_STORAGE = 1 << 27; + private static final int SEEN_CUSTOM_DISPATCH = 1 << 28; + private static final int SEEN_REGISTERED_REDUCER = 1 << 29; + private static final int SEEN_REDUCE_EX = 1 << 30; + private static final int SEEN_REDUCE = 1 << 31; @CompilationFinal private int seenTypes; @@ -1494,7 +1497,7 @@ private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, int proto, } else { writeIntOp(pickler, PickleUtils.OPCODE_BINUNICODE, size); } - writeUtf8(pickler, utf8); + writeUtf8Converted(pickler, utf8); } if (bypassBuffer && wasFraming) { @@ -2308,6 +2311,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa PickleState state = getGlobalState(ctx.getCore()); reduceFunc = getDictItem(frame, state.dispatchTable, type); } else { + profileSeen(SEEN_CUSTOM_DISPATCH); try { reduceFunc = getItem(frame, pickler.dispatchTable, type); } catch (PException ex) { @@ -2317,6 +2321,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa Object reduceValue; if (reduceFunc != null) { + profileSeen(SEEN_REGISTERED_REDUCER); reduceValue = callNode.execute(frame, reduceFunc, obj); } else if (isSubType(type, PythonBuiltinClassType.PythonClass)) { profileSeen(SEEN_TYPE); @@ -2332,11 +2337,13 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa // Check for a __reduce_ex__ method. reduceFunc = lookupAttribute(frame, obj, T___REDUCE_EX__); if (reduceFunc != PNone.NO_VALUE) { + profileSeen(SEEN_REDUCE_EX); reduceValue = callNode.execute(frame, reduceFunc, proto); } else { // Check for a __reduce__ method. reduceFunc = lookupAttribute(frame, obj, T___REDUCE__); if (reduceFunc != PNone.NO_VALUE) { + profileSeen(SEEN_REDUCE); reduceValue = callNode.execute(frame, reduceFunc); } else { throw raise(PicklingError, ErrorMessages.CANNOT_PICKLE_P_P, type, obj); From fb6c306777e10cd82b32bbd3c43747a0de973d51 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 29 Sep 2026 14:58:29 +0200 Subject: [PATCH 079/129] Push down helper nodes into PPickler.SaveNode (cherry picked from commit b60b36c563c3261217ab483bb18d0ec31310946a) --- .../builtins/modules/pickle/PPickler.java | 513 ++++++++++++++++-- .../builtins/modules/pickle/PicklerNodes.java | 110 ---- 2 files changed, 474 insertions(+), 149 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 75d1e8b08e..296cb5cecf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -40,6 +40,13 @@ */ package com.oracle.graal.python.builtins.modules.pickle; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; +import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; +import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; +import static com.oracle.graal.python.nodes.ErrorMessages.MUST_BE_STR_NOT_P; +import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; +import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MODULE__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NAME__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NEWOBJ_EX__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NEWOBJ__; @@ -48,8 +55,10 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE__; +import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.nodes.StringLiterals.T_NEWLINE; import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.PicklingError; @@ -65,6 +74,7 @@ import org.graalvm.collections.Pair; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PNotImplemented; @@ -75,15 +85,19 @@ import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass; import com.oracle.graal.python.builtins.objects.common.HashingStorage; +import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.CachedHashingStorageGetItem; +import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetIterator; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIterator; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorKey; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorNext; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorValue; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageLen; +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.ellipsis.PEllipsis; import com.oracle.graal.python.builtins.objects.floats.PFloat; 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.ints.IntNodes; import com.oracle.graal.python.builtins.objects.ints.IntNodesFactory; import com.oracle.graal.python.builtins.objects.ints.PInt; @@ -92,27 +106,41 @@ import com.oracle.graal.python.builtins.objects.set.PFrozenSet; import com.oracle.graal.python.builtins.objects.set.PSet; import com.oracle.graal.python.builtins.objects.str.PString; +import com.oracle.graal.python.builtins.objects.str.StringUtils; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.builtins.objects.type.PythonManagedClass; import com.oracle.graal.python.builtins.objects.type.TypeNodes; import com.oracle.graal.python.lib.IteratorExhausted; import com.oracle.graal.python.lib.PyCallableCheckNode; +import com.oracle.graal.python.lib.PyIterCheckNode; +import com.oracle.graal.python.lib.PyIterNextNode; import com.oracle.graal.python.lib.PyLongAsLongNode; import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; +import com.oracle.graal.python.lib.PyObjectGetItem; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectIsTrueNode; import com.oracle.graal.python.lib.PyObjectLookupAttr; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; +import com.oracle.graal.python.lib.PyObjectSizeNode; import com.oracle.graal.python.lib.PyObjectStrAsObjectNode; import com.oracle.graal.python.lib.PyTupleCheckNode; import com.oracle.graal.python.nodes.ErrorMessages; +import com.oracle.graal.python.nodes.HiddenAttr; import com.oracle.graal.python.nodes.PGuards; import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; +import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNodeGen; +import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode; import com.oracle.graal.python.nodes.builtins.ListNodes; import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.nodes.classes.IsSubtypeNode; +import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile; +import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; +import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.IsNode; +import com.oracle.graal.python.nodes.util.CannotCastException; +import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PythonContext; @@ -131,10 +159,13 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.Specialization; +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.object.Shape; +import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedIntValueProfile; import com.oracle.truffle.api.strings.TranscodingErrorHandler; @@ -387,12 +418,15 @@ public PBytes getString(PythonLanguage language) { } // inner nodes - public abstract static class BasePickleWriteNode extends PicklerNodes.BasePickleNode { + public abstract static class SaveNode extends Node { + private static final int MAX_RECURSION_DEPTH = 3; + private static final TruffleString T_LOCALS = tsLiteral(""); + private static final TruffleString T_SYS_MODULES = tsLiteral("sys.modules"); + static final byte[] TUPLE_LEN_2_OPCODE = new byte[]{PickleUtils.OPCODE_EMPTY_TUPLE, PickleUtils.OPCODE_TUPLE1, PickleUtils.OPCODE_TUPLE2, PickleUtils.OPCODE_TUPLE3}; static final byte NEW_LINE_BYTE = '\n'; static final TruffleString DICT_ITEMS = tsLiteral("dict items"); static final TruffleString LATIN1 = tsLiteral("latin1"); - static final TruffleString REDUCE_OVERRIDE = tsLiteral("reducer_override"); static final TruffleString T_L_NEW_LINE = tsLiteral("L\n"); static final TruffleString T_SET = tsLiteral("set"); static final TruffleString T_DICTIONARY = tsLiteral("dictionary"); @@ -405,6 +439,413 @@ public abstract static class BasePickleWriteNode extends PicklerNodes.BasePickle @Child private TypeNodes.IsTypeNode isTypeNode; @Child private FlushToFileNode flushToFileNode; @Child private CallNode callNode; + @SuppressWarnings("FieldMayBeFinal") @Child private PyObjectGetItem getItemNode = PyObjectGetItem.create(); + @SuppressWarnings("FieldMayBeFinal") @Child private PyIterNextNode getNextNode = PyIterNextNode.create(); + @Child private CastToTruffleStringNode toStringNode = CastToTruffleStringNode.create(); + @Child private HiddenAttr.ReadNode readHiddenAttributeNode; + @Child private IsBuiltinObjectProfile errProfile; + @Child private InlineIsBuiltinClassProfile isBuiltinClassProfile; + @Child private CachedHashingStorageGetItem getHashingStorageItemNode; + @Child private SequenceStorageNodes.GetItemScalarNode getSeqStorageItemNode; + @Child private PyObjectSizeNode sizeNode; + @Child private PyIterCheckNode isIteratorObjectNode; + @Child private GetClassNode getClassNode; + @Child private PyObjectLookupAttr lookupAttrNode; + @Child private ExecutePositionalStarargsNode getArgsNode; + @Child private ExpandKeywordStarargsNode getKwArgsNode; + @Child private HashingStorageGetIterator getHashingStorageIteratorNode; + @Child private HashingStorageIteratorNext hashingStorageItNext; + @Child private HashingStorageIteratorKey hashingStorageItKey; + @Child private HashingStorageIteratorValue hashingStorageItValue; + @Child private TruffleString.FromByteArrayWithCompactionUTF32Node tsFromByteArrayWithCompactionNode; + @Child private TruffleString.CodePointLengthNode tsCodePointLengthNode; + @Child private TruffleString.CodePointAtIndexUTF32Node tsCodePointAtIndexUTF32Node; + @Child private TruffleString.FromLongNode tsFromLongNode; + @Child private TruffleString.IndexOfStringNode tsIndexOfStringNode; + @Child private TruffleString.SubstringNode tsSubstringNode; + @Child private TruffleString.EqualNode tsEqualNode; + @Child private TruffleString.CopyToByteArrayNode tsCopyToByteArrayNode; + @Child private TruffleString.GetCodeRangeNode tsGetCodeRangeNode; + @Child private TruffleString.SwitchEncodingNode tsSwitchEncodingNode; + private final BranchProfile errorProfile = BranchProfile.create(); + + protected PException raise(PythonBuiltinClassType type, TruffleString string) { + errorProfile.enter(); + return PRaiseNode.raiseStatic(this, type, string); + } + + protected PException raise(PythonBuiltinClassType exceptionType) { + errorProfile.enter(); + return PRaiseNode.raiseStatic(this, exceptionType); + } + + protected final PException raise(PythonBuiltinClassType type, TruffleString format, Object... arguments) { + errorProfile.enter(); + return PRaiseNode.raiseStatic(this, type, format, arguments); + } + + protected TruffleString.FromByteArrayWithCompactionUTF32Node ensureTsFromByteArrayWithCompaction() { + if (tsFromByteArrayWithCompactionNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsFromByteArrayWithCompactionNode = insert(TruffleString.FromByteArrayWithCompactionUTF32Node.create()); + } + return tsFromByteArrayWithCompactionNode; + } + + protected TruffleString.CodePointLengthNode ensureTsCodePointLengthNode() { + if (tsCodePointLengthNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsCodePointLengthNode = insert(TruffleString.CodePointLengthNode.create()); + } + return tsCodePointLengthNode; + } + + protected TruffleString.CodePointAtIndexUTF32Node ensureTsCodePointAtIndexUTF32Node() { + if (tsCodePointAtIndexUTF32Node == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsCodePointAtIndexUTF32Node = insert(TruffleString.CodePointAtIndexUTF32Node.create()); + } + return tsCodePointAtIndexUTF32Node; + } + + protected TruffleString.FromLongNode ensureTsFromLongNode() { + if (tsFromLongNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsFromLongNode = insert(TruffleString.FromLongNode.create()); + } + return tsFromLongNode; + } + + protected TruffleString.IndexOfStringNode ensureTsIndexOfStringNode() { + if (tsIndexOfStringNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsIndexOfStringNode = insert(TruffleString.IndexOfStringNode.create()); + } + return tsIndexOfStringNode; + } + + protected TruffleString.SubstringNode ensureTsSubstringNode() { + if (tsSubstringNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsSubstringNode = insert(TruffleString.SubstringNode.create()); + } + return tsSubstringNode; + } + + protected TruffleString.EqualNode ensureTsEqualNode() { + if (tsEqualNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsEqualNode = insert(TruffleString.EqualNode.create()); + } + return tsEqualNode; + } + + protected TruffleString.CopyToByteArrayNode ensureTsCopyToByteArrayNode() { + if (tsCopyToByteArrayNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsCopyToByteArrayNode = insert(TruffleString.CopyToByteArrayNode.create()); + } + return tsCopyToByteArrayNode; + } + + protected TruffleString.GetCodeRangeNode ensureTsGetCodeRangeNode() { + if (tsGetCodeRangeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsGetCodeRangeNode = insert(TruffleString.GetCodeRangeNode.create()); + } + return tsGetCodeRangeNode; + } + + protected TruffleString.SwitchEncodingNode ensureTsSwitchEncodingNode() { + if (tsSwitchEncodingNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsSwitchEncodingNode = insert(TruffleString.SwitchEncodingNode.create()); + } + return tsSwitchEncodingNode; + } + + protected HashingStorageIterator getHashingStorageIterator(HashingStorage storage) { + if (getHashingStorageIteratorNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getHashingStorageIteratorNode = insert(HashingStorageGetIterator.create()); + } + return getHashingStorageIteratorNode.executeCached(storage); + } + + protected HashingStorageIteratorNext ensureHashingStorageIteratorNext() { + if (hashingStorageItNext == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + hashingStorageItNext = insert(HashingStorageIteratorNext.create()); + } + return hashingStorageItNext; + } + + protected HashingStorageIteratorKey ensureHashingStorageIteratorKey() { + if (hashingStorageItKey == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + hashingStorageItKey = insert(HashingStorageIteratorKey.create()); + } + return hashingStorageItKey; + } + + protected HashingStorageIteratorValue ensureHashingStorageIteratorValue() { + if (hashingStorageItValue == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + hashingStorageItValue = insert(HashingStorageIteratorValue.create()); + } + return hashingStorageItValue; + } + + protected int length(VirtualFrame frame, Object object) { + if (sizeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + sizeNode = insert(PyObjectSizeNode.create()); + } + return sizeNode.executeCached(frame, object); + } + + protected boolean isIterator(Object iter) { + if (isIteratorObjectNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + isIteratorObjectNode = insert(PyIterCheckNode.create()); + } + return isIteratorObjectNode.executeCached(iter); + } + + protected CallNode ensureCallNode() { + if (callNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + callNode = insert(CallNode.create()); + } + return callNode; + } + + protected Object callStarArgsAndKwArgs(VirtualFrame frame, Object method, Object args, Object kwargs) { + if (getArgsNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getArgsNode = insert(ExecutePositionalStarargsNode.create()); + } + PKeyword[] keywords; + if (kwargs == null) { + keywords = PKeyword.EMPTY_KEYWORDS; + } else { + if (getKwArgsNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getKwArgsNode = insert(ExpandKeywordStarargsNodeGen.create()); + } + keywords = getKwArgsNode.executeCached(kwargs); + } + return ensureCallNode().execute(frame, method, getArgsNode.executeWith(frame, args), keywords); + } + + protected PyObjectLookupAttr getLookupAttrNode() { + if (lookupAttrNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + lookupAttrNode = insert(PyObjectLookupAttr.create()); + } + return lookupAttrNode; + } + + protected Object lookupAttribute(Frame frame, Object receiver, TruffleString name) { + return getLookupAttrNode().executeCached(frame, receiver, name); + } + + protected Object lookupAttributeStrict(Frame frame, Object receiver, TruffleString name) { + Object attr = lookupAttribute(frame, receiver, name); + if (attr == NO_VALUE) { + throw raise(TypeError, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, attr, name); + } + return attr; + } + + protected Object getClass(Object object) { + if (getClassNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getClassNode = insert(GetClassNode.create()); + } + return getClassNode.executeCached(object); + } + + protected Object getClass(Frame frame, Object object) { + Object cls = getLookupAttrNode().executeCached(frame, object, T___CLASS__); + return cls == NO_VALUE ? getClass(object) : cls; + } + + protected HiddenAttr.ReadNode ensureReadHiddenAttrNode() { + if (readHiddenAttributeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + readHiddenAttributeNode = insert(HiddenAttr.ReadNode.create()); + } + return readHiddenAttributeNode; + } + + public PickleState getGlobalState(Python3Core core) { + Object state = ensureReadHiddenAttrNode().executeCached(core.lookupType(PythonBuiltinClassType.Pickler), HiddenAttr.PICKLE_STATE, NO_VALUE); + assert state instanceof PickleState; + return (PickleState) state; + } + + protected Object getDictItem(VirtualFrame frame, PDict dict, Object key) { + if (getHashingStorageItemNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getHashingStorageItemNode = insert(CachedHashingStorageGetItem.create()); + } + return getHashingStorageItemNode.execute(frame, dict.getDictStorage(), key); + } + + protected IsBuiltinObjectProfile ensureErrProfile() { + if (errProfile == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + errProfile = insert(IsBuiltinObjectProfile.create()); + } + return errProfile; + } + + protected boolean isBuiltinClass(Object cls, PythonBuiltinClassType type) { + if (isBuiltinClassProfile == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + isBuiltinClassProfile = insert(InlineIsBuiltinClassProfile.create()); + } + return isBuiltinClassProfile.profileClassCached(cls, type); + } + + public Object getNextItem(VirtualFrame frame, Object iterator) { + return getNextNode.executeCached(frame, iterator); + } + + public Object getItem(SequenceStorage storage, int index) { + if (getSeqStorageItemNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getSeqStorageItemNode = insert(SequenceStorageNodes.GetItemScalarNode.create()); + } + return getSeqStorageItemNode.executeCached(storage, index); + } + + public Object getItem(VirtualFrame frame, Object obj, Object key) { + return getItemNode.executeCached(frame, obj, key); + } + + public Object getItem(VirtualFrame frame, Object obj, int size, int pos, Object defaultValue) { + return size > pos ? getItemNode.executeCached(frame, obj, pos) : defaultValue; + } + + public TruffleString asString(Object value) { + if (value instanceof TruffleString string) { + return string; + } + try { + return toStringNode.executeCached(value); + } catch (CannotCastException e) { + return null; + } + } + + public TruffleString asStringStrict(Object value) { + if (value instanceof TruffleString string) { + return string; + } + try { + return toStringNode.executeCached(value); + } catch (CannotCastException e) { + throw raise(TypeError, MUST_BE_STR_NOT_P, value); + } + } + + public static Pair getDeepAttribute(VirtualFrame frame, PyObjectLookupAttr lookup, Object obj, TruffleString[] names) { + Object parent = null; + Object object = obj; + for (TruffleString name : names) { + parent = object; + object = lookup.executeCached(frame, parent, name); + if (object == NO_VALUE) { + return null; + } + } + return Pair.create(object, parent); + } + + public TruffleString[] getDottedPath(Object obj, TruffleString name) { + TruffleString[] dottedPath = StringUtils.split(name, T_DOT, ensureTsCodePointLengthNode(), ensureTsIndexOfStringNode(), ensureTsSubstringNode(), ensureTsEqualNode()); + assert dottedPath.length > 0; + for (TruffleString subPath : dottedPath) { + if (ensureTsEqualNode().execute(subPath, T_LOCALS, TS_ENCODING)) { + if (obj == null) { + throw raise(AttributeError, ErrorMessages.CANT_PICKLE_LOCAL_OBJ_S, name); + } else { + throw raise(AttributeError, ErrorMessages.CANT_PICKLE_ATTR_S_OF_P, name, obj); + } + } + } + return dottedPath; + } + + protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { + PickleState state = getGlobalState(core); + return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); + } + + private Pair getMapping(VirtualFrame frame, PDict nameMapping, PDict importMapping, + TruffleString nameMappingLabel, TruffleString importMappingLabel, TruffleString moduleName, TruffleString globalName) { + Object key = PFactory.createTuple(PythonLanguage.get(this), new Object[]{moduleName, globalName}); + Object item = getDictItem(frame, nameMapping, key); + if (item != null) { + if (!(item instanceof PTuple) || length(frame, item) != 2) { + throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P, nameMappingLabel, "2-tuples", item); + } + Object mappedModuleName = getItem(frame, item, 0); + Object mappedGlobalName = getItem(frame, item, 1); + if (!PGuards.isString(mappedModuleName) || !PGuards.isString(mappedGlobalName)) { + throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P_P, nameMappingLabel, "str", mappedModuleName, mappedGlobalName); + } + return Pair.create(asString(mappedModuleName), asString(mappedGlobalName)); + } + item = getDictItem(frame, importMapping, moduleName); + if (item != null) { + if (!PGuards.isString(item)) { + throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P, importMappingLabel, "strings", item); + } + return Pair.create(asString(item), globalName); + } + return Pair.create(moduleName, globalName); + } + + private static boolean checkModule(VirtualFrame frame, PyObjectLookupAttr lookup, Object moduleName, Object module, Object global, TruffleString[] dottedPath) { + if (module == PNone.NONE) { + return false; + } + assert !(moduleName instanceof String) : "moduleName shouldn't be j.l.String"; + if (moduleName instanceof TruffleString && ((TruffleString) moduleName).equalsUncached(T___MAIN__, TS_ENCODING)) { + return false; + } + Pair pair = getDeepAttribute(frame, lookup, module, dottedPath); + return pair != null && pair.getLeft() == global; + } + + public TruffleString whichModule(VirtualFrame frame, PythonContext context, Object global, TruffleString[] dottedPath) { + Object moduleName = lookupAttribute(frame, global, T___MODULE__); + if (moduleName != NO_VALUE && moduleName != PNone.NONE) { + return asStringStrict(moduleName); + } + + PDict sysModules = context.getSysModules(); + if (sysModules == null) { + throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.UNABLE_TO_GET_S, T_SYS_MODULES); + } + + HashingStorage storage = sysModules.getDictStorage(); + HashingStorageIterator it = getHashingStorageIterator(storage); + HashingStorageIteratorNext nextNode = ensureHashingStorageIteratorNext(); + HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); + HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); + while (nextNode.executeCached(storage, it)) { + Object value = getValueNode.executeCached(storage, it); + Object key = getKeyNode.executeCached(storage, it); + if (checkModule(frame, getLookupAttrNode(), moduleName, value, global, dottedPath)) { + return asStringStrict(key); + } + } + return T___MAIN__; + } protected boolean isType(Object obj) { if (isTypeNode == null) { @@ -462,14 +903,6 @@ protected boolean isSubType(Object clsA, Object clsB) { return isSubTypeNode.execute(clsA, clsB); } - protected CallNode getCallNode() { - if (callNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - callNode = insert(CallNode.create()); - } - return callNode; - } - public void opcodeBoundary(VirtualFrame frame, PPickler pickler) { if (!pickler.isFraming() || pickler.frameStart == -1) { return; @@ -646,23 +1079,6 @@ protected static void fastSaveLeave(PPickler pickler, Object obj) { pickler.fastMemoRemove(obj); } } - } - - public abstract static class FlushToFileNode extends BasePickleWriteNode { - public abstract void execute(VirtualFrame frame, PPickler pickler); - - @Specialization - public void flush(VirtualFrame frame, PPickler pickler, - @Bind PythonLanguage language) { - assert pickler.write != null; - // This will commit the frame first - PBytes output = pickler.getString(language); - call(frame, pickler.write, output); - } - } - - public abstract static class SaveNode extends BasePickleWriteNode { - private static final int MAX_RECURSION_DEPTH = 3; private static final int SEEN_NONE = 1 << 0; private static final int SEEN_BOOLEAN = 1 << 1; @@ -1011,9 +1427,9 @@ private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object itera private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object obj) { Object pid; if (pickler.persFuncSelf == null) { - pid = getCallNode().execute(frame, pickler.persFunc, obj); + pid = ensureCallNode().execute(frame, pickler.persFunc, obj); } else { - pid = getCallNode().execute(frame, pickler.persFunc, pickler.persFuncSelf, obj); + pid = ensureCallNode().execute(frame, pickler.persFunc, pickler.persFuncSelf, obj); } if (pid != PNone.NONE) { if (isBin(proto)) { @@ -1466,7 +1882,7 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool if (bypassBuffer && pickler.write != null) { flushToFile(frame, pickler); - getCallNode().execute(frame, pickler.write, obj); + ensureCallNode().execute(frame, pickler.write, obj); pickler.clearBuffer(); } else { writeBuffer(pickler, buffer, size, bufferLib); @@ -1489,7 +1905,7 @@ private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, int proto, byte[] data = new byte[size]; ensureTsCopyToByteArrayNode().execute(utf8, 0, data, 0, size, TruffleString.Encoding.UTF_8); flushToFile(frame, pickler); - getCallNode().execute(frame, pickler.write, PFactory.createBytes(PythonLanguage.get(this), data, size)); + ensureCallNode().execute(frame, pickler.write, PFactory.createBytes(PythonLanguage.get(this), data, size)); pickler.clearBuffer(); } else { if (size <= 0xff && proto >= 4) { @@ -1954,7 +2370,7 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, if (bypassBuffer && pickler.write != null) { flushToFile(frame, pickler); - getCallNode().execute(frame, pickler.write, obj); + ensureCallNode().execute(frame, pickler.write, obj); pickler.clearBuffer(); } else { writeBuffer(pickler, buffer, size, bufferLib); @@ -2002,7 +2418,7 @@ private void savePickleBuffer(VirtualFrame frame, PPickler pickler, int proto, b boolean inBand = true; if (pickler.bufferCallback != null) { - Object ret = getCallNode().execute(frame, pickler.bufferCallback, obj); + Object ret = ensureCallNode().execute(frame, pickler.bufferCallback, obj); inBand = isTrue(frame, ret); } @@ -2355,14 +2771,33 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa } } - public abstract static class DumpNode extends BasePickleWriteNode { + @GenerateInline(false) + public abstract static class FlushToFileNode extends Node { + public abstract void execute(VirtualFrame frame, PPickler pickler); + + @Specialization + public void flush(VirtualFrame frame, PPickler pickler, + @Bind PythonLanguage language, + @Cached CallNode callNode) { + assert pickler.write != null; + // This will commit the frame first + PBytes output = pickler.getString(language); + callNode.execute(frame, pickler.write, output); + } + } + + @GenerateInline(false) + public abstract static class DumpNode extends Node { + private static final TruffleString REDUCE_OVERRIDE = tsLiteral("reducer_override"); + public abstract void execute(VirtualFrame frame, PPickler pickler, Object obj); @Specialization public void dump(VirtualFrame frame, PPickler pickler, Object obj, - @Cached("create(0)") SaveNode saveNode) { + @Cached("create(0)") SaveNode saveNode, + @Cached PyObjectLookupAttr lookupAttrNode) { try { - final Object tmp = getLookupAttrNode().executeCached(frame, pickler, REDUCE_OVERRIDE); + final Object tmp = lookupAttrNode.execute(frame, this, pickler, REDUCE_OVERRIDE); if (tmp != PNone.NO_VALUE) { pickler.reducerOverride = tmp; } else { @@ -2373,9 +2808,9 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, assert pickler.proto <= 256; try { - write(pickler, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); + saveNode.write(pickler, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); } catch (Exception e) { - handleError(pickler); + SaveNode.handleError(pickler); throw e; } @@ -2385,7 +2820,7 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, } saveNode.execute(frame, pickler, obj, 0); - write(pickler, PickleUtils.OPCODE_STOP); + saveNode.write(pickler, PickleUtils.OPCODE_STOP); pickler.commitFrame(); } finally { pickler.framing = false; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 419ec3a8b6..7c94c9425b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -42,13 +42,8 @@ import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_IMPORT_MAPPING; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_NAME_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; -import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; -import static com.oracle.graal.python.nodes.ErrorMessages.MUST_BE_STR_NOT_P; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; -import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MODULE__; import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; @@ -64,7 +59,6 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltins; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltinsFactory; -import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; import com.oracle.graal.python.builtins.objects.common.HashingStorage; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.CachedHashingStorageGetItem; @@ -103,7 +97,6 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; -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.runtime.sequence.storage.SequenceStorage; @@ -118,7 +111,6 @@ public final class PicklerNodes { abstract static class BasePickleNode extends Node { private static final TruffleString T_LOCALS = tsLiteral(""); - static final TruffleString T_SYS_MODULES = tsLiteral("sys.modules"); public static final TruffleString T_CODEC_RAW_UNICODE_ESCAPE = tsLiteral("raw_unicode_escape"); public static final TruffleString T_CODEC_BYTES = tsLiteral("bytes"); public static final TruffleString T_CODEC_ASCII = tsLiteral("ascii"); @@ -155,13 +147,9 @@ abstract static class BasePickleNode extends Node { @Child private TruffleString.FromByteArrayNode tsFromByteArrayNode; @Child private TruffleString.FromByteArrayWithCompactionUTF32Node tsFromByteArrayWithCompactionNode; @Child private TruffleString.CodePointLengthNode tsCodePointLengthNode; - @Child private TruffleString.CodePointAtIndexUTF32Node tsCodePointAtIndexUTF32Node; - @Child private TruffleString.FromLongNode tsFromLongNode; @Child private TruffleString.IndexOfStringNode tsIndexOfStringNode; @Child private TruffleString.SubstringNode tsSubstringNode; @Child private TruffleString.EqualNode tsEqualNode; - @Child private TruffleString.CopyToByteArrayNode tsCopyToByteArrayNode; - @Child private TruffleString.GetCodeRangeNode tsGetCodeRangeNode; @Child private TruffleString.SwitchEncodingNode tsSwitchEncodingNode; @Child private HashingStorageGetIterator getHashingStorageIteratorNode; @Child private HashingStorageIteratorNext hashingStorageItNext; @@ -208,22 +196,6 @@ protected TruffleString.CodePointLengthNode ensureTsCodePointLengthNode() { return tsCodePointLengthNode; } - protected TruffleString.CodePointAtIndexUTF32Node ensureTsCodePointAtIndexUTF32Node() { - if (tsCodePointAtIndexUTF32Node == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsCodePointAtIndexUTF32Node = insert(TruffleString.CodePointAtIndexUTF32Node.create()); - } - return tsCodePointAtIndexUTF32Node; - } - - protected TruffleString.FromLongNode ensureTsFromLongNode() { - if (tsFromLongNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsFromLongNode = insert(TruffleString.FromLongNode.create()); - } - return tsFromLongNode; - } - protected TruffleString.IndexOfStringNode ensureTsIndexOfStringNode() { if (tsIndexOfStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -248,22 +220,6 @@ protected TruffleString.EqualNode ensureTsEqualNode() { return tsEqualNode; } - protected TruffleString.CopyToByteArrayNode ensureTsCopyToByteArrayNode() { - if (tsCopyToByteArrayNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsCopyToByteArrayNode = insert(TruffleString.CopyToByteArrayNode.create()); - } - return tsCopyToByteArrayNode; - } - - protected TruffleString.GetCodeRangeNode ensureTsGetCodeRangeNode() { - if (tsGetCodeRangeNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsGetCodeRangeNode = insert(TruffleString.GetCodeRangeNode.create()); - } - return tsGetCodeRangeNode; - } - protected TruffleString.SwitchEncodingNode ensureTsSwitchEncodingNode() { if (tsSwitchEncodingNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -587,18 +543,6 @@ public TruffleString asString(Object value) { } } - public TruffleString asStringStrict(Object value) { - if (value instanceof TruffleString) { - return (TruffleString) value; - } else { - try { - return toStringNode.executeCached(value); - } catch (CannotCastException e) { - throw raise(PythonBuiltinClassType.TypeError, MUST_BE_STR_NOT_P, value); - } - } - } - public static Pair getDeepAttribute(VirtualFrame frame, PyObjectLookupAttr lookup, Object obj, TruffleString[] names) { Object parent = null; Object object = obj; @@ -644,11 +588,6 @@ public Object getattribute(VirtualFrame frame, Object obj, TruffleString name, b } } - protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { - PickleState state = getGlobalState(core); - return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); - } - protected Pair get2To3Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { PickleState state = getGlobalState(core); return getMapping(frame, state.nameMapping2To3, state.importMapping2To3, T_CP_NAME_MAPPING, T_CP_IMPORT_MAPPING, moduleName, globalName); @@ -702,54 +641,5 @@ public Object findClass(VirtualFrame frame, BoundaryCallData boundaryCallData, P Object module = importModule(frame, boundaryCallData, mName); return getattribute(frame, module, gName, self.getProto() >= 4); } - - private static boolean checkModule(VirtualFrame frame, PyObjectLookupAttr lookup, Object moduleName, Object module, Object global, TruffleString[] dottedPath) { - if (module == PNone.NONE) { - return false; - } - - assert !(moduleName instanceof String) : "moduleName shouldn't be j.l.String"; - - if (moduleName instanceof TruffleString && ((TruffleString) moduleName).equalsUncached(T___MAIN__, TS_ENCODING)) { - return false; - } - final Pair pair = getDeepAttribute(frame, lookup, module, dottedPath); - if (pair == null) { - return false; - } - return pair.getLeft() == global; - } - - public TruffleString whichModule(VirtualFrame frame, PythonContext context, Object global, TruffleString[] dottedPath) { - Object moduleName = lookupAttribute(frame, global, T___MODULE__); - if (moduleName != NO_VALUE) { - // In some rare cases (e.g., bound methods of extension types), __module__ can be - // None. If it is so, then search sys.modules for the module of global - if (moduleName != PNone.NONE) { - return asStringStrict(moduleName); - } - } - - // Fallback on walking sys.modules - final PDict sysModules = context.getSysModules(); - if (sysModules == null) { - throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.UNABLE_TO_GET_S, T_SYS_MODULES); - } - - final HashingStorage storage = sysModules.getDictStorage(); - HashingStorageIterator it = getHashingStorageIterator(storage); - HashingStorageIteratorNext nextNode = ensureHashingStorageIteratorNext(); - HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); - HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); - while (nextNode.executeCached(storage, it)) { - Object value = getValueNode.executeCached(storage, it); - Object key = getKeyNode.executeCached(storage, it); - if (checkModule(frame, getLookupAttrNode(), moduleName, value, global, dottedPath)) { - return asStringStrict(key); - } - } - // If no module is found, use __main__ - return T___MAIN__; - } } } From 37a0e4757dd78448e2958335f5ad7451e9742c23 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 29 Sep 2026 15:21:39 +0200 Subject: [PATCH 080/129] Make pickler write helpers static (cherry picked from commit afc6dd2e34445f7358b71396d6af0514aedaa13a) --- .../builtins/modules/pickle/PPickler.java | 307 +++++++++--------- 1 file changed, 159 insertions(+), 148 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 296cb5cecf..dddf0773fb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -856,11 +856,15 @@ protected boolean isType(Object obj) { } protected void flushToFile(VirtualFrame frame, PPickler pickler) { + ensureFlushToFileNode().execute(frame, pickler); + } + + protected FlushToFileNode ensureFlushToFileNode() { if (flushToFileNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); flushToFileNode = insert(PPicklerFactory.FlushToFileNodeGen.create()); } - flushToFileNode.execute(frame, pickler); + return flushToFileNode; } protected int getSign(Object value) { @@ -926,51 +930,54 @@ public static void handleError(PPickler pickler) { pickler.reducerOverride = null; } - protected void writeASCII(PPickler pickler, TruffleString string) { + protected static void writeASCII(Node node, PPickler pickler, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { assert string.getCodeRangeUncached(TS_ENCODING) == TruffleString.CodeRange.ASCII; - TruffleString encoded = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.US_ASCII); + TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.US_ASCII); int length = encoded.byteLength(TruffleString.Encoding.US_ASCII); - ensureBufferSpace(pickler, length); - ensureTsCopyToByteArrayNode().execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.US_ASCII); + ensureBufferSpace(node, pickler, length); + copyToByteArrayNode.execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.US_ASCII); pickler.outputLen += length; } - protected void writeUtf8(PPickler pickler, TruffleString string) { - TruffleString encoded = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - writeUtf8Converted(pickler, encoded); + protected static void writeUtf8(Node node, PPickler pickler, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + writeUtf8Converted(node, pickler, encoded, copyToByteArrayNode); } - public void writeUtf8Converted(PPickler pickler, TruffleString encoded) { + public static void writeUtf8Converted(Node node, PPickler pickler, TruffleString encoded, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { int length = encoded.byteLength(TruffleString.Encoding.UTF_8); - ensureBufferSpace(pickler, length); - ensureTsCopyToByteArrayNode().execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.UTF_8); + ensureBufferSpace(node, pickler, length); + copyToByteArrayNode.execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.UTF_8); pickler.outputLen += length; } - protected void writeLongAsString(PPickler pickler, byte opcode, long value) { - TruffleString string = ensureTsFromLongNode().execute(value, TruffleString.Encoding.US_ASCII, true); + protected static void writeLongAsString(Node node, PPickler pickler, byte opcode, long value, TruffleString.FromLongNode fromLongNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString string = fromLongNode.execute(value, TruffleString.Encoding.US_ASCII, true); TruffleString.Encoding encoding = TruffleString.Encoding.US_ASCII; int length = string.byteLength(encoding); - ensureBufferSpace(pickler, length + 2); + ensureBufferSpace(node, pickler, length + 2); pickler.outputBuffer[pickler.outputLen++] = opcode; - ensureTsCopyToByteArrayNode().execute(string, 0, pickler.outputBuffer, pickler.outputLen, length, encoding); + copyToByteArrayNode.execute(string, 0, pickler.outputBuffer, pickler.outputLen, length, encoding); pickler.outputLen += length; pickler.outputBuffer[pickler.outputLen++] = NEW_LINE_BYTE; } - protected void write(PPickler pickler, byte b) { - ensureBufferSpace(pickler, 1); + protected static void write(Node node, PPickler pickler, byte b) { + ensureBufferSpace(node, pickler, 1); pickler.outputBuffer[pickler.outputLen++] = b; } - protected void write(PPickler pickler, byte b1, byte b2) { - ensureBufferSpace(pickler, 2); + protected static void write(Node node, PPickler pickler, byte b1, byte b2) { + ensureBufferSpace(node, pickler, 2); pickler.outputBuffer[pickler.outputLen++] = b1; pickler.outputBuffer[pickler.outputLen++] = b2; } - protected void writeBuffer(PPickler pickler, Object buffer, int size, PythonBufferAccessLibrary bufferLib) { - ensureBufferSpace(pickler, size); + protected static void writeBuffer(Node node, PPickler pickler, Object buffer, int size, PythonBufferAccessLibrary bufferLib) { + ensureBufferSpace(node, pickler, size); bufferLib.readIntoByteArray(buffer, 0, pickler.outputBuffer, pickler.outputLen, size); pickler.outputLen += size; } @@ -991,21 +998,21 @@ protected static byte intByte4(long value) { return (byte) ((value >> 24) & 0xff); } - protected void writeByteOp(PPickler pickler, byte opcode, long value) { - ensureBufferSpace(pickler, 2); + protected static void writeByteOp(Node node, PPickler pickler, byte opcode, long value) { + ensureBufferSpace(node, pickler, 2); pickler.outputBuffer[pickler.outputLen++] = opcode; pickler.outputBuffer[pickler.outputLen++] = intByte1(value); } - protected void writeShortOp(PPickler pickler, byte opcode, long value) { - ensureBufferSpace(pickler, 3); + protected static void writeShortOp(Node node, PPickler pickler, byte opcode, long value) { + ensureBufferSpace(node, pickler, 3); pickler.outputBuffer[pickler.outputLen++] = opcode; pickler.outputBuffer[pickler.outputLen++] = intByte1(value); pickler.outputBuffer[pickler.outputLen++] = intByte2(value); } - protected void writeIntOp(PPickler pickler, byte opcode, long value) { - ensureBufferSpace(pickler, 5); + protected static void writeIntOp(Node node, PPickler pickler, byte opcode, long value) { + ensureBufferSpace(node, pickler, 5); pickler.outputBuffer[pickler.outputLen++] = opcode; pickler.outputBuffer[pickler.outputLen++] = intByte1(value); pickler.outputBuffer[pickler.outputLen++] = intByte2(value); @@ -1013,17 +1020,17 @@ protected void writeIntOp(PPickler pickler, byte opcode, long value) { pickler.outputBuffer[pickler.outputLen++] = intByte4(value); } - protected void write(PPickler pickler, byte[] bytes) { - write(pickler, bytes, bytes.length); + protected static void write(Node node, PPickler pickler, byte[] bytes) { + write(node, pickler, bytes, bytes.length); } - protected void write(PPickler pickler, byte[] bytes, int dataLen) { - ensureBufferSpace(pickler, dataLen); + protected static void write(Node node, PPickler pickler, byte[] bytes, int dataLen) { + ensureBufferSpace(node, pickler, dataLen); PythonUtils.arraycopy(bytes, 0, pickler.outputBuffer, pickler.outputLen, dataLen); pickler.outputLen += dataLen; } - public void ensureBufferSpace(PPickler pickler, int dataLen) { + public static void ensureBufferSpace(Node node, PPickler pickler, int dataLen) { boolean needNewFrame = pickler.isFraming() && pickler.frameStart == -1; int n = CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; int required = pickler.outputLen + n; @@ -1032,7 +1039,8 @@ public void ensureBufferSpace(PPickler pickler, int dataLen) { // Make place in buffer for the pickle chunk // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, pickler.outputLen >= Integer.MAX_VALUE / 2 - n)) { - throw raise(PythonBuiltinClassType.MemoryError); + CompilerDirectives.transferToInterpreter(); + throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); } pickler.maxOutputLen = (pickler.outputLen + n) / 2 * 3; pickler.outputBuffer = PythonUtils.arrayCopyOf(pickler.outputBuffer, pickler.maxOutputLen); @@ -1043,7 +1051,7 @@ public void ensureBufferSpace(PPickler pickler, int dataLen) { } } - protected boolean bypassBuffer(PPickler pickler, int dataSize) { + protected static boolean bypassBuffer(PPickler pickler, int dataSize) { boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; if (bypassBuffer) { @@ -1286,7 +1294,7 @@ private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, Has int i; do { i = 0; - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); while (nextNode.executeCached(storage, it)) { save(frame, pickler, getKeyNode.executeCached(storage, it), 0); if (saveValues) { @@ -1296,7 +1304,7 @@ private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, Has break; } } - write(pickler, opcodeBatch); + write(this, pickler, opcodeBatch); if (getHashingStorageLength(storage) != initialSize) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.CHANGED_SIZE_DURING_ITERATION, name); } @@ -1342,12 +1350,12 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O } catch (IteratorExhausted e) { // Only one item to write saveItem.accept(firstItem); - write(pickler, opcodeOneItem); + write(this, pickler, opcodeOneItem); break; } // More than one item to write // Pump out MARK, items, APPENDS. - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); saveItem.accept(firstItem); n = 1; while (true) { @@ -1366,7 +1374,7 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O break; } } - write(pickler, opcodeMultipleItems); + write(this, pickler, opcodeMultipleItems); } while (n == PickleUtils.BATCHSIZE); } @@ -1401,7 +1409,7 @@ private void saveIterator(VirtualFrame frame, PPickler pickler, Object iterator, } itemConsumer.accept(item); if (opcode != PickleUtils.NO_OPCODE) { - write(pickler, opcode); + write(this, pickler, opcode); } } } @@ -1434,16 +1442,16 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object if (pid != PNone.NONE) { if (isBin(proto)) { save(frame, pickler, pid, 1); - write(pickler, PickleUtils.OPCODE_BINPERSID); + write(this, pickler, PickleUtils.OPCODE_BINPERSID); } else { final TruffleString pidStr = asString(convertToStr(frame, pid)); // XXX: Should it check whether the pid contains embedded newlines? if (!PythonUtils.isAscii(pidStr, ensureTsGetCodeRangeNode())) { throw raise(PythonBuiltinClassType.PicklingError, ErrorMessages.PIDS_MUST_BE_ASCII_STRS); } - write(pickler, PickleUtils.OPCODE_PERSID); - writeASCII(pickler, pidStr); - writeASCII(pickler, T_NEWLINE); + write(this, pickler, PickleUtils.OPCODE_PERSID); + writeASCII(this, pickler, pidStr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + writeASCII(this, pickler, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } return true; } @@ -1454,15 +1462,15 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object private void memoGet(PPickler pickler, int proto, int value) { if (isBin(proto)) { if (value < 256) { - writeByteOp(pickler, PickleUtils.OPCODE_BINGET, value); + writeByteOp(this, pickler, PickleUtils.OPCODE_BINGET, value); } else if (Long.compareUnsigned(value, 0xffffffffL) <= 0) { - writeIntOp(pickler, PickleUtils.OPCODE_LONG_BINGET, value); + writeIntOp(this, pickler, PickleUtils.OPCODE_LONG_BINGET, value); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINGET"); } } else { - writeLongAsString(pickler, PickleUtils.OPCODE_GET, value); + writeLongAsString(this, pickler, PickleUtils.OPCODE_GET, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } } @@ -1476,15 +1484,15 @@ private void memoPut(PPickler pickler, int proto, boolean fastMode, Object obj) pickler.memo.set(obj, idx); if (proto >= 4) { - write(pickler, PickleUtils.OPCODE_MEMOIZE); + write(this, pickler, PickleUtils.OPCODE_MEMOIZE); } else { if (!isBin(proto)) { - writeLongAsString(pickler, PickleUtils.OPCODE_PUT, idx); + writeLongAsString(this, pickler, PickleUtils.OPCODE_PUT, idx, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } else { if (idx < 256) { - writeByteOp(pickler, PickleUtils.OPCODE_BINPUT, idx); + writeByteOp(this, pickler, PickleUtils.OPCODE_BINPUT, idx); } else if (Long.compareUnsigned(idx, 0xffffffffL) <= 0) { - writeIntOp(pickler, PickleUtils.OPCODE_LONG_BINPUT, idx); + writeIntOp(this, pickler, PickleUtils.OPCODE_LONG_BINPUT, idx); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINPUT"); @@ -1601,7 +1609,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, save(frame, pickler, cls, 0); save(frame, pickler, args, 0); save(frame, pickler, kwargs, 0); - write(pickler, PickleUtils.OPCODE_NEWOBJ_EX); + write(this, pickler, PickleUtils.OPCODE_NEWOBJ_EX); } else { PickleState st = getGlobalState(ctx.getCore()); final int argsSize = length(frame, args); @@ -1620,7 +1628,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, save(frame, pickler, callable, 0); save(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this)), 0); - write(pickler, PickleUtils.OPCODE_REDUCE); + write(this, pickler, PickleUtils.OPCODE_REDUCE); } } else if (useNewobj) { Object cls; @@ -1677,12 +1685,12 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, save(frame, pickler, cls, 0); newargtup = getItem(frame, argtup, PFactory.createIntSlice(PythonLanguage.get(this), 1, argtupSize, 1)); save(frame, pickler, newargtup, 0); - write(pickler, PickleUtils.OPCODE_NEWOBJ); + write(this, pickler, PickleUtils.OPCODE_NEWOBJ); } else { // Not using NEWOBJ save(frame, pickler, callable, 0); save(frame, pickler, argtup, 0); - write(pickler, PickleUtils.OPCODE_REDUCE); + write(this, pickler, PickleUtils.OPCODE_REDUCE); } // obj can be NULL when save_reduce() is used directly. A NULL obj means the caller do @@ -1694,7 +1702,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // memo int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - write(pickler, PickleUtils.OPCODE_POP); + write(this, pickler, PickleUtils.OPCODE_POP); memoGet(pickler, proto, memoIndex); } else { memoPut(pickler, proto, fastMode, obj); @@ -1712,7 +1720,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, if (state != null) { if (stateSetter == null) { save(frame, pickler, state, 0); - write(pickler, PickleUtils.OPCODE_BUILD); + write(this, pickler, PickleUtils.OPCODE_BUILD); } else { // If a state_setter is specified, call it instead of load_build to update obj's // with its previous state. The first 4 save/write instructions push @@ -1724,40 +1732,40 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, save(frame, pickler, stateSetter, 0); save(frame, pickler, obj, 0); save(frame, pickler, state, 0); - write(pickler, PickleUtils.OPCODE_TUPLE2); - write(pickler, PickleUtils.OPCODE_REDUCE); - write(pickler, PickleUtils.OPCODE_POP); + write(this, pickler, PickleUtils.OPCODE_TUPLE2); + write(this, pickler, PickleUtils.OPCODE_REDUCE); + write(this, pickler, PickleUtils.OPCODE_POP); } } } private void saveNone(PPickler pickler) { - write(pickler, PickleUtils.OPCODE_NONE); + write(this, pickler, PickleUtils.OPCODE_NONE); } private void saveBool(PPickler pickler, int proto, boolean value) { if (proto >= 2) { - write(pickler, value ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); + write(this, pickler, value ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); } else { // These aren't opcodes -- they're ways to pickle bools before protocol 2 so that // unpicklers written before bools were introduced unpickle them as ints, but // unpicklers after can recognize that bools were intended. Note that protocol 2 // added direct ways to pickle bools. - writeASCII(pickler, value ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE); + writeASCII(this, pickler, value ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } private void saveLong(PPickler pickler, int proto, int value) { if (isBin(proto)) { if (value >= 0 && value < (1 << 8)) { - writeByteOp(pickler, PickleUtils.OPCODE_BININT1, value); + writeByteOp(this, pickler, PickleUtils.OPCODE_BININT1, value); } else if (value >= 0 && value < (1 << 16)) { - writeShortOp(pickler, PickleUtils.OPCODE_BININT2, value); + writeShortOp(this, pickler, PickleUtils.OPCODE_BININT2, value); } else { - writeIntOp(pickler, PickleUtils.OPCODE_BININT, value); + writeIntOp(this, pickler, PickleUtils.OPCODE_BININT, value); } } else { - writeLongAsString(pickler, PickleUtils.OPCODE_INT, value); + writeLongAsString(this, pickler, PickleUtils.OPCODE_INT, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } } @@ -1805,32 +1813,32 @@ private void saveLongLarge(VirtualFrame frame, PPickler pickler, int proto, Obje nbytes--; } if (nbytes < 256) { - writeByteOp(pickler, PickleUtils.OPCODE_LONG1, nbytes); + writeByteOp(this, pickler, PickleUtils.OPCODE_LONG1, nbytes); } else { - writeIntOp(pickler, PickleUtils.OPCODE_LONG4, nbytes); + writeIntOp(this, pickler, PickleUtils.OPCODE_LONG4, nbytes); } - write(pickler, pdata, nbytes); + write(this, pickler, pdata, nbytes); } else { TruffleString repr = repr(frame, obj); - write(pickler, PickleUtils.OPCODE_LONG); - writeASCII(pickler, asStringStrict(repr)); - writeASCII(pickler, T_L_NEW_LINE); + write(this, pickler, PickleUtils.OPCODE_LONG); + writeASCII(this, pickler, asStringStrict(repr), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + writeASCII(this, pickler, T_L_NEW_LINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } private void saveFloat(PPickler pickler, int proto, double value) { if (isBin(proto)) { - write(pickler, PickleUtils.OPCODE_BINFLOAT); - ensureBufferSpace(pickler, 8); + write(this, pickler, PickleUtils.OPCODE_BINFLOAT); + ensureBufferSpace(this, pickler, 8); NumericSupport.bigEndian().putDouble(pickler.outputBuffer, pickler.outputLen, value); pickler.outputLen += 8; } else { - write(pickler, PickleUtils.OPCODE_FLOAT); + write(this, pickler, PickleUtils.OPCODE_FLOAT); TruffleString repr = PickleUtils.doubleToAsciiString(value); - writeASCII(pickler, repr); - writeASCII(pickler, T_NEWLINE); + writeASCII(this, pickler, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + writeASCII(this, pickler, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } @@ -1875,9 +1883,9 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool boolean bypassBuffer = bypassBuffer(pickler, size); if (size <= 0xff) { - writeByteOp(pickler, PickleUtils.OPCODE_SHORT_BINBYTES, size); + writeByteOp(this, pickler, PickleUtils.OPCODE_SHORT_BINBYTES, size); } else { - writeIntOp(pickler, PickleUtils.OPCODE_BINBYTES, size); + writeIntOp(this, pickler, PickleUtils.OPCODE_BINBYTES, size); } if (bypassBuffer && pickler.write != null) { @@ -1885,7 +1893,7 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool ensureCallNode().execute(frame, pickler.write, obj); pickler.clearBuffer(); } else { - writeBuffer(pickler, buffer, size, bufferLib); + writeBuffer(this, pickler, buffer, size, bufferLib); } if (bypassBuffer && wasFraming) { @@ -1894,26 +1902,28 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool memoPut(pickler, proto, fastMode, obj); } - private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, int proto, TruffleString string) { - TruffleString utf8 = ensureTsSwitchEncodingNode().execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + private static void writeUnicodeBinary(Node node, VirtualFrame frame, PPickler pickler, int proto, TruffleString string, + TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode, + FlushToFileNode flushToFileNode, CallNode callNode) { + TruffleString utf8 = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); int size = utf8.byteLength(TruffleString.Encoding.UTF_8); boolean wasFraming = pickler.framing; boolean bypassBuffer = bypassBuffer(pickler, size); if (bypassBuffer && pickler.write != null) { - writeIntOp(pickler, PickleUtils.OPCODE_BINUNICODE, size); + writeIntOp(node, pickler, PickleUtils.OPCODE_BINUNICODE, size); byte[] data = new byte[size]; - ensureTsCopyToByteArrayNode().execute(utf8, 0, data, 0, size, TruffleString.Encoding.UTF_8); - flushToFile(frame, pickler); - ensureCallNode().execute(frame, pickler.write, PFactory.createBytes(PythonLanguage.get(this), data, size)); + copyToByteArrayNode.execute(utf8, 0, data, 0, size, TruffleString.Encoding.UTF_8); + flushToFileNode.execute(frame, pickler); + callNode.execute(frame, pickler.write, PFactory.createBytes(PythonLanguage.get(node), data, size)); pickler.clearBuffer(); } else { if (size <= 0xff && proto >= 4) { - writeByteOp(pickler, PickleUtils.OPCODE_SHORT_BINUNICODE, size); + writeByteOp(node, pickler, PickleUtils.OPCODE_SHORT_BINUNICODE, size); } else { - writeIntOp(pickler, PickleUtils.OPCODE_BINUNICODE, size); + writeIntOp(node, pickler, PickleUtils.OPCODE_BINUNICODE, size); } - writeUtf8Converted(pickler, utf8); + writeUtf8Converted(node, pickler, utf8, copyToByteArrayNode); } if (bypassBuffer && wasFraming) { @@ -1931,28 +1941,29 @@ private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolea private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, TruffleString string) { if (isBin(proto)) { - writeUnicodeBinary(frame, pickler, proto, string); + writeUnicodeBinary(this, frame, pickler, proto, string, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode(), ensureFlushToFileNode(), ensureCallNode()); } else { - write(pickler, PickleUtils.OPCODE_UNICODE); - writeRawUnicodeEscape(pickler, string); - writeASCII(pickler, T_NEWLINE); + write(this, pickler, PickleUtils.OPCODE_UNICODE); + writeRawUnicodeEscape(this, pickler, string, ensureTsCodePointLengthNode(), ensureTsCodePointAtIndexUTF32Node()); + writeASCII(this, pickler, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } memoPut(pickler, proto, fastMode, obj); } - private void writeRawUnicodeEscape(PPickler pickler, TruffleString string) { - int codePointLength = ensureTsCodePointLengthNode().execute(string, TS_ENCODING); + private static void writeRawUnicodeEscape(Node node, PPickler pickler, TruffleString string, + TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexUTF32Node codePointAtIndexNode) { + int codePointLength = codePointLengthNode.execute(string, TS_ENCODING); long escapedLength = 0; for (int i = 0; i < codePointLength; i++) { - int ch = ensureTsCodePointAtIndexUTF32Node().execute(string, i); + int ch = codePointAtIndexNode.execute(string, i); escapedLength += ch >= 0x10000 ? 10 : ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a ? 6 : 1; } if (escapedLength > Integer.MAX_VALUE) { - throw raise(PythonBuiltinClassType.MemoryError); + throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); } - ensureBufferSpace(pickler, (int) escapedLength); + ensureBufferSpace(node, pickler, (int) escapedLength); for (int i = 0; i < codePointLength; i++) { - int ch = ensureTsCodePointAtIndexUTF32Node().execute(string, i); + int ch = codePointAtIndexNode.execute(string, i); if (ch >= 0x10000) { pickler.outputBuffer[pickler.outputLen++] = '\\'; pickler.outputBuffer[pickler.outputLen++] = 'U'; @@ -1984,7 +1995,7 @@ private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); save(frame, pickler, getKeyNode.executeCached(storage, it), 0); save(frame, pickler, getValueNode.executeCached(storage, it), 0); - write(pickler, PickleUtils.OPCODE_SETITEM); + write(this, pickler, PickleUtils.OPCODE_SETITEM); } else { // Write in batches of BATCHSIZE. saveDictHashingStorageBatched(frame, pickler, storage); @@ -2009,9 +2020,9 @@ private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMetho // Create an empty dict. if (isBin(proto)) { - write(pickler, PickleUtils.OPCODE_EMPTY_DICT); + write(this, pickler, PickleUtils.OPCODE_EMPTY_DICT); } else { - write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_DICT); + write(this, pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_DICT); } memoPut(pickler, proto, fastMode, obj); @@ -2043,7 +2054,7 @@ private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, in return; } - write(pickler, PickleUtils.OPCODE_EMPTY_SET); + write(this, pickler, PickleUtils.OPCODE_EMPTY_SET); memoPut(pickler, proto, fastMode, obj); final int setSize = length(frame, obj); @@ -2068,7 +2079,7 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl return; } - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); saveSetHashingStorage(frame, pickler, obj.getDictStorage()); @@ -2076,12 +2087,12 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl // away everything we put on the stack, and fetch the object back from the memo. int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - write(pickler, PickleUtils.OPCODE_POP_MARK); + write(this, pickler, PickleUtils.OPCODE_POP_MARK); memoGet(pickler, proto, memoIndex); return; } - write(pickler, PickleUtils.OPCODE_FROZENSET); + write(this, pickler, PickleUtils.OPCODE_FROZENSET); memoPut(pickler, proto, fastMode, obj); } @@ -2107,7 +2118,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { if (storage.length() == 1) { item = getItem(storage, 0); save(frame, pickler, item, 0); - write(pickler, PickleUtils.OPCODE_APPEND); + write(this, pickler, PickleUtils.OPCODE_APPEND); return; } @@ -2116,7 +2127,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { int thisBatch; do { thisBatch = 0; - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); while (total < storage.length()) { item = getItem(storage, total); save(frame, pickler, item, 0); @@ -2125,7 +2136,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { break; } } - write(pickler, PickleUtils.OPCODE_APPENDS); + write(this, pickler, PickleUtils.OPCODE_APPENDS); } while (total < storage.length()); } @@ -2134,19 +2145,19 @@ private void batchIntList(VirtualFrame frame, PPickler pickler, IntSequenceStora if (storage.length() == 1) { opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getIntItemNormalized(0)); - write(pickler, PickleUtils.OPCODE_APPEND); + write(this, pickler, PickleUtils.OPCODE_APPEND); return; } int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getIntItemNormalized(i)); } - write(pickler, PickleUtils.OPCODE_APPENDS); + write(this, pickler, PickleUtils.OPCODE_APPENDS); } } @@ -2155,19 +2166,19 @@ private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceSto if (storage.length() == 1) { opcodeBoundary(frame, pickler); saveLong(frame, pickler, proto, storage.getLongItemNormalized(0)); - write(pickler, PickleUtils.OPCODE_APPEND); + write(this, pickler, PickleUtils.OPCODE_APPEND); return; } int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { opcodeBoundary(frame, pickler); saveLong(frame, pickler, proto, storage.getLongItemNormalized(i)); } - write(pickler, PickleUtils.OPCODE_APPENDS); + write(this, pickler, PickleUtils.OPCODE_APPENDS); } } @@ -2176,19 +2187,19 @@ private void batchDoubleList(VirtualFrame frame, PPickler pickler, DoubleSequenc if (storage.length() == 1) { opcodeBoundary(frame, pickler); saveFloat(pickler, proto, storage.getDoubleItemNormalized(0)); - write(pickler, PickleUtils.OPCODE_APPEND); + write(this, pickler, PickleUtils.OPCODE_APPEND); return; } int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { opcodeBoundary(frame, pickler); saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); } - write(pickler, PickleUtils.OPCODE_APPENDS); + write(this, pickler, PickleUtils.OPCODE_APPENDS); } } @@ -2210,9 +2221,9 @@ private void saveList(VirtualFrame frame, PPickler pickler, int proto, boolean f // Create an empty list. if (isBin(proto)) { - write(pickler, PickleUtils.OPCODE_EMPTY_LIST); + write(this, pickler, PickleUtils.OPCODE_EMPTY_LIST); } else { - write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); + write(this, pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); } int len = obj.getSequenceStorage().length(); @@ -2298,9 +2309,9 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean if (len == 0) { if (proto != 0) { - write(pickler, PickleUtils.OPCODE_EMPTY_TUPLE); + write(this, pickler, PickleUtils.OPCODE_EMPTY_TUPLE); } else { - write(pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_TUPLE); + write(this, pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_TUPLE); } return; } @@ -2316,14 +2327,14 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean if (memoIndex != -1) { // pop the len elements for (int i = 0; i < len; i++) { - write(pickler, PickleUtils.OPCODE_POP); + write(this, pickler, PickleUtils.OPCODE_POP); } // fetch from memo memoGet(pickler, proto, memoIndex); return; } else { // Not recursive. - write(pickler, TUPLE_LEN_2_OPCODE[len]); + write(this, pickler, TUPLE_LEN_2_OPCODE[len]); } memoPut(pickler, proto, fastMode, obj); @@ -2331,18 +2342,18 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean } // proto < 2 and len > 0, or proto >= 2 and len > 3. Generate MARK e1 e2 ... TUPLE - write(pickler, PickleUtils.OPCODE_MARK); + write(this, pickler, PickleUtils.OPCODE_MARK); storeTupleElements(frame, pickler, obj, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { // pop the stack stuff we pushed if (isBin(proto)) { - write(pickler, PickleUtils.OPCODE_POP_MARK); + write(this, pickler, PickleUtils.OPCODE_POP_MARK); } else { // Note that we pop one more than len, to remove the MARK too. for (int i = 0; i <= len; i++) { - write(pickler, PickleUtils.OPCODE_POP); + write(this, pickler, PickleUtils.OPCODE_POP); } } // fetch from memo @@ -2350,7 +2361,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean return; } else { // Not recursive. - write(pickler, PickleUtils.OPCODE_TUPLE); + write(this, pickler, PickleUtils.OPCODE_TUPLE); } memoPut(pickler, proto, fastMode, obj); @@ -2364,8 +2375,8 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, boolean bypassBuffer = bypassBuffer(pickler, size); // Our sizes are ints, but the protocol expects 8 bytes - ensureBufferSpace(pickler, 9); - writeIntOp(pickler, PickleUtils.OPCODE_BYTEARRAY8, size); + ensureBufferSpace(this, pickler, 9); + writeIntOp(this, pickler, PickleUtils.OPCODE_BYTEARRAY8, size); pickler.outputLen += 4; if (bypassBuffer && pickler.write != null) { @@ -2373,7 +2384,7 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, ensureCallNode().execute(frame, pickler.write, obj); pickler.clearBuffer(); } else { - writeBuffer(pickler, buffer, size, bufferLib); + writeBuffer(this, pickler, buffer, size, bufferLib); } if (bypassBuffer && wasFraming) { @@ -2432,9 +2443,9 @@ private void savePickleBuffer(VirtualFrame frame, PPickler pickler, int proto, b } } else { // Write data out-of-band - write(pickler, PickleUtils.OPCODE_NEXT_BUFFER); + write(this, pickler, PickleUtils.OPCODE_NEXT_BUFFER); if (readOnly) { - write(pickler, PickleUtils.OPCODE_READONLY_BUFFER); + write(this, pickler, PickleUtils.OPCODE_READONLY_BUFFER); } } } @@ -2514,11 +2525,11 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, // Generate an EXT opcode if (code <= 0xff) { - writeByteOp(pickler, PickleUtils.OPCODE_EXT1, code); + writeByteOp(this, pickler, PickleUtils.OPCODE_EXT1, code); } else if (code <= 0xffff) { - writeShortOp(pickler, PickleUtils.OPCODE_EXT2, code); + writeShortOp(this, pickler, PickleUtils.OPCODE_EXT2, code); } else { - writeIntOp(pickler, PickleUtils.OPCODE_EXT4, code); + writeIntOp(this, pickler, PickleUtils.OPCODE_EXT4, code); } } } else { @@ -2535,14 +2546,14 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, if (proto >= 4) { save(frame, pickler, moduleName, 0); save(frame, pickler, globalName, 0); - write(pickler, PickleUtils.OPCODE_STACK_GLOBAL); + write(this, pickler, PickleUtils.OPCODE_STACK_GLOBAL); } else if (parent != module) { Object reduceValue = createTuple(st.getattr, createTuple(parent, lastname)); saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, null); } else { // Generate a normal global opcode if we are using a pickle protocol < 4, or if // the object is not registered in the extension registry - write(pickler, PickleUtils.OPCODE_GLOBAL); + write(this, pickler, PickleUtils.OPCODE_GLOBAL); // For protocol < 3 and if the user didn't request against doing so, we convert // module names to the old 2.x module names. if (proto < 3 && pickler.fixImports) { @@ -2560,19 +2571,19 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, TS_ENCODING) == TruffleString.CodeRange.BROKEN) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); } - writeUtf8(pickler, moduleName); - write(pickler, (byte) '\n'); - writeUtf8(pickler, globalName); + writeUtf8(this, pickler, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + write(this, pickler, (byte) '\n'); + writeUtf8(this, pickler, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } else { if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) != TruffleString.CodeRange.ASCII || ensureTsGetCodeRangeNode().execute(globalName, TS_ENCODING) != TruffleString.CodeRange.ASCII) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); } - writeASCII(pickler, moduleName); - write(pickler, (byte) '\n'); - writeASCII(pickler, globalName); + writeASCII(this, pickler, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + write(this, pickler, (byte) '\n'); + writeASCII(this, pickler, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } - write(pickler, (byte) '\n'); + write(this, pickler, (byte) '\n'); } // Memoize the object memoPut(pickler, proto, fastMode, obj); @@ -2808,7 +2819,7 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, assert pickler.proto <= 256; try { - saveNode.write(pickler, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); + SaveNode.write(this, pickler, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); } catch (Exception e) { SaveNode.handleError(pickler); throw e; @@ -2820,7 +2831,7 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, } saveNode.execute(frame, pickler, obj, 0); - saveNode.write(pickler, PickleUtils.OPCODE_STOP); + SaveNode.write(this, pickler, PickleUtils.OPCODE_STOP); pickler.commitFrame(); } finally { pickler.framing = false; From 9d17c9555b0451af79f1badaa08c1e4502480c6e Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 30 Sep 2026 11:57:04 +0200 Subject: [PATCH 081/129] Avoid graph size explosion (cherry picked from commit a9f6108fd17d02cd2e5d90b46d027dda3e1dd074) --- .../builtins/modules/pickle/PPickler.java | 109 +++++++++++++----- 1 file changed, 82 insertions(+), 27 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index dddf0773fb..2b7adb2f3d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -1120,11 +1120,19 @@ protected static void fastSaveLeave(PPickler pickler, Object obj) { private static final int SEEN_REGISTERED_REDUCER = 1 << 29; private static final int SEEN_REDUCE_EX = 1 << 30; private static final int SEEN_REDUCE = 1 << 31; + private static final long SEEN_NEWOBJ_EX = 1L << 32; + private static final long SEEN_NEWOBJ = 1L << 33; + private static final long SEEN_PLAIN_REDUCE = 1L << 34; + private static final long SEEN_REDUCE_LISTITEMS = 1L << 35; + private static final long SEEN_REDUCE_DICTITEMS = 1L << 36; + private static final long SEEN_REDUCE_STATE = 1L << 37; - @CompilationFinal private int seenTypes; + @CompilationFinal private long seenTypes; private final int depth; - @Child private SaveNode recursiveSaveNode; + @Child private SaveNode recursiveSaveNode1; + @Child private SaveNode recursiveSaveNode2; + @Child private SaveNode recursiveSaveNode3; @Child private BoundaryCallData boundaryCallData; @Child private PyLongAsLongNode pyLongAsLongNode; @Child private PyObjectStrAsObjectNode pyObjectStrAsObjectNode; @@ -1142,7 +1150,7 @@ protected SaveNode(int depth) { this.depth = depth; } - private void profileSeen(int seen) { + private void profileSeen(long seen) { if ((seenTypes & seen) == 0) { CompilerDirectives.transferToInterpreterAndInvalidate(); seenTypes |= seen; @@ -1175,31 +1183,72 @@ private boolean isTuple(Object object) { private void save(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { if (depth < 0) { - // This should never be reached for compilation, but native-image can't prove it + saveDepthExceeded(pickler, obj, persSave); + return; + } + if (recursiveSaveNode1 == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - execute(frame, pickler, obj, persSave); + recursiveSaveNode1 = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + } + if (depth < MAX_RECURSION_DEPTH) { + recursiveSaveNode1.execute(frame, pickler, obj, persSave); + } else { + saveSetupBoundary(frame, recursiveSaveNode1, pickler, obj, persSave); + } + } + + private void save2(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, persSave); return; } - if (recursiveSaveNode == null) { + if (recursiveSaveNode2 == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveSaveNode = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + recursiveSaveNode2 = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); } if (depth < MAX_RECURSION_DEPTH) { - recursiveSaveNode.execute(frame, pickler, obj, persSave); + recursiveSaveNode2.execute(frame, pickler, obj, persSave); } else { - BoundaryCallData callData = getBoundaryCallData(); - Object savedState = BoundaryCallContext.enter(frame, callData); - try { - saveBoundary(pickler, obj, persSave); - } finally { - BoundaryCallContext.exit(frame, callData, savedState); - } + saveSetupBoundary(frame, recursiveSaveNode2, pickler, obj, persSave); + } + } + + private void save3(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, persSave); + return; + } + if (recursiveSaveNode3 == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + recursiveSaveNode3 = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + } + if (depth < MAX_RECURSION_DEPTH) { + recursiveSaveNode3.execute(frame, pickler, obj, persSave); + } else { + saveSetupBoundary(frame, recursiveSaveNode3, pickler, obj, persSave); } } + // This should never be reached for compilation, but native-image can't prove it at build time @TruffleBoundary - private void saveBoundary(PPickler pickler, Object obj, int persSave) { - recursiveSaveNode.execute(null, pickler, obj, persSave); + private void saveDepthExceeded(PPickler pickler, Object obj, int persSave) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + execute(null, pickler, obj, persSave); + } + + private void saveSetupBoundary(VirtualFrame frame, SaveNode saveNode, PPickler pickler, Object obj, int persSave) { + BoundaryCallData callData = getBoundaryCallData(); + Object savedState = BoundaryCallContext.enter(frame, callData); + try { + saveBoundary(saveNode, pickler, obj, persSave); + } finally { + BoundaryCallContext.exit(frame, callData, savedState); + } + } + + @TruffleBoundary + private void saveBoundary(SaveNode saveNode, PPickler pickler, Object obj, int persSave) { + saveNode.execute(null, pickler, obj, persSave); } private long asLong(VirtualFrame frame, Object object) { @@ -1298,7 +1347,7 @@ private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, Has while (nextNode.executeCached(storage, it)) { save(frame, pickler, getKeyNode.executeCached(storage, it), 0); if (saveValues) { - save(frame, pickler, getValueNode.executeCached(storage, it), 0); + save2(frame, pickler, getValueNode.executeCached(storage, it), 0); } if (++i == PickleUtils.BATCHSIZE) { break; @@ -1388,7 +1437,7 @@ private void saveDictIteratorBatchUnrolled(VirtualFrame frame, PPickler pickler, }, (Object item) -> { save(frame, pickler, getItem(frame, item, 0), 0); - save(frame, pickler, getItem(frame, item, 1), 0); + save2(frame, pickler, getItem(frame, item, 1), 0); }); } @@ -1426,7 +1475,7 @@ private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object itera throw raise(TypeError, ErrorMessages.MUST_S_ITER_RETURN_2TUPLE, DICT_ITEMS); } save(frame, pickler, getItem(frame, item, 0), 0); - save(frame, pickler, getItem(frame, item, 1), 0); + save2(frame, pickler, getItem(frame, item, 1), 0); }); } @@ -1582,6 +1631,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, final int argtupSize = length(frame, argtup); if (useNewobjEx) { + profileSeen(SEEN_NEWOBJ_EX); Object cls; Object args; Object kwargs; @@ -1607,8 +1657,8 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, if (proto >= 4) { save(frame, pickler, cls, 0); - save(frame, pickler, args, 0); - save(frame, pickler, kwargs, 0); + save2(frame, pickler, args, 0); + save3(frame, pickler, kwargs, 0); write(this, pickler, PickleUtils.OPCODE_NEWOBJ_EX); } else { PickleState st = getGlobalState(ctx.getCore()); @@ -1627,10 +1677,11 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, callable = callStarArgsAndKwArgs(frame, st.partial, newargs, kwargs); save(frame, pickler, callable, 0); - save(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this)), 0); + save2(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this)), 0); write(this, pickler, PickleUtils.OPCODE_REDUCE); } } else if (useNewobj) { + profileSeen(SEEN_NEWOBJ); Object cls; Object newargtup; Object objClass; @@ -1684,12 +1735,13 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // Save the class and its __new__ arguments save(frame, pickler, cls, 0); newargtup = getItem(frame, argtup, PFactory.createIntSlice(PythonLanguage.get(this), 1, argtupSize, 1)); - save(frame, pickler, newargtup, 0); + save2(frame, pickler, newargtup, 0); write(this, pickler, PickleUtils.OPCODE_NEWOBJ); } else { + profileSeen(SEEN_PLAIN_REDUCE); // Not using NEWOBJ save(frame, pickler, callable, 0); - save(frame, pickler, argtup, 0); + save2(frame, pickler, argtup, 0); write(this, pickler, PickleUtils.OPCODE_REDUCE); } @@ -1710,14 +1762,17 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, } if (listitems != null) { + profileSeen(SEEN_REDUCE_LISTITEMS); batchList(frame, pickler, proto, listitems); } if (dictitems != null) { + profileSeen(SEEN_REDUCE_DICTITEMS); batchDict(frame, pickler, proto, dictitems); } if (state != null) { + profileSeen(SEEN_REDUCE_STATE); if (stateSetter == null) { save(frame, pickler, state, 0); write(this, pickler, PickleUtils.OPCODE_BUILD); @@ -1730,8 +1785,8 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // whole operation has to be stack-transparent. Thus, we finally pop the call's // output from the stack. save(frame, pickler, stateSetter, 0); - save(frame, pickler, obj, 0); - save(frame, pickler, state, 0); + save2(frame, pickler, obj, 0); + save3(frame, pickler, state, 0); write(this, pickler, PickleUtils.OPCODE_TUPLE2); write(this, pickler, PickleUtils.OPCODE_REDUCE); write(this, pickler, PickleUtils.OPCODE_POP); From 32ef8ad77f12c4ba064d83c92ea75b37ba240781 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 30 Sep 2026 14:43:31 +0200 Subject: [PATCH 082/129] Get rid of MemoIterator (cherry picked from commit ad3897172fb43f45cac42da551e287be21bb3106) --- .../builtins/modules/pickle/MemoTable.java | 62 +++++++------------ .../pickle/PicklerMemoProxyBuiltins.java | 14 ++--- 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java index 4393f54f42..37e813fd87 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -54,39 +54,6 @@ public final class MemoTable { private static final int OCCUPANCY_EXPONENT = 1; // 2^X relation between capacity and size private static final int CAPACITY_INC_EXPONENT = 2; // 2^X increase in capacity when resizing - public static final class MemoIterator { - - private int index; - private final Object[] keys; - private final int[] values; - - public MemoIterator(MemoTable table) { - this.keys = table.keys; - this.values = table.values; - this.index = -1; - } - - public boolean advance() { - while (true) { - index++; - if (index >= keys.length) { - return false; - } - if (keys[index] != null) { - return true; - } - } - } - - public Object key() { - return keys[index]; - } - - public int value() { - return values[index]; - } - } - private Object[] keys; private int[] values; private int mask; @@ -176,11 +143,20 @@ private void resize() { throw PRaiseNode.raiseStatic(null, PicklingError, ErrorMessages.STRUCT_SIZE_TOO_LONG); } - MemoIterator iterator = iterator(); // captures the current contents + Object[] oldKeys = keys; + int[] oldValues = values; initArrays(newLength); - while (iterator.advance()) { - setInternal(iterator.key(), iterator.value()); + for (int i = 0; i < oldKeys.length; i++) { + Object key = oldKeys[i]; + if (key != null) { + int index = getIndex(key); + while (keys[index] != null) { + index = (index + 1) & mask; + } + keys[index] = key; + values[index] = oldValues[i]; + } } } @@ -192,7 +168,15 @@ public void set(Object key, int value) { } } - public MemoIterator iterator() { - return new MemoIterator(this); + int capacity() { + return keys.length; + } + + Object getKeyAt(int index) { + return keys[index]; + } + + int getValueAt(int index) { + return values[index]; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java index 9b5ad2622f..5d8ea60e57 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -53,7 +53,6 @@ import com.oracle.graal.python.builtins.CoreFunctions; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; -import com.oracle.graal.python.builtins.modules.pickle.MemoTable.MemoIterator; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.tuple.PTuple; @@ -106,11 +105,12 @@ Object clear(PPicklerMemoProxy self) { public static PDict picklerMemoCopyImpl(MemoTable memoTable) { PythonLanguage language = PythonLanguage.get(null); LinkedHashMap copy = new LinkedHashMap<>(); - MemoIterator iterator = memoTable.iterator(); - while (iterator.advance()) { - copy.put(System.identityHashCode(iterator.key()), - PFactory.createTuple(language, new Object[]{iterator.value(), iterator.key()})); - + for (int i = 0; i < memoTable.capacity(); i++) { + Object key = memoTable.getKeyAt(i); + if (key != null) { + copy.put(System.identityHashCode(key), + PFactory.createTuple(language, new Object[]{memoTable.getValueAt(i), key})); + } } return PFactory.createDictFromMapGeneric(language, copy); } From 596410ebb96173bfbd89f2051dd49d7b9c2097bf Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 30 Sep 2026 14:49:50 +0200 Subject: [PATCH 083/129] Profile buffer bypass (cherry picked from commit d867056e40ca3896ecf4fc1befcff2ad840cf3ff) --- .../graal/python/builtins/modules/pickle/PPickler.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 2b7adb2f3d..0e6062be4e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -912,7 +912,7 @@ public void opcodeBoundary(VirtualFrame frame, PPickler pickler) { return; } int frameLen = pickler.outputLen - pickler.frameStart - PickleUtils.FRAME_HEADER_SIZE; - if (frameLen >= PickleUtils.FRAME_SIZE_TARGET) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, frameLen >= PickleUtils.FRAME_SIZE_TARGET)) { pickler.commitFrame(); // Flush the content of the committed frame to the underlying // file and reuse the pickler buffer for the next frame so as @@ -1051,10 +1051,11 @@ public static void ensureBufferSpace(Node node, PPickler pickler, int dataLen) { } } - protected static boolean bypassBuffer(PPickler pickler, int dataSize) { + protected boolean bypassBuffer(PPickler pickler, int dataSize) { boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; if (bypassBuffer) { + profileSeen(SEEN_BYPASS_BUFFER); assert pickler.outputBuffer != null; // Commit the previous frame. pickler.commitFrame(); @@ -1126,6 +1127,7 @@ protected static void fastSaveLeave(PPickler pickler, Object obj) { private static final long SEEN_REDUCE_LISTITEMS = 1L << 35; private static final long SEEN_REDUCE_DICTITEMS = 1L << 36; private static final long SEEN_REDUCE_STATE = 1L << 37; + private static final long SEEN_BYPASS_BUFFER = 1L << 38; @CompilationFinal private long seenTypes; @@ -1957,7 +1959,7 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool memoPut(pickler, proto, fastMode, obj); } - private static void writeUnicodeBinary(Node node, VirtualFrame frame, PPickler pickler, int proto, TruffleString string, + private void writeUnicodeBinary(Node node, VirtualFrame frame, PPickler pickler, int proto, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode, FlushToFileNode flushToFileNode, CallNode callNode) { TruffleString utf8 = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); From 957cee7ea2f24f2c45421d78343f36fa12fdc835 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 30 Sep 2026 15:33:36 +0200 Subject: [PATCH 084/129] Keep size estimates for buffer and memo table (cherry picked from commit c31f65db5409cb65be8265f2f4b32b16b0aa61af) --- .../builtins/modules/pickle/MemoTable.java | 14 +++- .../builtins/modules/pickle/PPickler.java | 12 ++- .../modules/pickle/PickleModuleBuiltins.java | 74 +++++++++++++++++-- .../graal/python/runtime/object/PFactory.java | 4 +- 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java index 37e813fd87..182d4cdd95 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java @@ -42,6 +42,8 @@ import static com.oracle.graal.python.runtime.exception.PythonErrorType.PicklingError; +import java.util.Arrays; + import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.util.PythonUtils; @@ -50,7 +52,7 @@ public final class MemoTable { - private static final int INITIAL_CAPACITY = 8; + static final int INITIAL_CAPACITY = 8; private static final int OCCUPANCY_EXPONENT = 1; // 2^X relation between capacity and size private static final int CAPACITY_INC_EXPONENT = 2; // 2^X increase in capacity when resizing @@ -60,7 +62,12 @@ public final class MemoTable { private int size; public MemoTable() { - initArrays(INITIAL_CAPACITY); + this(INITIAL_CAPACITY); + } + + public MemoTable(int initialCapacity) { + assert initialCapacity >= INITIAL_CAPACITY && Integer.bitCount(initialCapacity) == 1; + initArrays(initialCapacity); } private MemoTable(MemoTable map) { @@ -79,7 +86,8 @@ public int size() { } public void clear() { - initArrays(INITIAL_CAPACITY); + Arrays.fill(keys, null); + Arrays.fill(values, 0); this.size = 0; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 0e6062be4e..f8ea57e6d9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -212,6 +212,10 @@ public class PPickler extends PythonBuiltinObject { private Object bufferCallback; public PPickler(Object cls, Shape instanceShape) { + this(cls, instanceShape, PickleUtils.WRITE_BUF_SIZE, MemoTable.INITIAL_CAPACITY); + } + + public PPickler(Object cls, Shape instanceShape, int outputCapacity, int memoCapacity) { super(cls, instanceShape); persFunc = null; dispatchTable = null; @@ -224,11 +228,11 @@ public PPickler(Object cls, Shape instanceShape) { fast = 0; fastNesting = 0; fixImports = false; - maxOutputLen = PickleUtils.WRITE_BUF_SIZE; + maxOutputLen = outputCapacity; outputLen = 0; reducerOverride = null; - memo = new MemoTable(); + memo = new MemoTable(memoCapacity); outputBuffer = new byte[maxOutputLen]; } @@ -285,6 +289,10 @@ public MemoTable getMemo() { return memo; } + public int getMaxOutputLen() { + return maxOutputLen; + } + public void setMemo(MemoTable memo) { this.memo = memo; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java index 9b8518028a..6cc08bb72c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -63,6 +63,8 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; 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.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateNodeFactory; @@ -80,6 +82,59 @@ protected List> getNodeFa return PickleModuleBuiltinsFactory.getFactories(); } + /** Learns the capacities reached by successful calls at one builtin node. */ + private static final class PicklerSizeProfile { + private static final int SHIFT = 3; + + @CompilationFinal private long outputEstimate = (long) PickleUtils.WRITE_BUF_SIZE << SHIFT; + @CompilationFinal private long memoEstimate = (long) MemoTable.INITIAL_CAPACITY << SHIFT; + + int outputCapacity() { + return (int) (outputEstimate >> SHIFT); + } + + int memoCapacity() { + int estimate = (int) (memoEstimate >> SHIFT); + return estimate <= MemoTable.INITIAL_CAPACITY ? MemoTable.INITIAL_CAPACITY : Integer.highestOneBit(estimate - 1) << 1; + } + + void report(PPickler pickler) { + if (CompilerDirectives.inInterpreter()) { + if (pickler.getMaxOutputLen() > outputCapacity()) { + outputEstimate = update(outputEstimate, pickler.getMaxOutputLen()); + } + int memoCapacity = pickler.getMemo().capacity(); + if (memoCapacity > (memoEstimate >> SHIFT)) { + memoEstimate = update(memoEstimate, memoCapacity); + } + } + } + + private static long update(long shiftedEstimate, int capacity) { + long estimate = shiftedEstimate >> SHIFT; + return shiftedEstimate + capacity - estimate; + } + } + + abstract static class ProfiledPickleDumpNode extends PythonClinicBuiltinNode { + @CompilationFinal private PicklerSizeProfile sizes = new PicklerSizeProfile(); + + final PPickler createPickler(PythonLanguage language) { + return PFactory.createPickler(language, sizes.outputCapacity(), sizes.memoCapacity()); + } + + final void reportSizes(PPickler pickler) { + sizes.report(pickler); + } + + @Override + public Node copy() { + ProfiledPickleDumpNode copy = (ProfiledPickleDumpNode) super.copy(); + copy.sizes = new PicklerSizeProfile(); + return copy; + } + } + @Override public void postInitialize(Python3Core core) { super.postInitialize(core); @@ -95,26 +150,27 @@ public void postInitialize(Python3Core core) { @ArgumentClinic(name = "protocol", conversion = ArgumentClinic.ClinicConversion.Int, defaultValue = J_DEFAULT_PICKLE_PROTOCOL, useDefaultForNone = true) @ArgumentClinic(name = "fix_imports", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "true") @GenerateNodeFactory - abstract static class PickleDumpNode extends PythonClinicBuiltinNode { + abstract static class PickleDumpNode extends ProfiledPickleDumpNode { @Override protected ArgumentClinicProvider getArgumentClinic() { return PickleModuleBuiltinsClinicProviders.PickleDumpNodeClinicProviderGen.INSTANCE; } @Specialization - static Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, Object file, int protocol, boolean fixImports, Object bufferCallback, + Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, Object file, int protocol, boolean fixImports, Object bufferCallback, @Bind Node inliningTarget, @Bind PythonLanguage language, @Cached PPickler.DumpNode dumpNode, @Cached PPickler.FlushToFileNode flushToFileNode, @Cached PyObjectLookupAttr lookup, @Cached PRaiseNode raiseNode) { - PPickler pickler = PFactory.createPickler(language); + PPickler pickler = createPickler(language); pickler.setProtocol(inliningTarget, raiseNode, protocol, fixImports); pickler.setOutputStream(frame, inliningTarget, raiseNode, lookup, file); pickler.setBufferCallback(inliningTarget, raiseNode, bufferCallback); dumpNode.execute(frame, pickler, obj); flushToFileNode.execute(frame, pickler); + reportSizes(pickler); return PNone.NONE; } } @@ -125,23 +181,25 @@ static Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule @ArgumentClinic(name = "protocol", conversion = ArgumentClinic.ClinicConversion.Int, defaultValue = J_DEFAULT_PICKLE_PROTOCOL, useDefaultForNone = true) @ArgumentClinic(name = "fix_imports", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "true") @GenerateNodeFactory - abstract static class PickleDumpsNode extends PythonClinicBuiltinNode { + abstract static class PickleDumpsNode extends ProfiledPickleDumpNode { @Override protected ArgumentClinicProvider getArgumentClinic() { return PickleModuleBuiltinsClinicProviders.PickleDumpsNodeClinicProviderGen.INSTANCE; } @Specialization - static Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, int protocol, boolean fixImports, Object bufferCallback, + Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, int protocol, boolean fixImports, Object bufferCallback, @Bind Node inliningTarget, @Bind PythonLanguage language, @Cached PPickler.DumpNode dumpNode, @Cached PRaiseNode raiseNode) { - PPickler pickler = PFactory.createPickler(language); + PPickler pickler = createPickler(language); pickler.setProtocol(inliningTarget, raiseNode, protocol, fixImports); pickler.setBufferCallback(inliningTarget, raiseNode, bufferCallback); dumpNode.execute(frame, pickler, obj); - return pickler.getString(language); + Object result = pickler.getString(language); + reportSizes(pickler); + return result; } } 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 35e58a8b29..989b5a5c52 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 @@ -1579,8 +1579,8 @@ public static PPickleBuffer createPickleBuffer(Object view, Object cls, Shape sh return new PPickleBuffer(cls, shape, view); } - public static PPickler createPickler(PythonLanguage language) { - return createPickler(PythonBuiltinClassType.Pickler, PythonBuiltinClassType.Pickler.getInstanceShape(language)); + public static PPickler createPickler(PythonLanguage language, int outputCapacity, int memoCapacity) { + return new PPickler(PythonBuiltinClassType.Pickler, PythonBuiltinClassType.Pickler.getInstanceShape(language), outputCapacity, memoCapacity); } public static PPickler createPickler(Object cls, Shape shape) { From 2eda69f7285b3dab92c56e22daa816e828f4e290 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 30 Sep 2026 16:40:23 +0200 Subject: [PATCH 085/129] Use more specific nodes when working with collections (cherry picked from commit bc0e552e5d6c07052e44a09a3667940cee661c69) --- .../builtins/modules/pickle/PPickler.java | 157 +++++++++--------- 1 file changed, 83 insertions(+), 74 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index f8ea57e6d9..5fc03d2831 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -133,8 +133,8 @@ import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNodeGen; import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode; import com.oracle.graal.python.nodes.builtins.ListNodes; +import com.oracle.graal.python.nodes.builtins.TupleNodes.GetTupleStorage; import com.oracle.graal.python.nodes.call.CallNode; -import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.GetClassNode; @@ -426,6 +426,18 @@ public PBytes getString(PythonLanguage language) { } // inner nodes + @GenerateInline(false) + public abstract static class TupleStorageNode extends Node { + public abstract SequenceStorage execute(Object tuple); + + @Specialization + static SequenceStorage get(Object tuple, + @Bind Node inliningTarget, + @Cached GetTupleStorage getTupleStorage) { + return getTupleStorage.execute(inliningTarget, tuple); + } + } + public abstract static class SaveNode extends Node { private static final int MAX_RECURSION_DEPTH = 3; private static final TruffleString T_LOCALS = tsLiteral(""); @@ -443,7 +455,6 @@ public abstract static class SaveNode extends Node { @Child private IntNodes.PyLongNumBits pyLongNumBits; @Child private IntNodes.PyLongAsByteArray pyLongAsByteArray; @Child private ListNodes.ConstructListNode constructListNode; - @Child private IsSubtypeNode isSubTypeNode; @Child private TypeNodes.IsTypeNode isTypeNode; @Child private FlushToFileNode flushToFileNode; @Child private CallNode callNode; @@ -455,6 +466,7 @@ public abstract static class SaveNode extends Node { @Child private InlineIsBuiltinClassProfile isBuiltinClassProfile; @Child private CachedHashingStorageGetItem getHashingStorageItemNode; @Child private SequenceStorageNodes.GetItemScalarNode getSeqStorageItemNode; + @Child private TupleStorageNode getTupleStorageNode; @Child private PyObjectSizeNode sizeNode; @Child private PyIterCheckNode isIteratorObjectNode; @Child private GetClassNode getClassNode; @@ -729,12 +741,16 @@ public Object getItem(SequenceStorage storage, int index) { return getSeqStorageItemNode.executeCached(storage, index); } - public Object getItem(VirtualFrame frame, Object obj, Object key) { - return getItemNode.executeCached(frame, obj, key); + protected SequenceStorage getTupleStorage(Object tuple) { + if (getTupleStorageNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getTupleStorageNode = insert(PPicklerFactory.TupleStorageNodeGen.create()); + } + return getTupleStorageNode.execute(tuple); } - public Object getItem(VirtualFrame frame, Object obj, int size, int pos, Object defaultValue) { - return size > pos ? getItemNode.executeCached(frame, obj, pos) : defaultValue; + public Object getItem(VirtualFrame frame, Object obj, Object key) { + return getItemNode.executeCached(frame, obj, key); } public TruffleString asString(Object value) { @@ -797,11 +813,12 @@ private Pair getMapping(VirtualFrame frame, PDict Object key = PFactory.createTuple(PythonLanguage.get(this), new Object[]{moduleName, globalName}); Object item = getDictItem(frame, nameMapping, key); if (item != null) { - if (!(item instanceof PTuple) || length(frame, item) != 2) { + if (!(item instanceof PTuple) || ((PTuple) item).getSequenceStorage().length() != 2) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P, nameMappingLabel, "2-tuples", item); } - Object mappedModuleName = getItem(frame, item, 0); - Object mappedGlobalName = getItem(frame, item, 1); + SequenceStorage storage = ((PTuple) item).getSequenceStorage(); + Object mappedModuleName = getItem(storage, 0); + Object mappedGlobalName = getItem(storage, 1); if (!PGuards.isString(mappedModuleName) || !PGuards.isString(mappedGlobalName)) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P_P, nameMappingLabel, "str", mappedModuleName, mappedGlobalName); } @@ -907,14 +924,6 @@ protected Object createList(VirtualFrame frame, Object iterable) { return constructListNode.execute(frame, iterable); } - protected boolean isSubType(Object clsA, Object clsB) { - if (isSubTypeNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - isSubTypeNode = insert(IsSubtypeNode.create()); - } - return isSubTypeNode.execute(clsA, clsB); - } - public void opcodeBoundary(VirtualFrame frame, PPickler pickler) { if (!pickler.isFraming() || pickler.frameStart == -1) { return; @@ -1441,13 +1450,14 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O private void saveDictIteratorBatchUnrolled(VirtualFrame frame, PPickler pickler, Object iterator) { saveIteratorBatchedUnrolled(frame, pickler, iterator, PickleUtils.OPCODE_SETITEM, PickleUtils.OPCODE_SETITEMS, (Object item) -> { - if (!isTuple(item) || length(frame, item) != 2) { + if (!isTuple(item) || getTupleStorage(item).length() != 2) { throw raise(TypeError, ErrorMessages.MUST_S_ITER_RETURN_2TUPLE, DICT_ITEMS); } }, (Object item) -> { - save(frame, pickler, getItem(frame, item, 0), 0); - save2(frame, pickler, getItem(frame, item, 1), 0); + SequenceStorage storage = getTupleStorage(item); + save(frame, pickler, getItem(storage, 0), 0); + save2(frame, pickler, getItem(storage, 1), 0); }); } @@ -1481,11 +1491,12 @@ private void saveListIterator(VirtualFrame frame, PPickler pickler, Object itera private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object iterator) { saveIterator(frame, pickler, iterator, PickleUtils.OPCODE_SETITEM, (Object item) -> { - if (!isTuple(item) || length(frame, item) != 2) { + if (!isTuple(item) || getTupleStorage(item).length() != 2) { throw raise(TypeError, ErrorMessages.MUST_S_ITER_RETURN_2TUPLE, DICT_ITEMS); } - save(frame, pickler, getItem(frame, item, 0), 0); - save2(frame, pickler, getItem(frame, item, 1), 0); + SequenceStorage storage = getTupleStorage(item); + save(frame, pickler, getItem(storage, 0), 0); + save2(frame, pickler, getItem(storage, 1), 0); }); } @@ -1583,17 +1594,18 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, if (!isTuple(arguments)) { throw raise(PythonBuiltinClassType.SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC); } - int size = length(frame, arguments); + SequenceStorage argumentsStorage = getTupleStorage(arguments); + int size = argumentsStorage.length(); if (size < 2 || size > 6) { throw raise(PicklingError, ErrorMessages.TUPLE_RET_BY_REDUCE_2_6); } - Object callable = getItem(frame, arguments, 0); - Object argtup = getItem(frame, arguments, 1); - Object state = getItem(frame, arguments, size, 2, null); - Object listitems = getItem(frame, arguments, size, 3, PNone.NONE); - Object dictitems = getItem(frame, arguments, size, 4, PNone.NONE); - Object stateSetter = getItem(frame, arguments, size, 5, PNone.NONE); + Object callable = getItem(argumentsStorage, 0); + Object argtup = getItem(argumentsStorage, 1); + Object state = size > 2 ? getItem(argumentsStorage, 2) : null; + Object listitems = size > 3 ? getItem(argumentsStorage, 3) : PNone.NONE; + Object dictitems = size > 4 ? getItem(argumentsStorage, 4) : PNone.NONE; + Object stateSetter = size > 5 ? getItem(argumentsStorage, 5) : PNone.NONE; if (!isCallable(callable)) { throw raise(PicklingError, ErrorMessages.S_ITEM_REDUCE_MUST_BE_S, "first", "callable"); @@ -1638,7 +1650,8 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, } } - final int argtupSize = length(frame, argtup); + final SequenceStorage argtupStorage = getTupleStorage(argtup); + final int argtupSize = argtupStorage.length(); if (useNewobjEx) { profileSeen(SEEN_NEWOBJ_EX); @@ -1650,17 +1663,17 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, throw raise(PicklingError, ErrorMessages.LEN_OF_S_MUST_BE_D_NOT_D, "NEWOBJ_EX", 3, argtupSize); } - cls = getItem(frame, argtup, 0); + cls = getItem(argtupStorage, 0); if (!isType(cls)) { throw raise(PicklingError, ErrorMessages.S_ITEM_FROM_S_MUST_BE_S_NOT_P, "first", "NEWOBJ_EX", "a class", cls); } - args = getItem(frame, argtup, 1); + args = getItem(argtupStorage, 1); if (!isTuple(args)) { throw raise(PicklingError, ErrorMessages.S_ITEM_FROM_S_MUST_BE_S_NOT_P, "second", "NEWOBJ_EX", "a tuple", args); } - kwargs = getItem(frame, argtup, 2); + kwargs = getItem(argtupStorage, 2); if (!(kwargs instanceof PDict)) { throw raise(PicklingError, ErrorMessages.S_ITEM_FROM_S_MUST_BE_S_NOT_P, "third", "NEWOBJ_EX", "a dict", kwargs); } @@ -1672,7 +1685,8 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, write(this, pickler, PickleUtils.OPCODE_NEWOBJ_EX); } else { PickleState st = getGlobalState(ctx.getCore()); - final int argsSize = length(frame, args); + final SequenceStorage argsStorage = getTupleStorage(args); + final int argsSize = argsStorage.length(); Object[] newargs = new Object[argsSize + 2]; Object clsNew; int i; @@ -1681,7 +1695,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, newargs[0] = clsNew; newargs[1] = cls; for (i = 0; i < argsSize; i++) { - Object item = getItem(frame, args, i); + Object item = getItem(argsStorage, i); newargs[i + 2] = item; } callable = callStarArgsAndKwArgs(frame, st.partial, newargs, kwargs); @@ -1702,7 +1716,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, throw raise(PicklingError, ErrorMessages.IS_EMPTY, "__newobj__ arglist"); } - cls = getItem(frame, argtup, 0); + cls = getItem(argtupStorage, 0); if (!isType(cls)) { throw raise(PicklingError, ErrorMessages.ARGS_0_FROM_S_ARGS_S, "__newobj__", "is not a type"); } @@ -1744,7 +1758,11 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // Save the class and its __new__ arguments save(frame, pickler, cls, 0); - newargtup = getItem(frame, argtup, PFactory.createIntSlice(PythonLanguage.get(this), 1, argtupSize, 1)); + Object[] newargs = new Object[argtupSize - 1]; + for (int i = 1; i < argtupSize; i++) { + newargs[i - 1] = getItem(argtupStorage, i); + } + newargtup = createTuple(newargs); save2(frame, pickler, newargtup, 0); write(this, pickler, PickleUtils.OPCODE_NEWOBJ); } else { @@ -2106,10 +2124,6 @@ private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMetho } } - private void batchSetExact(VirtualFrame frame, PPickler pickler, PSet set) { - saveSetHashingStorageBatched(frame, pickler, set.getDictStorage()); - } - private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PSet obj) { Object reduceValue; if (proto < 4) { @@ -2122,14 +2136,14 @@ private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, in write(this, pickler, PickleUtils.OPCODE_EMPTY_SET); memoPut(pickler, proto, fastMode, obj); - final int setSize = length(frame, obj); - if (setSize == 0) { + HashingStorage storage = obj.getDictStorage(); + if (getHashingStorageLength(storage) == 0) { // nothing to do return; } // Write in batches of BATCHSIZE. - batchSetExact(frame, pickler, obj); + saveSetHashingStorageBatched(frame, pickler, storage); } private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PFrozenSet obj) { @@ -2307,34 +2321,28 @@ private void saveList(VirtualFrame frame, PPickler pickler, int proto, boolean f } } - private void storeTupleElements(VirtualFrame frame, PPickler pickler, Object obj, SequenceStorage storage, int len) { + private void storeTupleElements(VirtualFrame frame, PPickler pickler, SequenceStorage storage, int len) { // A helper for save_tuple. Push the len elements in tuple t on the stack - if (storage == null) { - for (int i = 0; i < len; i++) { - save(frame, pickler, getItem(frame, obj, i), 0); - } - } else { - assert storage.length() == len; - if (pickler.persFunc == null) { - if (storage instanceof IntSequenceStorage intStorage) { - profileSeen(SEEN_INT_STORAGE); - storeIntTupleElements(frame, pickler, intStorage); - return; - } else if (storage instanceof LongSequenceStorage longStorage) { - profileSeen(SEEN_LONG_STORAGE); - storeLongTupleElements(frame, pickler, longStorage); - return; - } else if (storage instanceof DoubleSequenceStorage doubleStorage) { - profileSeen(SEEN_DOUBLE_STORAGE); - storeDoubleTupleElements(frame, pickler, doubleStorage); - return; - } - } - profileSeen(SEEN_GENERIC_STORAGE); - for (int i = 0; i < len; i++) { - save(frame, pickler, getItem(storage, i), 0); + assert storage.length() == len; + if (pickler.persFunc == null) { + if (storage instanceof IntSequenceStorage intStorage) { + profileSeen(SEEN_INT_STORAGE); + storeIntTupleElements(frame, pickler, intStorage); + return; + } else if (storage instanceof LongSequenceStorage longStorage) { + profileSeen(SEEN_LONG_STORAGE); + storeLongTupleElements(frame, pickler, longStorage); + return; + } else if (storage instanceof DoubleSequenceStorage doubleStorage) { + profileSeen(SEEN_DOUBLE_STORAGE); + storeDoubleTupleElements(frame, pickler, doubleStorage); + return; } } + profileSeen(SEEN_GENERIC_STORAGE); + for (int i = 0; i < len; i++) { + save(frame, pickler, getItem(storage, i), 0); + } } private void storeIntTupleElements(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { @@ -2367,7 +2375,8 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean } private void saveNativeTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj) { - saveTuple(frame, pickler, proto, fastMode, obj, null, length(frame, obj)); + SequenceStorage storage = getTupleStorage(obj); + saveTuple(frame, pickler, proto, fastMode, obj, storage, storage.length()); } private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, SequenceStorage storage, int len) { @@ -2386,7 +2395,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean // the stack, and fetch its value from the memo. if (len <= 3 && proto >= 2) { // Use TUPLE{1,2,3} opcodes. - storeTupleElements(frame, pickler, obj, storage, len); + storeTupleElements(frame, pickler, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { @@ -2408,7 +2417,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean // proto < 2 and len > 0, or proto >= 2 and len > 3. Generate MARK e1 e2 ... TUPLE write(this, pickler, PickleUtils.OPCODE_MARK); - storeTupleElements(frame, pickler, obj, storage, len); + storeTupleElements(frame, pickler, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { @@ -2815,7 +2824,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa if (reduceFunc != null) { profileSeen(SEEN_REGISTERED_REDUCER); reduceValue = callNode.execute(frame, reduceFunc, obj); - } else if (isSubType(type, PythonBuiltinClassType.PythonClass)) { + } else if (isType(obj)) { profileSeen(SEEN_TYPE); saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; From 0b408ae29213fee2f0c4a5d69ba9ff1454c4b642 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 30 Sep 2026 16:41:39 +0200 Subject: [PATCH 086/129] Fix emitting OPCODE_BYTEARRAY8 (cherry picked from commit 2d7de94d69c66165998ce7fd7c68eb2212436637) --- .../graal/python/builtins/modules/pickle/PPickler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 5fc03d2831..12c54f5b4f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -2450,8 +2450,9 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, // Our sizes are ints, but the protocol expects 8 bytes ensureBufferSpace(this, pickler, 9); - writeIntOp(this, pickler, PickleUtils.OPCODE_BYTEARRAY8, size); - pickler.outputLen += 4; + pickler.outputBuffer[pickler.outputLen++] = PickleUtils.OPCODE_BYTEARRAY8; + PickleUtils.writeSize64(pickler.outputBuffer, pickler.outputLen, size); + pickler.outputLen += 8; if (bypassBuffer && pickler.write != null) { flushToFile(frame, pickler); From d589fd6fc32ce84e2224615dce84a226edb7c2c6 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 10:22:41 +0200 Subject: [PATCH 087/129] Reintroduce BasePickleNode again (cherry picked from commit 2600c46f2b1b4ed734c27f25f52605771b9b418a) --- .../builtins/modules/pickle/PPickler.java | 366 +----------------- .../builtins/modules/pickle/PicklerNodes.java | 14 +- 2 files changed, 19 insertions(+), 361 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 12c54f5b4f..80329180c5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -40,12 +40,9 @@ */ package com.oracle.graal.python.builtins.modules.pickle; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; import static com.oracle.graal.python.nodes.ErrorMessages.MUST_BE_STR_NOT_P; -import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MODULE__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NAME__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NEWOBJ_EX__; @@ -55,10 +52,8 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE__; -import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.nodes.StringLiterals.T_NEWLINE; import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; -import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.PicklingError; @@ -74,7 +69,6 @@ import org.graalvm.collections.Pair; import com.oracle.graal.python.PythonLanguage; -import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PNotImplemented; @@ -85,19 +79,15 @@ import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass; import com.oracle.graal.python.builtins.objects.common.HashingStorage; -import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.CachedHashingStorageGetItem; -import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetIterator; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIterator; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorKey; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorNext; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorValue; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageLen; -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.ellipsis.PEllipsis; import com.oracle.graal.python.builtins.objects.floats.PFloat; 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.ints.IntNodes; import com.oracle.graal.python.builtins.objects.ints.IntNodesFactory; import com.oracle.graal.python.builtins.objects.ints.PInt; @@ -106,41 +96,27 @@ import com.oracle.graal.python.builtins.objects.set.PFrozenSet; import com.oracle.graal.python.builtins.objects.set.PSet; import com.oracle.graal.python.builtins.objects.str.PString; -import com.oracle.graal.python.builtins.objects.str.StringUtils; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.builtins.objects.type.PythonManagedClass; import com.oracle.graal.python.builtins.objects.type.TypeNodes; import com.oracle.graal.python.lib.IteratorExhausted; import com.oracle.graal.python.lib.PyCallableCheckNode; -import com.oracle.graal.python.lib.PyIterCheckNode; -import com.oracle.graal.python.lib.PyIterNextNode; import com.oracle.graal.python.lib.PyLongAsLongNode; import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; -import com.oracle.graal.python.lib.PyObjectGetItem; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectIsTrueNode; import com.oracle.graal.python.lib.PyObjectLookupAttr; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; -import com.oracle.graal.python.lib.PyObjectSizeNode; import com.oracle.graal.python.lib.PyObjectStrAsObjectNode; import com.oracle.graal.python.lib.PyTupleCheckNode; import com.oracle.graal.python.nodes.ErrorMessages; -import com.oracle.graal.python.nodes.HiddenAttr; import com.oracle.graal.python.nodes.PGuards; import com.oracle.graal.python.nodes.PRaiseNode; -import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; -import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNodeGen; -import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode; import com.oracle.graal.python.nodes.builtins.ListNodes; import com.oracle.graal.python.nodes.builtins.TupleNodes.GetTupleStorage; import com.oracle.graal.python.nodes.call.CallNode; -import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile; -import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; -import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.IsNode; -import com.oracle.graal.python.nodes.util.CannotCastException; -import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PythonContext; @@ -161,11 +137,9 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.Specialization; -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.object.Shape; -import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedIntValueProfile; import com.oracle.truffle.api.strings.TranscodingErrorHandler; @@ -438,9 +412,8 @@ static SequenceStorage get(Object tuple, } } - public abstract static class SaveNode extends Node { + public abstract static class SaveNode extends PicklerNodes.BasePickleNode { private static final int MAX_RECURSION_DEPTH = 3; - private static final TruffleString T_LOCALS = tsLiteral(""); private static final TruffleString T_SYS_MODULES = tsLiteral("sys.modules"); static final byte[] TUPLE_LEN_2_OPCODE = new byte[]{PickleUtils.OPCODE_EMPTY_TUPLE, PickleUtils.OPCODE_TUPLE1, PickleUtils.OPCODE_TUPLE2, PickleUtils.OPCODE_TUPLE3}; @@ -457,67 +430,18 @@ public abstract static class SaveNode extends Node { @Child private ListNodes.ConstructListNode constructListNode; @Child private TypeNodes.IsTypeNode isTypeNode; @Child private FlushToFileNode flushToFileNode; - @Child private CallNode callNode; - @SuppressWarnings("FieldMayBeFinal") @Child private PyObjectGetItem getItemNode = PyObjectGetItem.create(); - @SuppressWarnings("FieldMayBeFinal") @Child private PyIterNextNode getNextNode = PyIterNextNode.create(); - @Child private CastToTruffleStringNode toStringNode = CastToTruffleStringNode.create(); - @Child private HiddenAttr.ReadNode readHiddenAttributeNode; - @Child private IsBuiltinObjectProfile errProfile; - @Child private InlineIsBuiltinClassProfile isBuiltinClassProfile; - @Child private CachedHashingStorageGetItem getHashingStorageItemNode; - @Child private SequenceStorageNodes.GetItemScalarNode getSeqStorageItemNode; @Child private TupleStorageNode getTupleStorageNode; - @Child private PyObjectSizeNode sizeNode; - @Child private PyIterCheckNode isIteratorObjectNode; - @Child private GetClassNode getClassNode; - @Child private PyObjectLookupAttr lookupAttrNode; - @Child private ExecutePositionalStarargsNode getArgsNode; - @Child private ExpandKeywordStarargsNode getKwArgsNode; - @Child private HashingStorageGetIterator getHashingStorageIteratorNode; - @Child private HashingStorageIteratorNext hashingStorageItNext; - @Child private HashingStorageIteratorKey hashingStorageItKey; - @Child private HashingStorageIteratorValue hashingStorageItValue; - @Child private TruffleString.FromByteArrayWithCompactionUTF32Node tsFromByteArrayWithCompactionNode; - @Child private TruffleString.CodePointLengthNode tsCodePointLengthNode; @Child private TruffleString.CodePointAtIndexUTF32Node tsCodePointAtIndexUTF32Node; @Child private TruffleString.FromLongNode tsFromLongNode; - @Child private TruffleString.IndexOfStringNode tsIndexOfStringNode; - @Child private TruffleString.SubstringNode tsSubstringNode; - @Child private TruffleString.EqualNode tsEqualNode; @Child private TruffleString.CopyToByteArrayNode tsCopyToByteArrayNode; @Child private TruffleString.GetCodeRangeNode tsGetCodeRangeNode; - @Child private TruffleString.SwitchEncodingNode tsSwitchEncodingNode; - private final BranchProfile errorProfile = BranchProfile.create(); - protected PException raise(PythonBuiltinClassType type, TruffleString string) { - errorProfile.enter(); - return PRaiseNode.raiseStatic(this, type, string); - } - - protected PException raise(PythonBuiltinClassType exceptionType) { - errorProfile.enter(); - return PRaiseNode.raiseStatic(this, exceptionType); - } - - protected final PException raise(PythonBuiltinClassType type, TruffleString format, Object... arguments) { - errorProfile.enter(); - return PRaiseNode.raiseStatic(this, type, format, arguments); - } - - protected TruffleString.FromByteArrayWithCompactionUTF32Node ensureTsFromByteArrayWithCompaction() { - if (tsFromByteArrayWithCompactionNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsFromByteArrayWithCompactionNode = insert(TruffleString.FromByteArrayWithCompactionUTF32Node.create()); - } - return tsFromByteArrayWithCompactionNode; - } - - protected TruffleString.CodePointLengthNode ensureTsCodePointLengthNode() { - if (tsCodePointLengthNode == null) { + protected SequenceStorage getTupleStorage(Object tuple) { + if (getTupleStorageNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - tsCodePointLengthNode = insert(TruffleString.CodePointLengthNode.create()); + getTupleStorageNode = insert(PPicklerFactory.TupleStorageNodeGen.create()); } - return tsCodePointLengthNode; + return getTupleStorageNode.execute(tuple); } protected TruffleString.CodePointAtIndexUTF32Node ensureTsCodePointAtIndexUTF32Node() { @@ -536,30 +460,6 @@ protected TruffleString.FromLongNode ensureTsFromLongNode() { return tsFromLongNode; } - protected TruffleString.IndexOfStringNode ensureTsIndexOfStringNode() { - if (tsIndexOfStringNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsIndexOfStringNode = insert(TruffleString.IndexOfStringNode.create()); - } - return tsIndexOfStringNode; - } - - protected TruffleString.SubstringNode ensureTsSubstringNode() { - if (tsSubstringNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsSubstringNode = insert(TruffleString.SubstringNode.create()); - } - return tsSubstringNode; - } - - protected TruffleString.EqualNode ensureTsEqualNode() { - if (tsEqualNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsEqualNode = insert(TruffleString.EqualNode.create()); - } - return tsEqualNode; - } - protected TruffleString.CopyToByteArrayNode ensureTsCopyToByteArrayNode() { if (tsCopyToByteArrayNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -576,262 +476,12 @@ protected TruffleString.GetCodeRangeNode ensureTsGetCodeRangeNode() { return tsGetCodeRangeNode; } - protected TruffleString.SwitchEncodingNode ensureTsSwitchEncodingNode() { - if (tsSwitchEncodingNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsSwitchEncodingNode = insert(TruffleString.SwitchEncodingNode.create()); - } - return tsSwitchEncodingNode; - } - - protected HashingStorageIterator getHashingStorageIterator(HashingStorage storage) { - if (getHashingStorageIteratorNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getHashingStorageIteratorNode = insert(HashingStorageGetIterator.create()); - } - return getHashingStorageIteratorNode.executeCached(storage); - } - - protected HashingStorageIteratorNext ensureHashingStorageIteratorNext() { - if (hashingStorageItNext == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - hashingStorageItNext = insert(HashingStorageIteratorNext.create()); - } - return hashingStorageItNext; - } - - protected HashingStorageIteratorKey ensureHashingStorageIteratorKey() { - if (hashingStorageItKey == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - hashingStorageItKey = insert(HashingStorageIteratorKey.create()); - } - return hashingStorageItKey; - } - - protected HashingStorageIteratorValue ensureHashingStorageIteratorValue() { - if (hashingStorageItValue == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - hashingStorageItValue = insert(HashingStorageIteratorValue.create()); - } - return hashingStorageItValue; - } - - protected int length(VirtualFrame frame, Object object) { - if (sizeNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - sizeNode = insert(PyObjectSizeNode.create()); - } - return sizeNode.executeCached(frame, object); - } - - protected boolean isIterator(Object iter) { - if (isIteratorObjectNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - isIteratorObjectNode = insert(PyIterCheckNode.create()); - } - return isIteratorObjectNode.executeCached(iter); - } - - protected CallNode ensureCallNode() { - if (callNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - callNode = insert(CallNode.create()); - } - return callNode; - } - - protected Object callStarArgsAndKwArgs(VirtualFrame frame, Object method, Object args, Object kwargs) { - if (getArgsNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getArgsNode = insert(ExecutePositionalStarargsNode.create()); - } - PKeyword[] keywords; - if (kwargs == null) { - keywords = PKeyword.EMPTY_KEYWORDS; - } else { - if (getKwArgsNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getKwArgsNode = insert(ExpandKeywordStarargsNodeGen.create()); - } - keywords = getKwArgsNode.executeCached(kwargs); - } - return ensureCallNode().execute(frame, method, getArgsNode.executeWith(frame, args), keywords); - } - - protected PyObjectLookupAttr getLookupAttrNode() { - if (lookupAttrNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - lookupAttrNode = insert(PyObjectLookupAttr.create()); - } - return lookupAttrNode; - } - - protected Object lookupAttribute(Frame frame, Object receiver, TruffleString name) { - return getLookupAttrNode().executeCached(frame, receiver, name); - } - - protected Object lookupAttributeStrict(Frame frame, Object receiver, TruffleString name) { - Object attr = lookupAttribute(frame, receiver, name); - if (attr == NO_VALUE) { - throw raise(TypeError, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, attr, name); - } - return attr; - } - - protected Object getClass(Object object) { - if (getClassNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getClassNode = insert(GetClassNode.create()); - } - return getClassNode.executeCached(object); - } - - protected Object getClass(Frame frame, Object object) { - Object cls = getLookupAttrNode().executeCached(frame, object, T___CLASS__); - return cls == NO_VALUE ? getClass(object) : cls; - } - - protected HiddenAttr.ReadNode ensureReadHiddenAttrNode() { - if (readHiddenAttributeNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - readHiddenAttributeNode = insert(HiddenAttr.ReadNode.create()); - } - return readHiddenAttributeNode; - } - - public PickleState getGlobalState(Python3Core core) { - Object state = ensureReadHiddenAttrNode().executeCached(core.lookupType(PythonBuiltinClassType.Pickler), HiddenAttr.PICKLE_STATE, NO_VALUE); - assert state instanceof PickleState; - return (PickleState) state; - } - - protected Object getDictItem(VirtualFrame frame, PDict dict, Object key) { - if (getHashingStorageItemNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getHashingStorageItemNode = insert(CachedHashingStorageGetItem.create()); - } - return getHashingStorageItemNode.execute(frame, dict.getDictStorage(), key); - } - - protected IsBuiltinObjectProfile ensureErrProfile() { - if (errProfile == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - errProfile = insert(IsBuiltinObjectProfile.create()); - } - return errProfile; - } - - protected boolean isBuiltinClass(Object cls, PythonBuiltinClassType type) { - if (isBuiltinClassProfile == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - isBuiltinClassProfile = insert(InlineIsBuiltinClassProfile.create()); - } - return isBuiltinClassProfile.profileClassCached(cls, type); - } - - public Object getNextItem(VirtualFrame frame, Object iterator) { - return getNextNode.executeCached(frame, iterator); - } - - public Object getItem(SequenceStorage storage, int index) { - if (getSeqStorageItemNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getSeqStorageItemNode = insert(SequenceStorageNodes.GetItemScalarNode.create()); - } - return getSeqStorageItemNode.executeCached(storage, index); - } - - protected SequenceStorage getTupleStorage(Object tuple) { - if (getTupleStorageNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getTupleStorageNode = insert(PPicklerFactory.TupleStorageNodeGen.create()); - } - return getTupleStorageNode.execute(tuple); - } - - public Object getItem(VirtualFrame frame, Object obj, Object key) { - return getItemNode.executeCached(frame, obj, key); - } - - public TruffleString asString(Object value) { - if (value instanceof TruffleString string) { - return string; - } - try { - return toStringNode.executeCached(value); - } catch (CannotCastException e) { - return null; - } - } - public TruffleString asStringStrict(Object value) { - if (value instanceof TruffleString string) { - return string; - } - try { - return toStringNode.executeCached(value); - } catch (CannotCastException e) { + TruffleString string = asString(value); + if (string == null) { throw raise(TypeError, MUST_BE_STR_NOT_P, value); } - } - - public static Pair getDeepAttribute(VirtualFrame frame, PyObjectLookupAttr lookup, Object obj, TruffleString[] names) { - Object parent = null; - Object object = obj; - for (TruffleString name : names) { - parent = object; - object = lookup.executeCached(frame, parent, name); - if (object == NO_VALUE) { - return null; - } - } - return Pair.create(object, parent); - } - - public TruffleString[] getDottedPath(Object obj, TruffleString name) { - TruffleString[] dottedPath = StringUtils.split(name, T_DOT, ensureTsCodePointLengthNode(), ensureTsIndexOfStringNode(), ensureTsSubstringNode(), ensureTsEqualNode()); - assert dottedPath.length > 0; - for (TruffleString subPath : dottedPath) { - if (ensureTsEqualNode().execute(subPath, T_LOCALS, TS_ENCODING)) { - if (obj == null) { - throw raise(AttributeError, ErrorMessages.CANT_PICKLE_LOCAL_OBJ_S, name); - } else { - throw raise(AttributeError, ErrorMessages.CANT_PICKLE_ATTR_S_OF_P, name, obj); - } - } - } - return dottedPath; - } - - protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { - PickleState state = getGlobalState(core); - return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); - } - - private Pair getMapping(VirtualFrame frame, PDict nameMapping, PDict importMapping, - TruffleString nameMappingLabel, TruffleString importMappingLabel, TruffleString moduleName, TruffleString globalName) { - Object key = PFactory.createTuple(PythonLanguage.get(this), new Object[]{moduleName, globalName}); - Object item = getDictItem(frame, nameMapping, key); - if (item != null) { - if (!(item instanceof PTuple) || ((PTuple) item).getSequenceStorage().length() != 2) { - throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P, nameMappingLabel, "2-tuples", item); - } - SequenceStorage storage = ((PTuple) item).getSequenceStorage(); - Object mappedModuleName = getItem(storage, 0); - Object mappedGlobalName = getItem(storage, 1); - if (!PGuards.isString(mappedModuleName) || !PGuards.isString(mappedGlobalName)) { - throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P_P, nameMappingLabel, "str", mappedModuleName, mappedGlobalName); - } - return Pair.create(asString(mappedModuleName), asString(mappedGlobalName)); - } - item = getDictItem(frame, importMapping, moduleName); - if (item != null) { - if (!PGuards.isString(item)) { - throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P, importMappingLabel, "strings", item); - } - return Pair.create(asString(item), globalName); - } - return Pair.create(moduleName, globalName); + return string; } private static boolean checkModule(VirtualFrame frame, PyObjectLookupAttr lookup, Object moduleName, Object module, Object global, TruffleString[] dottedPath) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 7c94c9425b..203d7ea33b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -42,6 +42,8 @@ import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_IMPORT_MAPPING; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_NAME_MAPPING; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; @@ -588,6 +590,11 @@ public Object getattribute(VirtualFrame frame, Object obj, TruffleString name, b } } + protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { + PickleState state = getGlobalState(core); + return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); + } + protected Pair get2To3Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { PickleState state = getGlobalState(core); return getMapping(frame, state.nameMapping2To3, state.importMapping2To3, T_CP_NAME_MAPPING, T_CP_IMPORT_MAPPING, moduleName, globalName); @@ -598,11 +605,12 @@ private Pair getMapping(VirtualFrame frame, PDict Object key = PFactory.createTuple(PythonLanguage.get(this), new Object[]{moduleName, globalName}); Object item = getDictItem(frame, nameMapping, key); if (item != null) { - if (!(item instanceof PTuple) || length(frame, item) != 2) { + if (!(item instanceof PTuple) || ((PTuple) item).getSequenceStorage().length() != 2) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P, nameMappingLabel, "2-tuples", item); } - Object mappedModuleName = getItem(frame, item, 0); - Object mappedGlobalName = getItem(frame, item, 1); + SequenceStorage storage = ((PTuple) item).getSequenceStorage(); + Object mappedModuleName = getItem(storage, 0); + Object mappedGlobalName = getItem(storage, 1); if (!PGuards.isString(mappedModuleName) || !PGuards.isString(mappedGlobalName)) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P_P, nameMappingLabel, "str", mappedModuleName, mappedGlobalName); } From 605eb2865a1848101dd38c8fb8a9b401806d2e05 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 10:29:22 +0200 Subject: [PATCH 088/129] Organize SaveNode fields (cherry picked from commit c275c1d6923628af5c4712fe32aaa9580c23facb) --- .../builtins/modules/pickle/PPickler.java | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 80329180c5..d7b1883fb5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -424,6 +424,53 @@ public abstract static class SaveNode extends PicklerNodes.BasePickleNode { static final TruffleString T_SET = tsLiteral("set"); static final TruffleString T_DICTIONARY = tsLiteral("dictionary"); + private static final long SEEN_NONE = 1; + private static final long SEEN_BOOLEAN = 1 << 1; + private static final long SEEN_INTEGER = 1 << 2; + private static final long SEEN_LONG = 1 << 3; + private static final long SEEN_PINT = 1 << 4; + private static final long SEEN_DOUBLE = 1 << 5; + private static final long SEEN_PFLOAT = 1 << 6; + private static final long SEEN_BUILTIN_CLASS_TYPE = 1 << 7; + private static final long SEEN_BYTES = 1 << 8; + private static final long SEEN_TRUFFLE_STRING = 1 << 9; + private static final long SEEN_PSTRING = 1 << 10; + private static final long SEEN_DICT = 1 << 11; + private static final long SEEN_SET = 1 << 12; + private static final long SEEN_FROZENSET = 1 << 13; + private static final long SEEN_LIST = 1 << 14; + private static final long SEEN_TUPLE = 1 << 15; + private static final long SEEN_NATIVE_TUPLE = 1 << 16; + private static final long SEEN_BYTE_ARRAY = 1 << 17; + private static final long SEEN_PICKLE_BUFFER = 1 << 18; + private static final long SEEN_MANAGED_CLASS = 1 << 19; + private static final long SEEN_NATIVE_CLASS = 1 << 20; + private static final long SEEN_FUNCTION = 1 << 21; + private static final long SEEN_TYPE = 1 << 22; + private static final long SEEN_OBJECT = 1 << 23; + private static final long SEEN_INT_STORAGE = 1 << 24; + private static final long SEEN_LONG_STORAGE = 1 << 25; + private static final long SEEN_DOUBLE_STORAGE = 1 << 26; + private static final long SEEN_GENERIC_STORAGE = 1 << 27; + private static final long SEEN_CUSTOM_DISPATCH = 1 << 28; + private static final long SEEN_REGISTERED_REDUCER = 1 << 29; + private static final long SEEN_REDUCE_EX = 1 << 30; + private static final long SEEN_REDUCE = 1L << 31; + private static final long SEEN_NEWOBJ_EX = 1L << 32; + private static final long SEEN_NEWOBJ = 1L << 33; + private static final long SEEN_PLAIN_REDUCE = 1L << 34; + private static final long SEEN_REDUCE_LISTITEMS = 1L << 35; + private static final long SEEN_REDUCE_DICTITEMS = 1L << 36; + private static final long SEEN_REDUCE_STATE = 1L << 37; + private static final long SEEN_BYPASS_BUFFER = 1L << 38; + + @CompilationFinal private long seenTypes; + + private final int depth; + @Child private SaveNode recursiveSaveNode1; + @Child private SaveNode recursiveSaveNode2; + @Child private SaveNode recursiveSaveNode3; + @Child private IntNodes.PyLongSign pyLongSign; @Child private IntNodes.PyLongNumBits pyLongNumBits; @Child private IntNodes.PyLongAsByteArray pyLongAsByteArray; @@ -435,6 +482,22 @@ public abstract static class SaveNode extends PicklerNodes.BasePickleNode { @Child private TruffleString.FromLongNode tsFromLongNode; @Child private TruffleString.CopyToByteArrayNode tsCopyToByteArrayNode; @Child private TruffleString.GetCodeRangeNode tsGetCodeRangeNode; + @Child private BoundaryCallData boundaryCallData; + @Child private PyLongAsLongNode pyLongAsLongNode; + @Child private PyObjectStrAsObjectNode pyObjectStrAsObjectNode; + @Child private PyObjectIsTrueNode isTrueNode; + @Child private IsNode isNode; + @Child private PythonBufferAcquireLibrary bufferAcquireLibrary; + @Child private PythonBufferAccessLibrary bufferLibrary; + @Child private PyCallableCheckNode callableCheckNode; + @Child private PyObjectReprAsTruffleStringNode reprNode; + @Child private PyObjectGetIter getIterNode; + @Child private HashingStorageLen hashingStorageLenNode; + @Child private PyTupleCheckNode.CachedNode tupleCheckNode; + + protected SaveNode(int depth) { + this.depth = depth; + } protected SequenceStorage getTupleStorage(Object tuple) { if (getTupleStorageNode == null) { @@ -756,69 +819,6 @@ protected static void fastSaveLeave(PPickler pickler, Object obj) { } } - private static final int SEEN_NONE = 1 << 0; - private static final int SEEN_BOOLEAN = 1 << 1; - private static final int SEEN_INTEGER = 1 << 2; - private static final int SEEN_LONG = 1 << 3; - private static final int SEEN_PINT = 1 << 4; - private static final int SEEN_DOUBLE = 1 << 5; - private static final int SEEN_PFLOAT = 1 << 6; - private static final int SEEN_BUILTIN_CLASS_TYPE = 1 << 7; - private static final int SEEN_BYTES = 1 << 8; - private static final int SEEN_TRUFFLE_STRING = 1 << 9; - private static final int SEEN_PSTRING = 1 << 10; - private static final int SEEN_DICT = 1 << 11; - private static final int SEEN_SET = 1 << 12; - private static final int SEEN_FROZENSET = 1 << 13; - private static final int SEEN_LIST = 1 << 14; - private static final int SEEN_TUPLE = 1 << 15; - private static final int SEEN_NATIVE_TUPLE = 1 << 16; - private static final int SEEN_BYTE_ARRAY = 1 << 17; - private static final int SEEN_PICKLE_BUFFER = 1 << 18; - private static final int SEEN_MANAGED_CLASS = 1 << 19; - private static final int SEEN_NATIVE_CLASS = 1 << 20; - private static final int SEEN_FUNCTION = 1 << 21; - private static final int SEEN_TYPE = 1 << 22; - private static final int SEEN_OBJECT = 1 << 23; - private static final int SEEN_INT_STORAGE = 1 << 24; - private static final int SEEN_LONG_STORAGE = 1 << 25; - private static final int SEEN_DOUBLE_STORAGE = 1 << 26; - private static final int SEEN_GENERIC_STORAGE = 1 << 27; - private static final int SEEN_CUSTOM_DISPATCH = 1 << 28; - private static final int SEEN_REGISTERED_REDUCER = 1 << 29; - private static final int SEEN_REDUCE_EX = 1 << 30; - private static final int SEEN_REDUCE = 1 << 31; - private static final long SEEN_NEWOBJ_EX = 1L << 32; - private static final long SEEN_NEWOBJ = 1L << 33; - private static final long SEEN_PLAIN_REDUCE = 1L << 34; - private static final long SEEN_REDUCE_LISTITEMS = 1L << 35; - private static final long SEEN_REDUCE_DICTITEMS = 1L << 36; - private static final long SEEN_REDUCE_STATE = 1L << 37; - private static final long SEEN_BYPASS_BUFFER = 1L << 38; - - @CompilationFinal private long seenTypes; - - private final int depth; - @Child private SaveNode recursiveSaveNode1; - @Child private SaveNode recursiveSaveNode2; - @Child private SaveNode recursiveSaveNode3; - @Child private BoundaryCallData boundaryCallData; - @Child private PyLongAsLongNode pyLongAsLongNode; - @Child private PyObjectStrAsObjectNode pyObjectStrAsObjectNode; - @Child private PyObjectIsTrueNode isTrueNode; - @Child private IsNode isNode; - @Child private PythonBufferAcquireLibrary bufferAcquireLibrary; - @Child private PythonBufferAccessLibrary bufferLibrary; - @Child private PyCallableCheckNode callableCheckNode; - @Child private PyObjectReprAsTruffleStringNode reprNode; - @Child private PyObjectGetIter getIterNode; - @Child private HashingStorageLen hashingStorageLenNode; - @Child private PyTupleCheckNode.CachedNode tupleCheckNode; - - protected SaveNode(int depth) { - this.depth = depth; - } - private void profileSeen(long seen) { if ((seenTypes & seen) == 0) { CompilerDirectives.transferToInterpreterAndInvalidate(); From 904c28d11af4656a4a780de43f9d6b4b6347eab9 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 10:39:26 +0200 Subject: [PATCH 089/129] Move write helpers to PPickler (cherry picked from commit 7848db81fbc20eb7865721e7b8814b17438a51a7) --- .../builtins/modules/pickle/PPickler.java | 548 +++++++++--------- 1 file changed, 276 insertions(+), 272 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index d7b1883fb5..646f5f925a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -146,6 +146,7 @@ import com.oracle.truffle.api.strings.TruffleString; public class PPickler extends PythonBuiltinObject { + private static final byte NEW_LINE_BYTE = '\n'; // Memo table, keep track of the seen objects to support self-referential objects pickling private MemoTable memo; // persistent_id() method, can be NULL @@ -399,6 +400,168 @@ public PBytes getString(PythonLanguage language) { return PFactory.createBytes(language, outputBuffer, outputLen); } + private void writeASCII(Node node, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + assert string.getCodeRangeUncached(TS_ENCODING) == TruffleString.CodeRange.ASCII; + TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.US_ASCII); + int length = encoded.byteLength(TruffleString.Encoding.US_ASCII); + ensureBufferSpace(node, length); + copyToByteArrayNode.execute(encoded, 0, outputBuffer, outputLen, length, TruffleString.Encoding.US_ASCII); + outputLen += length; + } + + private void writeUtf8(Node node, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + writeUtf8Converted(node, encoded, copyToByteArrayNode); + } + + private void writeUtf8Converted(Node node, TruffleString encoded, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + int length = encoded.byteLength(TruffleString.Encoding.UTF_8); + ensureBufferSpace(node, length); + copyToByteArrayNode.execute(encoded, 0, outputBuffer, outputLen, length, TruffleString.Encoding.UTF_8); + outputLen += length; + } + + private void writeLongAsString(Node node, byte opcode, long value, TruffleString.FromLongNode fromLongNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString string = fromLongNode.execute(value, TruffleString.Encoding.US_ASCII, true); + TruffleString.Encoding encoding = TruffleString.Encoding.US_ASCII; + int length = string.byteLength(encoding); + ensureBufferSpace(node, length + 2); + outputBuffer[outputLen++] = opcode; + copyToByteArrayNode.execute(string, 0, outputBuffer, outputLen, length, encoding); + outputLen += length; + outputBuffer[outputLen++] = NEW_LINE_BYTE; + } + + private void write(Node node, byte b) { + ensureBufferSpace(node, 1); + outputBuffer[outputLen++] = b; + } + + private void write(Node node, byte b1, byte b2) { + ensureBufferSpace(node, 2); + outputBuffer[outputLen++] = b1; + outputBuffer[outputLen++] = b2; + } + + private void writeBuffer(Node node, Object buffer, int size, PythonBufferAccessLibrary bufferLib) { + ensureBufferSpace(node, size); + bufferLib.readIntoByteArray(buffer, 0, outputBuffer, outputLen, size); + outputLen += size; + } + + private static byte intByte1(long value) { + return (byte) (value & 0xff); + } + + private static byte intByte2(long value) { + return (byte) ((value >> 8) & 0xff); + } + + private static byte intByte3(long value) { + return (byte) ((value >> 16) & 0xff); + } + + private static byte intByte4(long value) { + return (byte) ((value >> 24) & 0xff); + } + + private void writeByteOp(Node node, byte opcode, long value) { + ensureBufferSpace(node, 2); + outputBuffer[outputLen++] = opcode; + outputBuffer[outputLen++] = intByte1(value); + } + + private void writeShortOp(Node node, byte opcode, long value) { + ensureBufferSpace(node, 3); + outputBuffer[outputLen++] = opcode; + outputBuffer[outputLen++] = intByte1(value); + outputBuffer[outputLen++] = intByte2(value); + } + + private void writeIntOp(Node node, byte opcode, long value) { + ensureBufferSpace(node, 5); + outputBuffer[outputLen++] = opcode; + outputBuffer[outputLen++] = intByte1(value); + outputBuffer[outputLen++] = intByte2(value); + outputBuffer[outputLen++] = intByte3(value); + outputBuffer[outputLen++] = intByte4(value); + } + + private void write(Node node, byte[] bytes, int dataLen) { + ensureBufferSpace(node, dataLen); + PythonUtils.arraycopy(bytes, 0, outputBuffer, outputLen, dataLen); + outputLen += dataLen; + } + + private void ensureBufferSpace(Node node, int dataLen) { + boolean needNewFrame = isFraming() && frameStart == -1; + int n = CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; + int required = outputLen + n; + + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, required > maxOutputLen)) { + // Make place in buffer for the pickle chunk + // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, outputLen >= Integer.MAX_VALUE / 2 - n)) { + CompilerDirectives.transferToInterpreter(); + throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); + } + maxOutputLen = (outputLen + n) / 2 * 3; + outputBuffer = PythonUtils.arrayCopyOf(outputBuffer, maxOutputLen); + } + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame)) { + frameStart = outputLen; + outputLen += PickleUtils.FRAME_HEADER_SIZE; + } + } + + private boolean bypassBuffer(int dataSize) { + boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; + + if (bypassBuffer) { + assert outputBuffer != null; + // Commit the previous frame. + commitFrame(); + // Disable framing temporarily + framing = false; + } + return bypassBuffer; + } + + private void writeRawUnicodeEscape(Node node, TruffleString string, + TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexUTF32Node codePointAtIndexNode) { + int codePointLength = codePointLengthNode.execute(string, TS_ENCODING); + long escapedLength = 0; + for (int i = 0; i < codePointLength; i++) { + int ch = codePointAtIndexNode.execute(string, i); + escapedLength += ch >= 0x10000 ? 10 : ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a ? 6 : 1; + } + if (escapedLength > Integer.MAX_VALUE) { + throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); + } + ensureBufferSpace(node, (int) escapedLength); + for (int i = 0; i < codePointLength; i++) { + int ch = codePointAtIndexNode.execute(string, i); + if (ch >= 0x10000) { + outputBuffer[outputLen++] = '\\'; + outputBuffer[outputLen++] = 'U'; + for (int shift = 28; shift >= 0; shift -= 4) { + outputBuffer[outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; + } + } else if (ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a) { + outputBuffer[outputLen++] = '\\'; + outputBuffer[outputLen++] = 'u'; + for (int shift = 12; shift >= 0; shift -= 4) { + outputBuffer[outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; + } + } else { + outputBuffer[outputLen++] = (byte) ch; + } + } + } + // inner nodes @GenerateInline(false) public abstract static class TupleStorageNode extends Node { @@ -417,7 +580,6 @@ public abstract static class SaveNode extends PicklerNodes.BasePickleNode { private static final TruffleString T_SYS_MODULES = tsLiteral("sys.modules"); static final byte[] TUPLE_LEN_2_OPCODE = new byte[]{PickleUtils.OPCODE_EMPTY_TUPLE, PickleUtils.OPCODE_TUPLE1, PickleUtils.OPCODE_TUPLE2, PickleUtils.OPCODE_TUPLE3}; - static final byte NEW_LINE_BYTE = '\n'; static final TruffleString DICT_ITEMS = tsLiteral("dict items"); static final TruffleString LATIN1 = tsLiteral("latin1"); static final TruffleString T_L_NEW_LINE = tsLiteral("L\n"); @@ -660,141 +822,6 @@ public static void handleError(PPickler pickler) { pickler.reducerOverride = null; } - protected static void writeASCII(Node node, PPickler pickler, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, - TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - assert string.getCodeRangeUncached(TS_ENCODING) == TruffleString.CodeRange.ASCII; - TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.US_ASCII); - int length = encoded.byteLength(TruffleString.Encoding.US_ASCII); - ensureBufferSpace(node, pickler, length); - copyToByteArrayNode.execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.US_ASCII); - pickler.outputLen += length; - } - - protected static void writeUtf8(Node node, PPickler pickler, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, - TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - writeUtf8Converted(node, pickler, encoded, copyToByteArrayNode); - } - - public static void writeUtf8Converted(Node node, PPickler pickler, TruffleString encoded, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - int length = encoded.byteLength(TruffleString.Encoding.UTF_8); - ensureBufferSpace(node, pickler, length); - copyToByteArrayNode.execute(encoded, 0, pickler.outputBuffer, pickler.outputLen, length, TruffleString.Encoding.UTF_8); - pickler.outputLen += length; - } - - protected static void writeLongAsString(Node node, PPickler pickler, byte opcode, long value, TruffleString.FromLongNode fromLongNode, - TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - TruffleString string = fromLongNode.execute(value, TruffleString.Encoding.US_ASCII, true); - TruffleString.Encoding encoding = TruffleString.Encoding.US_ASCII; - int length = string.byteLength(encoding); - ensureBufferSpace(node, pickler, length + 2); - pickler.outputBuffer[pickler.outputLen++] = opcode; - copyToByteArrayNode.execute(string, 0, pickler.outputBuffer, pickler.outputLen, length, encoding); - pickler.outputLen += length; - pickler.outputBuffer[pickler.outputLen++] = NEW_LINE_BYTE; - } - - protected static void write(Node node, PPickler pickler, byte b) { - ensureBufferSpace(node, pickler, 1); - pickler.outputBuffer[pickler.outputLen++] = b; - } - - protected static void write(Node node, PPickler pickler, byte b1, byte b2) { - ensureBufferSpace(node, pickler, 2); - pickler.outputBuffer[pickler.outputLen++] = b1; - pickler.outputBuffer[pickler.outputLen++] = b2; - } - - protected static void writeBuffer(Node node, PPickler pickler, Object buffer, int size, PythonBufferAccessLibrary bufferLib) { - ensureBufferSpace(node, pickler, size); - bufferLib.readIntoByteArray(buffer, 0, pickler.outputBuffer, pickler.outputLen, size); - pickler.outputLen += size; - } - - protected static byte intByte1(long value) { - return (byte) (value & 0xff); - } - - protected static byte intByte2(long value) { - return (byte) ((value >> 8) & 0xff); - } - - protected static byte intByte3(long value) { - return (byte) ((value >> 16) & 0xff); - } - - protected static byte intByte4(long value) { - return (byte) ((value >> 24) & 0xff); - } - - protected static void writeByteOp(Node node, PPickler pickler, byte opcode, long value) { - ensureBufferSpace(node, pickler, 2); - pickler.outputBuffer[pickler.outputLen++] = opcode; - pickler.outputBuffer[pickler.outputLen++] = intByte1(value); - } - - protected static void writeShortOp(Node node, PPickler pickler, byte opcode, long value) { - ensureBufferSpace(node, pickler, 3); - pickler.outputBuffer[pickler.outputLen++] = opcode; - pickler.outputBuffer[pickler.outputLen++] = intByte1(value); - pickler.outputBuffer[pickler.outputLen++] = intByte2(value); - } - - protected static void writeIntOp(Node node, PPickler pickler, byte opcode, long value) { - ensureBufferSpace(node, pickler, 5); - pickler.outputBuffer[pickler.outputLen++] = opcode; - pickler.outputBuffer[pickler.outputLen++] = intByte1(value); - pickler.outputBuffer[pickler.outputLen++] = intByte2(value); - pickler.outputBuffer[pickler.outputLen++] = intByte3(value); - pickler.outputBuffer[pickler.outputLen++] = intByte4(value); - } - - protected static void write(Node node, PPickler pickler, byte[] bytes) { - write(node, pickler, bytes, bytes.length); - } - - protected static void write(Node node, PPickler pickler, byte[] bytes, int dataLen) { - ensureBufferSpace(node, pickler, dataLen); - PythonUtils.arraycopy(bytes, 0, pickler.outputBuffer, pickler.outputLen, dataLen); - pickler.outputLen += dataLen; - } - - public static void ensureBufferSpace(Node node, PPickler pickler, int dataLen) { - boolean needNewFrame = pickler.isFraming() && pickler.frameStart == -1; - int n = CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; - int required = pickler.outputLen + n; - - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, required > pickler.maxOutputLen)) { - // Make place in buffer for the pickle chunk - // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, pickler.outputLen >= Integer.MAX_VALUE / 2 - n)) { - CompilerDirectives.transferToInterpreter(); - throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); - } - pickler.maxOutputLen = (pickler.outputLen + n) / 2 * 3; - pickler.outputBuffer = PythonUtils.arrayCopyOf(pickler.outputBuffer, pickler.maxOutputLen); - } - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame)) { - pickler.frameStart = pickler.outputLen; - pickler.outputLen += PickleUtils.FRAME_HEADER_SIZE; - } - } - - protected boolean bypassBuffer(PPickler pickler, int dataSize) { - boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; - - if (bypassBuffer) { - profileSeen(SEEN_BYPASS_BUFFER); - assert pickler.outputBuffer != null; - // Commit the previous frame. - pickler.commitFrame(); - // Disable framing temporarily - pickler.framing = false; - } - return bypassBuffer; - } - protected PTuple createTuple(Object... items) { if (items.length == 0) { return PFactory.createEmptyTuple(PythonLanguage.get(this)); @@ -1012,7 +1039,7 @@ private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, Has int i; do { i = 0; - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); while (nextNode.executeCached(storage, it)) { save(frame, pickler, getKeyNode.executeCached(storage, it), 0); if (saveValues) { @@ -1022,7 +1049,7 @@ private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, Has break; } } - write(this, pickler, opcodeBatch); + pickler.write(this, opcodeBatch); if (getHashingStorageLength(storage) != initialSize) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.CHANGED_SIZE_DURING_ITERATION, name); } @@ -1068,12 +1095,12 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O } catch (IteratorExhausted e) { // Only one item to write saveItem.accept(firstItem); - write(this, pickler, opcodeOneItem); + pickler.write(this, opcodeOneItem); break; } // More than one item to write // Pump out MARK, items, APPENDS. - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); saveItem.accept(firstItem); n = 1; while (true) { @@ -1092,7 +1119,7 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O break; } } - write(this, pickler, opcodeMultipleItems); + pickler.write(this, opcodeMultipleItems); } while (n == PickleUtils.BATCHSIZE); } @@ -1128,7 +1155,7 @@ private void saveIterator(VirtualFrame frame, PPickler pickler, Object iterator, } itemConsumer.accept(item); if (opcode != PickleUtils.NO_OPCODE) { - write(this, pickler, opcode); + pickler.write(this, opcode); } } } @@ -1162,16 +1189,16 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object if (pid != PNone.NONE) { if (isBin(proto)) { save(frame, pickler, pid, 1); - write(this, pickler, PickleUtils.OPCODE_BINPERSID); + pickler.write(this, PickleUtils.OPCODE_BINPERSID); } else { final TruffleString pidStr = asString(convertToStr(frame, pid)); // XXX: Should it check whether the pid contains embedded newlines? if (!PythonUtils.isAscii(pidStr, ensureTsGetCodeRangeNode())) { throw raise(PythonBuiltinClassType.PicklingError, ErrorMessages.PIDS_MUST_BE_ASCII_STRS); } - write(this, pickler, PickleUtils.OPCODE_PERSID); - writeASCII(this, pickler, pidStr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); - writeASCII(this, pickler, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.write(this, PickleUtils.OPCODE_PERSID); + pickler.writeASCII(this, pidStr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } return true; } @@ -1182,15 +1209,15 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object private void memoGet(PPickler pickler, int proto, int value) { if (isBin(proto)) { if (value < 256) { - writeByteOp(this, pickler, PickleUtils.OPCODE_BINGET, value); + pickler.writeByteOp(this, PickleUtils.OPCODE_BINGET, value); } else if (Long.compareUnsigned(value, 0xffffffffL) <= 0) { - writeIntOp(this, pickler, PickleUtils.OPCODE_LONG_BINGET, value); + pickler.writeIntOp(this, PickleUtils.OPCODE_LONG_BINGET, value); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINGET"); } } else { - writeLongAsString(this, pickler, PickleUtils.OPCODE_GET, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + pickler.writeLongAsString(this, PickleUtils.OPCODE_GET, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } } @@ -1204,15 +1231,15 @@ private void memoPut(PPickler pickler, int proto, boolean fastMode, Object obj) pickler.memo.set(obj, idx); if (proto >= 4) { - write(this, pickler, PickleUtils.OPCODE_MEMOIZE); + pickler.write(this, PickleUtils.OPCODE_MEMOIZE); } else { if (!isBin(proto)) { - writeLongAsString(this, pickler, PickleUtils.OPCODE_PUT, idx, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + pickler.writeLongAsString(this, PickleUtils.OPCODE_PUT, idx, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } else { if (idx < 256) { - writeByteOp(this, pickler, PickleUtils.OPCODE_BINPUT, idx); + pickler.writeByteOp(this, PickleUtils.OPCODE_BINPUT, idx); } else if (Long.compareUnsigned(idx, 0xffffffffL) <= 0) { - writeIntOp(this, pickler, PickleUtils.OPCODE_LONG_BINPUT, idx); + pickler.writeIntOp(this, PickleUtils.OPCODE_LONG_BINPUT, idx); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINPUT"); @@ -1332,7 +1359,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, save(frame, pickler, cls, 0); save2(frame, pickler, args, 0); save3(frame, pickler, kwargs, 0); - write(this, pickler, PickleUtils.OPCODE_NEWOBJ_EX); + pickler.write(this, PickleUtils.OPCODE_NEWOBJ_EX); } else { PickleState st = getGlobalState(ctx.getCore()); final SequenceStorage argsStorage = getTupleStorage(args); @@ -1352,7 +1379,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, save(frame, pickler, callable, 0); save2(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this)), 0); - write(this, pickler, PickleUtils.OPCODE_REDUCE); + pickler.write(this, PickleUtils.OPCODE_REDUCE); } } else if (useNewobj) { profileSeen(SEEN_NEWOBJ); @@ -1414,13 +1441,13 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, } newargtup = createTuple(newargs); save2(frame, pickler, newargtup, 0); - write(this, pickler, PickleUtils.OPCODE_NEWOBJ); + pickler.write(this, PickleUtils.OPCODE_NEWOBJ); } else { profileSeen(SEEN_PLAIN_REDUCE); // Not using NEWOBJ save(frame, pickler, callable, 0); save2(frame, pickler, argtup, 0); - write(this, pickler, PickleUtils.OPCODE_REDUCE); + pickler.write(this, PickleUtils.OPCODE_REDUCE); } // obj can be NULL when save_reduce() is used directly. A NULL obj means the caller do @@ -1432,7 +1459,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // memo int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - write(this, pickler, PickleUtils.OPCODE_POP); + pickler.write(this, PickleUtils.OPCODE_POP); memoGet(pickler, proto, memoIndex); } else { memoPut(pickler, proto, fastMode, obj); @@ -1453,7 +1480,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, profileSeen(SEEN_REDUCE_STATE); if (stateSetter == null) { save(frame, pickler, state, 0); - write(this, pickler, PickleUtils.OPCODE_BUILD); + pickler.write(this, PickleUtils.OPCODE_BUILD); } else { // If a state_setter is specified, call it instead of load_build to update obj's // with its previous state. The first 4 save/write instructions push @@ -1465,40 +1492,40 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, save(frame, pickler, stateSetter, 0); save2(frame, pickler, obj, 0); save3(frame, pickler, state, 0); - write(this, pickler, PickleUtils.OPCODE_TUPLE2); - write(this, pickler, PickleUtils.OPCODE_REDUCE); - write(this, pickler, PickleUtils.OPCODE_POP); + pickler.write(this, PickleUtils.OPCODE_TUPLE2); + pickler.write(this, PickleUtils.OPCODE_REDUCE); + pickler.write(this, PickleUtils.OPCODE_POP); } } } private void saveNone(PPickler pickler) { - write(this, pickler, PickleUtils.OPCODE_NONE); + pickler.write(this, PickleUtils.OPCODE_NONE); } private void saveBool(PPickler pickler, int proto, boolean value) { if (proto >= 2) { - write(this, pickler, value ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); + pickler.write(this, value ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); } else { // These aren't opcodes -- they're ways to pickle bools before protocol 2 so that // unpicklers written before bools were introduced unpickle them as ints, but // unpicklers after can recognize that bools were intended. Note that protocol 2 // added direct ways to pickle bools. - writeASCII(this, pickler, value ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, value ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } private void saveLong(PPickler pickler, int proto, int value) { if (isBin(proto)) { if (value >= 0 && value < (1 << 8)) { - writeByteOp(this, pickler, PickleUtils.OPCODE_BININT1, value); + pickler.writeByteOp(this, PickleUtils.OPCODE_BININT1, value); } else if (value >= 0 && value < (1 << 16)) { - writeShortOp(this, pickler, PickleUtils.OPCODE_BININT2, value); + pickler.writeShortOp(this, PickleUtils.OPCODE_BININT2, value); } else { - writeIntOp(this, pickler, PickleUtils.OPCODE_BININT, value); + pickler.writeIntOp(this, PickleUtils.OPCODE_BININT, value); } } else { - writeLongAsString(this, pickler, PickleUtils.OPCODE_INT, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + pickler.writeLongAsString(this, PickleUtils.OPCODE_INT, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } } @@ -1546,32 +1573,32 @@ private void saveLongLarge(VirtualFrame frame, PPickler pickler, int proto, Obje nbytes--; } if (nbytes < 256) { - writeByteOp(this, pickler, PickleUtils.OPCODE_LONG1, nbytes); + pickler.writeByteOp(this, PickleUtils.OPCODE_LONG1, nbytes); } else { - writeIntOp(this, pickler, PickleUtils.OPCODE_LONG4, nbytes); + pickler.writeIntOp(this, PickleUtils.OPCODE_LONG4, nbytes); } - write(this, pickler, pdata, nbytes); + pickler.write(this, pdata, nbytes); } else { TruffleString repr = repr(frame, obj); - write(this, pickler, PickleUtils.OPCODE_LONG); - writeASCII(this, pickler, asStringStrict(repr), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); - writeASCII(this, pickler, T_L_NEW_LINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.write(this, PickleUtils.OPCODE_LONG); + pickler.writeASCII(this, asStringStrict(repr), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_L_NEW_LINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } private void saveFloat(PPickler pickler, int proto, double value) { if (isBin(proto)) { - write(this, pickler, PickleUtils.OPCODE_BINFLOAT); - ensureBufferSpace(this, pickler, 8); + pickler.write(this, PickleUtils.OPCODE_BINFLOAT); + pickler.ensureBufferSpace(this, 8); NumericSupport.bigEndian().putDouble(pickler.outputBuffer, pickler.outputLen, value); pickler.outputLen += 8; } else { - write(this, pickler, PickleUtils.OPCODE_FLOAT); + pickler.write(this, PickleUtils.OPCODE_FLOAT); TruffleString repr = PickleUtils.doubleToAsciiString(value); - writeASCII(this, pickler, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); - writeASCII(this, pickler, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } @@ -1613,12 +1640,15 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool assert proto >= 3; int size = bufferLib.getBufferLength(buffer); boolean wasFraming = pickler.framing; - boolean bypassBuffer = bypassBuffer(pickler, size); + boolean bypassBuffer = pickler.bypassBuffer(size); + if (bypassBuffer) { + profileSeen(SEEN_BYPASS_BUFFER); + } if (size <= 0xff) { - writeByteOp(this, pickler, PickleUtils.OPCODE_SHORT_BINBYTES, size); + pickler.writeByteOp(this, PickleUtils.OPCODE_SHORT_BINBYTES, size); } else { - writeIntOp(this, pickler, PickleUtils.OPCODE_BINBYTES, size); + pickler.writeIntOp(this, PickleUtils.OPCODE_BINBYTES, size); } if (bypassBuffer && pickler.write != null) { @@ -1626,7 +1656,7 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool ensureCallNode().execute(frame, pickler.write, obj); pickler.clearBuffer(); } else { - writeBuffer(this, pickler, buffer, size, bufferLib); + pickler.writeBuffer(this, buffer, size, bufferLib); } if (bypassBuffer && wasFraming) { @@ -1641,10 +1671,13 @@ private void writeUnicodeBinary(Node node, VirtualFrame frame, PPickler pickler, TruffleString utf8 = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); int size = utf8.byteLength(TruffleString.Encoding.UTF_8); boolean wasFraming = pickler.framing; - boolean bypassBuffer = bypassBuffer(pickler, size); + boolean bypassBuffer = pickler.bypassBuffer(size); + if (bypassBuffer) { + profileSeen(SEEN_BYPASS_BUFFER); + } if (bypassBuffer && pickler.write != null) { - writeIntOp(node, pickler, PickleUtils.OPCODE_BINUNICODE, size); + pickler.writeIntOp(node, PickleUtils.OPCODE_BINUNICODE, size); byte[] data = new byte[size]; copyToByteArrayNode.execute(utf8, 0, data, 0, size, TruffleString.Encoding.UTF_8); flushToFileNode.execute(frame, pickler); @@ -1652,11 +1685,11 @@ private void writeUnicodeBinary(Node node, VirtualFrame frame, PPickler pickler, pickler.clearBuffer(); } else { if (size <= 0xff && proto >= 4) { - writeByteOp(node, pickler, PickleUtils.OPCODE_SHORT_BINUNICODE, size); + pickler.writeByteOp(node, PickleUtils.OPCODE_SHORT_BINUNICODE, size); } else { - writeIntOp(node, pickler, PickleUtils.OPCODE_BINUNICODE, size); + pickler.writeIntOp(node, PickleUtils.OPCODE_BINUNICODE, size); } - writeUtf8Converted(node, pickler, utf8, copyToByteArrayNode); + pickler.writeUtf8Converted(node, utf8, copyToByteArrayNode); } if (bypassBuffer && wasFraming) { @@ -1676,45 +1709,13 @@ private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolea if (isBin(proto)) { writeUnicodeBinary(this, frame, pickler, proto, string, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode(), ensureFlushToFileNode(), ensureCallNode()); } else { - write(this, pickler, PickleUtils.OPCODE_UNICODE); - writeRawUnicodeEscape(this, pickler, string, ensureTsCodePointLengthNode(), ensureTsCodePointAtIndexUTF32Node()); - writeASCII(this, pickler, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.write(this, PickleUtils.OPCODE_UNICODE); + pickler.writeRawUnicodeEscape(this, string, ensureTsCodePointLengthNode(), ensureTsCodePointAtIndexUTF32Node()); + pickler.writeASCII(this, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } memoPut(pickler, proto, fastMode, obj); } - private static void writeRawUnicodeEscape(Node node, PPickler pickler, TruffleString string, - TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexUTF32Node codePointAtIndexNode) { - int codePointLength = codePointLengthNode.execute(string, TS_ENCODING); - long escapedLength = 0; - for (int i = 0; i < codePointLength; i++) { - int ch = codePointAtIndexNode.execute(string, i); - escapedLength += ch >= 0x10000 ? 10 : ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a ? 6 : 1; - } - if (escapedLength > Integer.MAX_VALUE) { - throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); - } - ensureBufferSpace(node, pickler, (int) escapedLength); - for (int i = 0; i < codePointLength; i++) { - int ch = codePointAtIndexNode.execute(string, i); - if (ch >= 0x10000) { - pickler.outputBuffer[pickler.outputLen++] = '\\'; - pickler.outputBuffer[pickler.outputLen++] = 'U'; - for (int shift = 28; shift >= 0; shift -= 4) { - pickler.outputBuffer[pickler.outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; - } - } else if (ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a) { - pickler.outputBuffer[pickler.outputLen++] = '\\'; - pickler.outputBuffer[pickler.outputLen++] = 'u'; - for (int shift = 12; shift >= 0; shift -= 4) { - pickler.outputBuffer[pickler.outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; - } - } else { - pickler.outputBuffer[pickler.outputLen++] = (byte) ch; - } - } - } - private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { final HashingStorage storage = dict.getDictStorage(); final int length = getHashingStorageLength(storage); @@ -1728,7 +1729,7 @@ private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); save(frame, pickler, getKeyNode.executeCached(storage, it), 0); save(frame, pickler, getValueNode.executeCached(storage, it), 0); - write(this, pickler, PickleUtils.OPCODE_SETITEM); + pickler.write(this, PickleUtils.OPCODE_SETITEM); } else { // Write in batches of BATCHSIZE. saveDictHashingStorageBatched(frame, pickler, storage); @@ -1753,9 +1754,9 @@ private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMetho // Create an empty dict. if (isBin(proto)) { - write(this, pickler, PickleUtils.OPCODE_EMPTY_DICT); + pickler.write(this, PickleUtils.OPCODE_EMPTY_DICT); } else { - write(this, pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_DICT); + pickler.write(this, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_DICT); } memoPut(pickler, proto, fastMode, obj); @@ -1783,7 +1784,7 @@ private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, in return; } - write(this, pickler, PickleUtils.OPCODE_EMPTY_SET); + pickler.write(this, PickleUtils.OPCODE_EMPTY_SET); memoPut(pickler, proto, fastMode, obj); HashingStorage storage = obj.getDictStorage(); @@ -1808,7 +1809,7 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl return; } - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); saveSetHashingStorage(frame, pickler, obj.getDictStorage()); @@ -1816,12 +1817,12 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl // away everything we put on the stack, and fetch the object back from the memo. int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - write(this, pickler, PickleUtils.OPCODE_POP_MARK); + pickler.write(this, PickleUtils.OPCODE_POP_MARK); memoGet(pickler, proto, memoIndex); return; } - write(this, pickler, PickleUtils.OPCODE_FROZENSET); + pickler.write(this, PickleUtils.OPCODE_FROZENSET); memoPut(pickler, proto, fastMode, obj); } @@ -1847,7 +1848,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { if (storage.length() == 1) { item = getItem(storage, 0); save(frame, pickler, item, 0); - write(this, pickler, PickleUtils.OPCODE_APPEND); + pickler.write(this, PickleUtils.OPCODE_APPEND); return; } @@ -1856,7 +1857,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { int thisBatch; do { thisBatch = 0; - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); while (total < storage.length()) { item = getItem(storage, total); save(frame, pickler, item, 0); @@ -1865,7 +1866,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { break; } } - write(this, pickler, PickleUtils.OPCODE_APPENDS); + pickler.write(this, PickleUtils.OPCODE_APPENDS); } while (total < storage.length()); } @@ -1874,19 +1875,19 @@ private void batchIntList(VirtualFrame frame, PPickler pickler, IntSequenceStora if (storage.length() == 1) { opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getIntItemNormalized(0)); - write(this, pickler, PickleUtils.OPCODE_APPEND); + pickler.write(this, PickleUtils.OPCODE_APPEND); return; } int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getIntItemNormalized(i)); } - write(this, pickler, PickleUtils.OPCODE_APPENDS); + pickler.write(this, PickleUtils.OPCODE_APPENDS); } } @@ -1895,19 +1896,19 @@ private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceSto if (storage.length() == 1) { opcodeBoundary(frame, pickler); saveLong(frame, pickler, proto, storage.getLongItemNormalized(0)); - write(this, pickler, PickleUtils.OPCODE_APPEND); + pickler.write(this, PickleUtils.OPCODE_APPEND); return; } int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { opcodeBoundary(frame, pickler); saveLong(frame, pickler, proto, storage.getLongItemNormalized(i)); } - write(this, pickler, PickleUtils.OPCODE_APPENDS); + pickler.write(this, PickleUtils.OPCODE_APPENDS); } } @@ -1916,19 +1917,19 @@ private void batchDoubleList(VirtualFrame frame, PPickler pickler, DoubleSequenc if (storage.length() == 1) { opcodeBoundary(frame, pickler); saveFloat(pickler, proto, storage.getDoubleItemNormalized(0)); - write(this, pickler, PickleUtils.OPCODE_APPEND); + pickler.write(this, PickleUtils.OPCODE_APPEND); return; } int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { opcodeBoundary(frame, pickler); saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); } - write(this, pickler, PickleUtils.OPCODE_APPENDS); + pickler.write(this, PickleUtils.OPCODE_APPENDS); } } @@ -1950,9 +1951,9 @@ private void saveList(VirtualFrame frame, PPickler pickler, int proto, boolean f // Create an empty list. if (isBin(proto)) { - write(this, pickler, PickleUtils.OPCODE_EMPTY_LIST); + pickler.write(this, PickleUtils.OPCODE_EMPTY_LIST); } else { - write(this, pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); + pickler.write(this, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); } int len = obj.getSequenceStorage().length(); @@ -2033,9 +2034,9 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean if (len == 0) { if (proto != 0) { - write(this, pickler, PickleUtils.OPCODE_EMPTY_TUPLE); + pickler.write(this, PickleUtils.OPCODE_EMPTY_TUPLE); } else { - write(this, pickler, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_TUPLE); + pickler.write(this, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_TUPLE); } return; } @@ -2051,14 +2052,14 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean if (memoIndex != -1) { // pop the len elements for (int i = 0; i < len; i++) { - write(this, pickler, PickleUtils.OPCODE_POP); + pickler.write(this, PickleUtils.OPCODE_POP); } // fetch from memo memoGet(pickler, proto, memoIndex); return; } else { // Not recursive. - write(this, pickler, TUPLE_LEN_2_OPCODE[len]); + pickler.write(this, TUPLE_LEN_2_OPCODE[len]); } memoPut(pickler, proto, fastMode, obj); @@ -2066,18 +2067,18 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean } // proto < 2 and len > 0, or proto >= 2 and len > 3. Generate MARK e1 e2 ... TUPLE - write(this, pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); storeTupleElements(frame, pickler, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { // pop the stack stuff we pushed if (isBin(proto)) { - write(this, pickler, PickleUtils.OPCODE_POP_MARK); + pickler.write(this, PickleUtils.OPCODE_POP_MARK); } else { // Note that we pop one more than len, to remove the MARK too. for (int i = 0; i <= len; i++) { - write(this, pickler, PickleUtils.OPCODE_POP); + pickler.write(this, PickleUtils.OPCODE_POP); } } // fetch from memo @@ -2085,7 +2086,7 @@ private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean return; } else { // Not recursive. - write(this, pickler, PickleUtils.OPCODE_TUPLE); + pickler.write(this, PickleUtils.OPCODE_TUPLE); } memoPut(pickler, proto, fastMode, obj); @@ -2096,10 +2097,13 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, int size = bufferLib.getBufferLength(buffer); boolean wasFraming = pickler.framing; - boolean bypassBuffer = bypassBuffer(pickler, size); + boolean bypassBuffer = pickler.bypassBuffer(size); + if (bypassBuffer) { + profileSeen(SEEN_BYPASS_BUFFER); + } // Our sizes are ints, but the protocol expects 8 bytes - ensureBufferSpace(this, pickler, 9); + pickler.ensureBufferSpace(this, 9); pickler.outputBuffer[pickler.outputLen++] = PickleUtils.OPCODE_BYTEARRAY8; PickleUtils.writeSize64(pickler.outputBuffer, pickler.outputLen, size); pickler.outputLen += 8; @@ -2109,7 +2113,7 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, ensureCallNode().execute(frame, pickler.write, obj); pickler.clearBuffer(); } else { - writeBuffer(this, pickler, buffer, size, bufferLib); + pickler.writeBuffer(this, buffer, size, bufferLib); } if (bypassBuffer && wasFraming) { @@ -2168,9 +2172,9 @@ private void savePickleBuffer(VirtualFrame frame, PPickler pickler, int proto, b } } else { // Write data out-of-band - write(this, pickler, PickleUtils.OPCODE_NEXT_BUFFER); + pickler.write(this, PickleUtils.OPCODE_NEXT_BUFFER); if (readOnly) { - write(this, pickler, PickleUtils.OPCODE_READONLY_BUFFER); + pickler.write(this, PickleUtils.OPCODE_READONLY_BUFFER); } } } @@ -2250,11 +2254,11 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, // Generate an EXT opcode if (code <= 0xff) { - writeByteOp(this, pickler, PickleUtils.OPCODE_EXT1, code); + pickler.writeByteOp(this, PickleUtils.OPCODE_EXT1, code); } else if (code <= 0xffff) { - writeShortOp(this, pickler, PickleUtils.OPCODE_EXT2, code); + pickler.writeShortOp(this, PickleUtils.OPCODE_EXT2, code); } else { - writeIntOp(this, pickler, PickleUtils.OPCODE_EXT4, code); + pickler.writeIntOp(this, PickleUtils.OPCODE_EXT4, code); } } } else { @@ -2271,14 +2275,14 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, if (proto >= 4) { save(frame, pickler, moduleName, 0); save(frame, pickler, globalName, 0); - write(this, pickler, PickleUtils.OPCODE_STACK_GLOBAL); + pickler.write(this, PickleUtils.OPCODE_STACK_GLOBAL); } else if (parent != module) { Object reduceValue = createTuple(st.getattr, createTuple(parent, lastname)); saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, null); } else { // Generate a normal global opcode if we are using a pickle protocol < 4, or if // the object is not registered in the extension registry - write(this, pickler, PickleUtils.OPCODE_GLOBAL); + pickler.write(this, PickleUtils.OPCODE_GLOBAL); // For protocol < 3 and if the user didn't request against doing so, we convert // module names to the old 2.x module names. if (proto < 3 && pickler.fixImports) { @@ -2296,19 +2300,19 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, TS_ENCODING) == TruffleString.CodeRange.BROKEN) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); } - writeUtf8(this, pickler, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); - write(this, pickler, (byte) '\n'); - writeUtf8(this, pickler, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeUtf8(this, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.write(this, (byte) '\n'); + pickler.writeUtf8(this, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } else { if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) != TruffleString.CodeRange.ASCII || ensureTsGetCodeRangeNode().execute(globalName, TS_ENCODING) != TruffleString.CodeRange.ASCII) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); } - writeASCII(this, pickler, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); - write(this, pickler, (byte) '\n'); - writeASCII(this, pickler, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.write(this, (byte) '\n'); + pickler.writeASCII(this, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } - write(this, pickler, (byte) '\n'); + pickler.write(this, (byte) '\n'); } // Memoize the object memoPut(pickler, proto, fastMode, obj); @@ -2544,7 +2548,7 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, assert pickler.proto <= 256; try { - SaveNode.write(this, pickler, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); + pickler.write(this, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); } catch (Exception e) { SaveNode.handleError(pickler); throw e; @@ -2556,7 +2560,7 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, } saveNode.execute(frame, pickler, obj, 0); - SaveNode.write(this, pickler, PickleUtils.OPCODE_STOP); + pickler.write(this, PickleUtils.OPCODE_STOP); pickler.commitFrame(); } finally { pickler.framing = false; From 6ebccfe1a3a4d0b32580f09a2f55c5ba0f788047 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 13:22:31 +0200 Subject: [PATCH 090/129] Get rid of PPickler.maxOutputLen (cherry picked from commit 7bfa0b69dc73edc654a5496c409ad4d57a83dd14) --- .../builtins/modules/pickle/PPickler.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 646f5f925a..ce6beb5fba 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -164,8 +164,6 @@ public class PPickler extends PythonBuiltinObject { private byte[] outputBuffer; // Length of output_buffer private int outputLen; - // Allocation size of output_buffer - private int maxOutputLen; // Pickle protocol number, >= 0 private int proto; // true if proto > 0 @@ -203,12 +201,11 @@ public PPickler(Object cls, Shape instanceShape, int outputCapacity, int memoCap fast = 0; fastNesting = 0; fixImports = false; - maxOutputLen = outputCapacity; outputLen = 0; reducerOverride = null; memo = new MemoTable(memoCapacity); - outputBuffer = new byte[maxOutputLen]; + outputBuffer = new byte[outputCapacity]; } @TruffleBoundary @@ -265,7 +262,7 @@ public MemoTable getMemo() { } public int getMaxOutputLen() { - return maxOutputLen; + return outputBuffer.length; } public void setMemo(MemoTable memo) { @@ -350,8 +347,7 @@ public void initInternals(VirtualFrame frame, Node inliningTarget, PyObjectLooku this.outputLen = 0; if (this.outputBuffer == null) { - this.maxOutputLen = PickleUtils.WRITE_BUF_SIZE; - this.outputBuffer = new byte[this.maxOutputLen]; + this.outputBuffer = new byte[PickleUtils.WRITE_BUF_SIZE]; } this.fast = 0; @@ -372,7 +368,7 @@ public void clearMemo() { } public void clearBuffer() { - this.outputBuffer = new byte[this.maxOutputLen]; + this.outputBuffer = new byte[this.outputBuffer.length]; this.outputLen = 0; this.frameStart = -1; } @@ -501,15 +497,15 @@ private void ensureBufferSpace(Node node, int dataLen) { int n = CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; int required = outputLen + n; - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, required > maxOutputLen)) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, required > outputBuffer.length)) { // Make place in buffer for the pickle chunk // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, outputLen >= Integer.MAX_VALUE / 2 - n)) { CompilerDirectives.transferToInterpreter(); throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); } - maxOutputLen = (outputLen + n) / 2 * 3; - outputBuffer = PythonUtils.arrayCopyOf(outputBuffer, maxOutputLen); + int newCapacity = (required) / 2 * 3; + outputBuffer = PythonUtils.arrayCopyOf(outputBuffer, newCapacity); } if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame)) { frameStart = outputLen; From d343210f72244ca4f9f755de5b0787a10e40712c Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 14:16:05 +0200 Subject: [PATCH 091/129] Get rid of ByteArrayView (cherry picked from commit 5f78bd2280cad5722fa03191de0711da250fdf12) --- .../modules/pickle/ByteArrayView.java | 105 ------------------ .../builtins/modules/pickle/PPickler.java | 8 +- .../builtins/modules/pickle/PUnpickler.java | 101 ++++++++--------- .../builtins/modules/pickle/PickleUtils.java | 17 ++- .../builtins/modules/pickle/PicklerNodes.java | 5 +- .../builtins/objects/ints/IntNodes.java | 26 +++-- 6 files changed, 80 insertions(+), 182 deletions(-) delete mode 100644 graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/ByteArrayView.java diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/ByteArrayView.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/ByteArrayView.java deleted file mode 100644 index 34dd8b26cf..0000000000 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/ByteArrayView.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2024, 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.builtins.modules.pickle; - -import com.oracle.graal.python.util.PythonUtils; - -public class ByteArrayView { - private final byte[] bytes; - private int offset; - - public ByteArrayView(byte[] bytes) { - this(bytes, 0); - } - - public ByteArrayView(byte[] bytes, int offset) { - this.bytes = bytes; - this.offset = offset; - validateOffset(0); - } - - private void validateOffset(int n) { - assert offset + n >= 0 && offset + n <= bytes.length; - } - - public void add(int n) { - validateOffset(n); - this.offset += n; - } - - public void sub(int n) { - this.add(-n); - } - - public byte[] getBytes(int len) { - assert len >= 0 && (len + offset) >= 0 && (len + offset) <= bytes.length; - if (offset == 0 && len == bytes.length) { - return bytes; - } - byte[] arr = new byte[len]; - PythonUtils.arraycopy(this.bytes, this.offset, arr, 0, len); - return arr; - } - - public int getOffset() { - return offset; - } - - public byte get(int i) { - return this.bytes[this.offset + i]; - } - - public int getUnsigned(int i) { - return get(i) & 0xff; - } - - public void put(int i, byte value) { - this.bytes[this.offset + i] = value; - } - - public void writeSize64(int value) { - PickleUtils.writeSize64(bytes, offset, value); - } - - public void memmove(int off, int num) { - PythonUtils.arraycopy(this.bytes, this.offset + off, this.bytes, this.offset, num); - } -} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index ce6beb5fba..73114ca26d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -379,13 +379,11 @@ public void commitFrame() { } int frameLen = outputLen - frameStart - PickleUtils.FRAME_HEADER_SIZE; - ByteArrayView qdata = new ByteArrayView(outputBuffer, frameStart); if (frameLen >= PickleUtils.FRAME_SIZE_MIN) { - qdata.put(0, PickleUtils.OPCODE_FRAME); - qdata.add(1); - qdata.writeSize64(frameLen); + outputBuffer[frameStart] = PickleUtils.OPCODE_FRAME; + PickleUtils.writeSize64(outputBuffer, frameStart + 1, frameLen); } else { - qdata.memmove(PickleUtils.FRAME_HEADER_SIZE, frameLen); + PythonUtils.arraycopy(outputBuffer, frameStart + PickleUtils.FRAME_HEADER_SIZE, outputBuffer, frameStart, frameLen); outputLen -= PickleUtils.FRAME_HEADER_SIZE; } frameStart = -1; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index 85ab4c5bba..0b437491b9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -534,19 +534,20 @@ protected int readFromFile(VirtualFrame frame, PUnpickler self, int n) { } protected byte read(VirtualFrame frame, PUnpickler self) { - return read(frame, self, 1).get(0); + int offset = read(frame, self, 1); + return self.inputBuffer[offset]; } - protected ByteArrayView read(VirtualFrame frame, PUnpickler self, int n) { + protected int read(VirtualFrame frame, PUnpickler self, int n) { if (n <= self.inputLen - self.nextReadIdx) { - ByteArrayView bytesView = new ByteArrayView(self.inputBuffer, self.nextReadIdx); + int offset = self.nextReadIdx; self.nextReadIdx += n; - return bytesView; + return offset; } return readImpl(frame, self, n); } - private ByteArrayView readImpl(VirtualFrame frame, PUnpickler self, int n) { + private int readImpl(VirtualFrame frame, PUnpickler self, int n) { int numRead; // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX if (self.nextReadIdx > Integer.MAX_VALUE - 1) { @@ -563,7 +564,7 @@ private ByteArrayView readImpl(VirtualFrame frame, PUnpickler self, int n) { throw badReadLine(); } self.nextReadIdx = n; - return new ByteArrayView(self.inputBuffer); + return 0; } protected int readInto(VirtualFrame frame, PUnpickler self, byte[] buffer) { @@ -722,12 +723,12 @@ protected boolean isTuple(Object object) { return tupleCheck.execute(object); } - protected Object longFromBytes(byte[] data, boolean littleEndian) { + protected Object longFromBytes(byte[] data, int offset, int length, boolean littleEndian) { if (pyLongFromByteArray == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); pyLongFromByteArray = insert(IntNodesFactory.PyLongFromByteArrayNodeGen.create()); } - return pyLongFromByteArray.executeCached(data, littleEndian, true); + return pyLongFromByteArray.executeCached(data, offset, length, littleEndian, true); } protected void setAttribute(VirtualFrame frame, Object object, Object key, Object value) { @@ -809,11 +810,11 @@ void loadNone(PUnpickler self) { pDataPush(self, PNone.NONE); } - private static long calcBinInt(ByteArrayView s, int nBytes) { + private static long calcBinInt(byte[] s, int offset, int nBytes) { long x = 0; for (int i = 0; i < nBytes; i++) { - x |= (long) s.getUnsigned(i) << (8 * i); + x |= (long) (s[offset + i] & 0xff) << (8 * i); } // Unlike BININT1 and BININT2, BININT (more accurately BININT4) is signed, so on a box @@ -826,7 +827,7 @@ private static long calcBinInt(ByteArrayView s, int nBytes) { return x; } - private int calcBinSize(ByteArrayView s, int nbytes) { + private int calcBinSize(byte[] s, int offset, int nbytes) { int i; int x = 0; int n = nbytes; @@ -836,7 +837,7 @@ private int calcBinSize(ByteArrayView s, int nbytes) { // Check for integer overflow. BINBYTES8 and BINUNICODE8 opcodes have 64-bit size // that can't be represented on 32-bit platform. for (i = Integer.BYTES; i < n; i++) { - if (s.get(i) != 0) { + if (s[offset + i] != 0) { throw raise(PythonBuiltinClassType.OverflowError); } } @@ -844,7 +845,7 @@ private int calcBinSize(ByteArrayView s, int nbytes) { } for (i = 0; i < n; i++) { - x |= s.getUnsigned(i) << (8 * i); + x |= (s[offset + i] & 0xff) << (8 * i); } // TODO: GR-24978 check for PY_SSIZE_T_MAX (see: _cpickle.c:calc_binsize) @@ -855,24 +856,24 @@ private int calcBinSize(ByteArrayView s, int nbytes) { return x; } - private void loadBinIntX(PUnpickler self, ByteArrayView s, int size) { - long x = calcBinInt(s, size); + private void loadBinIntX(PUnpickler self, int offset, int size) { + long x = calcBinInt(self.inputBuffer, offset, size); pDataPush(self, x); } private void loadBinInt(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 4); - loadBinIntX(self, s, 4); + int offset = read(frame, self, 4); + loadBinIntX(self, offset, 4); } private void loadBinInt1(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 1); - loadBinIntX(self, s, 1); + int offset = read(frame, self, 1); + loadBinIntX(self, offset, 1); } private void loadBinInt2(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 2); - loadBinIntX(self, s, 2); + int offset = read(frame, self, 2); + loadBinIntX(self, offset, 2); } private void loadInt(VirtualFrame frame, PUnpickler self) { @@ -922,8 +923,8 @@ private void loadLong(VirtualFrame frame, PUnpickler self) { private void loadCountedLong(VirtualFrame frame, PUnpickler self, int n) { assert n == 1 || n == 4; int size = n; - final ByteArrayView nbytes = read(frame, self, size); - size = (int) calcBinInt(nbytes, size); + int sizeOffset = read(frame, self, size); + size = (int) calcBinInt(self.inputBuffer, sizeOffset, size); Object value; @@ -935,8 +936,8 @@ private void loadCountedLong(VirtualFrame frame, PUnpickler self, int n) { value = 0L; } else { // Read the raw little-endian bytes and convert. - final ByteArrayView pdata = read(frame, self, size); - value = longFromBytes(pdata.getBytes(size), true); + int dataOffset = read(frame, self, size); + value = longFromBytes(self.inputBuffer, dataOffset, size, true); } pDataPush(self, value); } @@ -956,15 +957,15 @@ private void loadFloat(VirtualFrame frame, PUnpickler self) { private void loadBinFloat(VirtualFrame frame, PUnpickler self) { Object value; - ByteArrayView s = read(frame, self, 8); + int offset = read(frame, self, 8); - value = NumericSupport.bigEndian().getDouble(s.getBytes(Double.BYTES), 0); + value = NumericSupport.bigEndian().getDouble(self.inputBuffer, offset); pDataPush(self, value); } private void loadCountedBinBytes(VirtualFrame frame, PUnpickler self, int nbytes) { - final ByteArrayView s = read(frame, self, nbytes); - int size = calcBinSize(s, nbytes); + int offset = read(frame, self, nbytes); + int size = calcBinSize(self.inputBuffer, offset, nbytes); if (size < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BINBYTES", Integer.MAX_VALUE); } @@ -977,8 +978,8 @@ private void loadCountedBinBytes(VirtualFrame frame, PUnpickler self, int nbytes } private void loadCountedByteArray(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 8); - int size = calcBinSize(s, 8); + int offset = read(frame, self, 8); + int size = calcBinSize(self.inputBuffer, offset, 8); if (size < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BYTEARRAY8", Integer.MAX_VALUE); } @@ -1025,18 +1026,18 @@ private void loadReadOnlyBuffer(VirtualFrame frame, PUnpickler self) { private void loadCountedBinString(VirtualFrame frame, PUnpickler self, int nbytes) { Object obj; - ByteArrayView s = read(frame, self, nbytes); + int offset = read(frame, self, nbytes); - int size = calcBinSize(s, nbytes); + int size = calcBinSize(self.inputBuffer, offset, nbytes); if (size < 0) { throw raise(PythonBuiltinClassType.UnpicklingError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BINSTRING", Integer.MAX_VALUE); } - s = read(frame, self, size); + offset = read(frame, self, size); // Convert Python 2.x strings to bytes if the *encoding* given to the Unpickler was // 'bytes'. Otherwise, convert them to unicode. - final PBytes bytes = PFactory.createBytes(PythonLanguage.get(this), s.getBytes(size), size); + final PBytes bytes = PFactory.createBytes(PythonLanguage.get(this), PythonUtils.arrayCopyOfRange(self.inputBuffer, offset, offset + size)); if (ensureTsEqualNode().execute(self.encoding, T_CODEC_BYTES, TS_ENCODING)) { obj = bytes; } else { @@ -1095,16 +1096,16 @@ private void loadUnicode(VirtualFrame frame, PUnpickler self) { private void loadBinCountedUnicode(VirtualFrame frame, PUnpickler self, int nbytes) { Object str; - ByteArrayView s = read(frame, self, nbytes); + int offset = read(frame, self, nbytes); - int size = calcBinSize(s, nbytes); + int size = calcBinSize(self.inputBuffer, offset, nbytes); if (size < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BINUNICODE", Integer.MAX_VALUE); } - s = read(frame, self, size); + offset = read(frame, self, size); - str = decodeUTF8(frame, s, size, T_ERRORS_SURROGATEPASS); + str = decodeUTF8(frame, self.inputBuffer, offset, size, T_ERRORS_SURROGATEPASS); pDataPush(self, str); } @@ -1499,8 +1500,8 @@ private void loadBinGet(VirtualFrame frame, PUnpickler self) { } private void loadLongBinGet(VirtualFrame frame, PUnpickler self) { - ByteArrayView s = read(frame, self, 4); - int idx = calcBinSize(s, 4); + int offset = read(frame, self, 4); + int idx = calcBinSize(self.inputBuffer, offset, 4); Object value = self.memoGet(idx); if (value == null) { @@ -1559,13 +1560,13 @@ private void loadBinPut(VirtualFrame frame, PUnpickler self) { } private void loadLongBinPut(VirtualFrame frame, PUnpickler self) { - ByteArrayView s = read(frame, self, 4); + int offset = read(frame, self, 4); if (self.stack.size <= self.stack.fence) { throw pDataStackRaiseUnderflow(self); } Object value = self.stack.data[self.stack.size - 1]; - int idx = calcBinSize(s, 4); + int idx = calcBinSize(self.inputBuffer, offset, 4); if (idx < 0) { throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.NEG_S_ARG, "LONG_BINPUT"); } @@ -1717,9 +1718,9 @@ private void loadReduce(VirtualFrame frame, PUnpickler self) { } private void loadProto(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 1); + int offset = read(frame, self, 1); - int i = s.getUnsigned(0); + int i = self.inputBuffer[offset] & 0xff; if (i <= PICKLE_PROTOCOL_HIGHEST) { self.proto = i; return; @@ -1729,14 +1730,14 @@ private void loadProto(VirtualFrame frame, PUnpickler self) { } private void loadFrame(VirtualFrame frame, PUnpickler self) { - ByteArrayView s = read(frame, self, 8); + int offset = read(frame, self, 8); - int frameLen = calcBinSize(s, 8); + int frameLen = calcBinSize(self.inputBuffer, offset, 8); if (frameLen < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "FRAME", Integer.MAX_VALUE); } - s = read(frame, self, frameLen); + read(frame, self, frameLen); // Rewind to start of frame self.nextReadIdx -= frameLen; @@ -1745,9 +1746,9 @@ private void loadFrame(VirtualFrame frame, PUnpickler self) { private void loadExtension(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self, int nbytes) { assert (nbytes == 1 || nbytes == 2 || nbytes == 4); // the nbytes bytes after the opcode - ByteArrayView codebytes = read(frame, self, nbytes); + int codeOffset = read(frame, self, nbytes); // calc_binint returns long - long code = calcBinInt(codebytes, nbytes); + long code = calcBinInt(self.inputBuffer, codeOffset, nbytes); if (code <= 0) { // note that 0 is forbidden diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java index 772d2abc95..193840a77b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java @@ -61,7 +61,6 @@ import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -214,15 +213,15 @@ public final class PickleUtils { public static final TruffleString T_PROTO_LE2_TRUE = tsLiteral("I01\n"); public static final TruffleString T_PROTO_LE2_FALSE = tsLiteral("I00\n"); - @ExplodeLoop public static void writeSize64(byte[] out, int start, int value) { - final int sizeofSizeT = Integer.BYTES; - for (int i = 0; i < sizeofSizeT; i++) { - out[start + i] = (byte) ((value >> (8 * i)) & 0xff); - } - for (int i = sizeofSizeT; i < 8; i++) { - out[start + i] = 0; - } + out[start] = (byte) value; + out[start + 1] = (byte) (value >> 8); + out[start + 2] = (byte) (value >> 16); + out[start + 3] = (byte) (value >> 24); + out[start + 4] = 0; + out[start + 5] = 0; + out[start + 6] = 0; + out[start + 7] = 0; } public static int getStringSize(byte[] bytes) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 203d7ea33b..2c1292c6cf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -102,6 +102,7 @@ import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; +import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; @@ -326,8 +327,8 @@ protected Object decodeASCII(VirtualFrame frame, byte[] bytes, int len, TruffleS return decode(frame, PFactory.createBytes(PythonLanguage.get(this), bytes, len), T_CODEC_ASCII, errors); } - protected Object decodeUTF8(VirtualFrame frame, ByteArrayView bytes, int len, TruffleString errors) { - return decode(frame, PFactory.createBytes(PythonLanguage.get(this), bytes.getBytes(len), len), T_UTF8, errors); + protected Object decodeUTF8(VirtualFrame frame, byte[] bytes, int offset, int len, TruffleString errors) { + return decode(frame, PFactory.createBytes(PythonLanguage.get(this), PythonUtils.arrayCopyOfRange(bytes, offset, offset + len)), T_UTF8, errors); } protected Object decode(VirtualFrame frame, Object value, TruffleString encoding) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java index 4cd53ffff2..fd4f0cdae8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.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 @@ -181,10 +181,14 @@ static byte[] doPInt(Node inliningTarget, PInt value, int size, boolean bigEndia @GenerateInline(inlineByDefault = true) @GenerateUncached public abstract static class PyLongFromByteArray extends Node { - public abstract Object execute(Node inliningTarget, byte[] data, boolean littleEndian, boolean signed); + public abstract Object execute(Node inliningTarget, byte[] data, int offset, int length, boolean littleEndian, boolean signed); - public final Object executeCached(byte[] data, boolean littleEndian, boolean signed) { - return execute(this, data, littleEndian, signed); + public final Object execute(Node inliningTarget, byte[] data, boolean littleEndian, boolean signed) { + return execute(inliningTarget, data, 0, data.length, littleEndian, signed); + } + + public final Object executeCached(byte[] data, int offset, int length, boolean littleEndian, boolean signed) { + return execute(this, data, offset, length, littleEndian, signed); } public static Object executeUncached(byte[] data, boolean littleEndian, boolean signed) { @@ -192,7 +196,7 @@ public static Object executeUncached(byte[] data, boolean littleEndian, boolean } @Specialization - static Object doOther(Node inliningTarget, byte[] data, boolean littleEndian, boolean signed, + static Object doOther(Node inliningTarget, byte[] data, int offset, int length, boolean littleEndian, boolean signed, @Cached InlinedBranchProfile fastPath1, @Cached InlinedBranchProfile fastPath2, @Cached InlinedBranchProfile fastPath4, @@ -201,28 +205,28 @@ static Object doOther(Node inliningTarget, byte[] data, boolean littleEndian, bo @Cached PRaiseNode raiseNode) { NumericSupport support = littleEndian ? NumericSupport.littleEndian() : NumericSupport.bigEndian(); if (signed) { - switch (data.length) { + switch (length) { case 1 -> { fastPath1.enter(inliningTarget); - return (int) support.getByte(data, 0); + return (int) support.getByte(data, offset); } case 2 -> { fastPath2.enter(inliningTarget); - return (int) support.getShort(data, 0); + return (int) support.getShort(data, offset); } case 4 -> { fastPath4.enter(inliningTarget); - return support.getInt(data, 0); + return support.getInt(data, offset); } case 8 -> { fastPath8.enter(inliningTarget); - return support.getLong(data, 0); + return support.getLong(data, offset); } } } generic.enter(inliningTarget); try { - BigInteger integer = support.getBigInteger(data, signed); + BigInteger integer = support.getBigInteger(data, offset, length, signed); if (PInt.bigIntegerFitsInLong(integer)) { long longValue = PInt.longValue(integer); return PInt.isIntRange(longValue) ? (int) longValue : longValue; From f5463a1f789d10523b1ad246f8fa8af2013e7d6a Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 14:21:54 +0200 Subject: [PATCH 092/129] Add unpickler fast path for decoding UTF-8 (cherry picked from commit eb14674fa644f8492ee58bc62ef7056382ef8817) --- .../builtins/modules/pickle/PicklerNodes.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 2c1292c6cf..70c443df35 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -154,6 +154,7 @@ abstract static class BasePickleNode extends Node { @Child private TruffleString.SubstringNode tsSubstringNode; @Child private TruffleString.EqualNode tsEqualNode; @Child private TruffleString.SwitchEncodingNode tsSwitchEncodingNode; + @Child private TruffleString.IsValidNode tsIsValidNode; @Child private HashingStorageGetIterator getHashingStorageIteratorNode; @Child private HashingStorageIteratorNext hashingStorageItNext; @Child private HashingStorageIteratorKey hashingStorageItKey; @@ -231,6 +232,14 @@ protected TruffleString.SwitchEncodingNode ensureTsSwitchEncodingNode() { return tsSwitchEncodingNode; } + protected TruffleString.IsValidNode ensureTsIsValidNode() { + if (tsIsValidNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + tsIsValidNode = insert(TruffleString.IsValidNode.create()); + } + return tsIsValidNode; + } + protected byte[] toBytes(VirtualFrame frame, Object obj) { if (toBytesNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -328,6 +337,10 @@ protected Object decodeASCII(VirtualFrame frame, byte[] bytes, int len, TruffleS } protected Object decodeUTF8(VirtualFrame frame, byte[] bytes, int offset, int len, TruffleString errors) { + TruffleString utf8 = ensureTsFromByteArray().execute(bytes, offset, len, TruffleString.Encoding.UTF_8, true); + if (ensureTsIsValidNode().execute(utf8, TruffleString.Encoding.UTF_8)) { + return ensureTsSwitchEncodingNode().execute(utf8, TS_ENCODING); + } return decode(frame, PFactory.createBytes(PythonLanguage.get(this), PythonUtils.arrayCopyOfRange(bytes, offset, offset + len)), T_UTF8, errors); } From c459167379b513d93ac5fc2659722c89b7797258 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 14:27:55 +0200 Subject: [PATCH 093/129] Add profiling for seen unpickler opcodes (cherry picked from commit 9e2d6e5c632f500489909c4d3a23be3d9b3b1c81) --- .../builtins/modules/pickle/PUnpickler.java | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index 0b437491b9..2fa8f5f11a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -183,6 +183,7 @@ import com.oracle.graal.python.util.NumericSupport; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; @@ -684,6 +685,78 @@ Object find(VirtualFrame frame, PUnpickler unpickler, TruffleString module, Truf } public abstract static class LoadNode extends BasePickleReadNode { + private static final int SEEN_NONE = 0; + private static final int SEEN_BININT = 1; + private static final int SEEN_BININT1 = 2; + private static final int SEEN_BININT2 = 3; + private static final int SEEN_INT = 4; + private static final int SEEN_LONG = 5; + private static final int SEEN_LONG1 = 6; + private static final int SEEN_LONG4 = 7; + private static final int SEEN_FLOAT = 8; + private static final int SEEN_BINFLOAT = 9; + private static final int SEEN_SHORT_BINBYTES = 10; + private static final int SEEN_BINBYTES = 11; + private static final int SEEN_BINBYTES8 = 12; + private static final int SEEN_BYTEARRAY8 = 13; + private static final int SEEN_NEXT_BUFFER = 14; + private static final int SEEN_READONLY_BUFFER = 15; + private static final int SEEN_SHORT_BINSTRING = 16; + private static final int SEEN_BINSTRING = 17; + private static final int SEEN_STRING = 18; + private static final int SEEN_UNICODE = 19; + private static final int SEEN_SHORT_BINUNICODE = 20; + private static final int SEEN_BINUNICODE = 21; + private static final int SEEN_BINUNICODE8 = 22; + private static final int SEEN_EMPTY_TUPLE = 23; + private static final int SEEN_TUPLE1 = 24; + private static final int SEEN_TUPLE2 = 25; + private static final int SEEN_TUPLE3 = 26; + private static final int SEEN_TUPLE = 27; + private static final int SEEN_EMPTY_LIST = 28; + private static final int SEEN_LIST = 29; + private static final int SEEN_EMPTY_DICT = 30; + private static final int SEEN_DICT = 31; + private static final int SEEN_EMPTY_SET = 32; + private static final int SEEN_ADDITEMS = 33; + private static final int SEEN_FROZENSET = 34; + private static final int SEEN_OBJ = 35; + private static final int SEEN_INST = 36; + private static final int SEEN_NEWOBJ = 37; + private static final int SEEN_NEWOBJ_EX = 38; + private static final int SEEN_GLOBAL = 39; + private static final int SEEN_STACK_GLOBAL = 40; + private static final int SEEN_APPEND = 41; + private static final int SEEN_APPENDS = 42; + private static final int SEEN_BUILD = 43; + private static final int SEEN_DUP = 44; + private static final int SEEN_BINGET = 45; + private static final int SEEN_LONG_BINGET = 46; + private static final int SEEN_GET = 47; + private static final int SEEN_MARK = 48; + private static final int SEEN_BINPUT = 49; + private static final int SEEN_LONG_BINPUT = 50; + private static final int SEEN_PUT = 51; + private static final int SEEN_MEMOIZE = 52; + private static final int SEEN_POP = 53; + private static final int SEEN_POP_MARK = 54; + private static final int SEEN_SETITEM = 55; + private static final int SEEN_SETITEMS = 56; + private static final int SEEN_PERSID = 57; + private static final int SEEN_BINPERSID = 58; + private static final int SEEN_REDUCE = 59; + private static final int SEEN_PROTO = 60; + private static final int SEEN_FRAME = 61; + private static final int SEEN_EXT1 = 62; + private static final int SEEN_EXT2 = 63; + private static final int SEEN_EXT4 = 64; + private static final int SEEN_NEWTRUE = 65; + private static final int SEEN_NEWFALSE = 66; + private static final int SEEN_STOP = 67; + + @CompilationFinal private long seenOpcodes0; + @CompilationFinal private long seenOpcodes1; + @Child private PData.PDataPushNode pDataPushNode; @Child private PData.PDataPopNode pDataPopNode; @Child private PData.PDataPopTupleNode pDataPopTupleNode; @@ -699,6 +772,22 @@ public abstract static class LoadNode extends BasePickleReadNode { public abstract Object execute(VirtualFrame frame, PUnpickler self); + private void profileSeen(int seen) { + if (seen < Long.SIZE) { + long mask = 1L << seen; + if ((seenOpcodes0 & mask) == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenOpcodes0 |= mask; + } + } else { + long mask = 1L << (seen - Long.SIZE); + if ((seenOpcodes1 & mask) == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenOpcodes1 |= mask; + } + } + } + protected HashingStorageCopy ensureHashingStorageCopy() { if (hashCopy == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -1829,207 +1918,275 @@ public Object load(VirtualFrame frame, PUnpickler self, } switch (s) { case OPCODE_NONE: + profileSeen(SEEN_NONE); loadNone(self); continue; case OPCODE_BININT: + profileSeen(SEEN_BININT); loadBinInt(frame, self); continue; case OPCODE_BININT1: + profileSeen(SEEN_BININT1); loadBinInt1(frame, self); continue; case OPCODE_BININT2: + profileSeen(SEEN_BININT2); loadBinInt2(frame, self); continue; case OPCODE_INT: + profileSeen(SEEN_INT); loadInt(frame, self); continue; case OPCODE_LONG: + profileSeen(SEEN_LONG); loadLong(frame, self); continue; case OPCODE_LONG1: + profileSeen(SEEN_LONG1); loadCountedLong(frame, self, 1); continue; case OPCODE_LONG4: + profileSeen(SEEN_LONG4); loadCountedLong(frame, self, 4); continue; case OPCODE_FLOAT: + profileSeen(SEEN_FLOAT); loadFloat(frame, self); continue; case OPCODE_BINFLOAT: + profileSeen(SEEN_BINFLOAT); loadBinFloat(frame, self); continue; case OPCODE_SHORT_BINBYTES: + profileSeen(SEEN_SHORT_BINBYTES); loadCountedBinBytes(frame, self, 1); continue; case OPCODE_BINBYTES: + profileSeen(SEEN_BINBYTES); loadCountedBinBytes(frame, self, 4); continue; case OPCODE_BINBYTES8: + profileSeen(SEEN_BINBYTES8); loadCountedBinBytes(frame, self, 8); continue; case OPCODE_BYTEARRAY8: + profileSeen(SEEN_BYTEARRAY8); loadCountedByteArray(frame, self); continue; case OPCODE_NEXT_BUFFER: + profileSeen(SEEN_NEXT_BUFFER); loadNextBuffer(frame, self); continue; case OPCODE_READONLY_BUFFER: + profileSeen(SEEN_READONLY_BUFFER); loadReadOnlyBuffer(frame, self); continue; case OPCODE_SHORT_BINSTRING: + profileSeen(SEEN_SHORT_BINSTRING); loadCountedBinString(frame, self, 1); continue; case OPCODE_BINSTRING: + profileSeen(SEEN_BINSTRING); loadCountedBinString(frame, self, 4); continue; case OPCODE_STRING: + profileSeen(SEEN_STRING); loadString(frame, self); continue; case OPCODE_UNICODE: + profileSeen(SEEN_UNICODE); loadUnicode(frame, self); continue; case OPCODE_SHORT_BINUNICODE: + profileSeen(SEEN_SHORT_BINUNICODE); loadBinCountedUnicode(frame, self, 1); continue; case OPCODE_BINUNICODE: + profileSeen(SEEN_BINUNICODE); loadBinCountedUnicode(frame, self, 4); continue; case OPCODE_BINUNICODE8: + profileSeen(SEEN_BINUNICODE8); loadBinCountedUnicode(frame, self, 8); continue; case OPCODE_EMPTY_TUPLE: + profileSeen(SEEN_EMPTY_TUPLE); loadCountedTuple(self, 0); continue; case OPCODE_TUPLE1: + profileSeen(SEEN_TUPLE1); loadCountedTuple(self, 1); continue; case OPCODE_TUPLE2: + profileSeen(SEEN_TUPLE2); loadCountedTuple(self, 2); continue; case OPCODE_TUPLE3: + profileSeen(SEEN_TUPLE3); loadCountedTuple(self, 3); continue; case OPCODE_TUPLE: + profileSeen(SEEN_TUPLE); loadTuple(self); continue; case OPCODE_EMPTY_LIST: + profileSeen(SEEN_EMPTY_LIST); loadEmptyList(self); continue; case OPCODE_LIST: + profileSeen(SEEN_LIST); loadList(self); continue; case OPCODE_EMPTY_DICT: + profileSeen(SEEN_EMPTY_DICT); loadEmptyDict(self); continue; case OPCODE_DICT: + profileSeen(SEEN_DICT); loadDict(frame, self); continue; case OPCODE_EMPTY_SET: + profileSeen(SEEN_EMPTY_SET); loadEmptySet(self); continue; case OPCODE_ADDITEMS: + profileSeen(SEEN_ADDITEMS); loadAddItems(frame, self); continue; case OPCODE_FROZENSET: + profileSeen(SEEN_FROZENSET); loadFrozenSet(frame, self); continue; case OPCODE_OBJ: + profileSeen(SEEN_OBJ); loadObj(frame, inliningTarget, self, callMethod); continue; case OPCODE_INST: + profileSeen(SEEN_INST); loadInst(frame, inliningTarget, boundaryCallData, ctx, self, callMethod); continue; case OPCODE_NEWOBJ: + profileSeen(SEEN_NEWOBJ); loadNewObj(frame, inliningTarget, self, getSlots, callNew, expandArgs); continue; case OPCODE_NEWOBJ_EX: + profileSeen(SEEN_NEWOBJ_EX); loadNewObjEx(frame, inliningTarget, self, getSlots, callNew, expandArgs, expandKwargs); continue; case OPCODE_GLOBAL: + profileSeen(SEEN_GLOBAL); loadGlobal(frame, boundaryCallData, ctx, self); continue; case OPCODE_STACK_GLOBAL: + profileSeen(SEEN_STACK_GLOBAL); loadStackGlobal(frame, boundaryCallData, ctx, self); continue; case OPCODE_APPEND: + profileSeen(SEEN_APPEND); loadAppend(frame, self); continue; case OPCODE_APPENDS: + profileSeen(SEEN_APPENDS); loadAppends(frame, self); continue; case OPCODE_BUILD: + profileSeen(SEEN_BUILD); loadBuild(frame, self); continue; case OPCODE_DUP: + profileSeen(SEEN_DUP); loadDup(self); continue; case OPCODE_BINGET: + profileSeen(SEEN_BINGET); loadBinGet(frame, self); continue; case OPCODE_LONG_BINGET: + profileSeen(SEEN_LONG_BINGET); loadLongBinGet(frame, self); continue; case OPCODE_GET: + profileSeen(SEEN_GET); loadGet(frame, self); continue; case OPCODE_MARK: + profileSeen(SEEN_MARK); loadMark(self); continue; case OPCODE_BINPUT: + profileSeen(SEEN_BINPUT); loadBinPut(frame, self); continue; case OPCODE_LONG_BINPUT: + profileSeen(SEEN_LONG_BINPUT); loadLongBinPut(frame, self); continue; case OPCODE_PUT: + profileSeen(SEEN_PUT); loadPut(frame, self); continue; case OPCODE_MEMOIZE: + profileSeen(SEEN_MEMOIZE); loadMemoize(self); continue; case OPCODE_POP: + profileSeen(SEEN_POP); loadPop(self); continue; case OPCODE_POP_MARK: + profileSeen(SEEN_POP_MARK); loadPopMark(self); continue; case OPCODE_SETITEM: + profileSeen(SEEN_SETITEM); loadSetItem(frame, self); continue; case OPCODE_SETITEMS: + profileSeen(SEEN_SETITEMS); loadSetItems(frame, self); continue; case OPCODE_PERSID: + profileSeen(SEEN_PERSID); loadPersId(frame, self); continue; case OPCODE_BINPERSID: + profileSeen(SEEN_BINPERSID); loadBinPersId(frame, self); continue; case OPCODE_REDUCE: + profileSeen(SEEN_REDUCE); loadReduce(frame, self); continue; case OPCODE_PROTO: + profileSeen(SEEN_PROTO); loadProto(frame, self); continue; case OPCODE_FRAME: + profileSeen(SEEN_FRAME); loadFrame(frame, self); continue; case OPCODE_EXT1: + profileSeen(SEEN_EXT1); loadExtension(frame, boundaryCallData, ctx, self, 1); continue; case OPCODE_EXT2: + profileSeen(SEEN_EXT2); loadExtension(frame, boundaryCallData, ctx, self, 2); continue; case OPCODE_EXT4: + profileSeen(SEEN_EXT4); loadExtension(frame, boundaryCallData, ctx, self, 4); continue; case OPCODE_NEWTRUE: + profileSeen(SEEN_NEWTRUE); loadBool(self, true); continue; case OPCODE_NEWFALSE: + profileSeen(SEEN_NEWFALSE); loadBool(self, false); continue; case OPCODE_STOP: + profileSeen(SEEN_STOP); break; default: if (0x20 <= s && s <= 0x7e && s != '\'' && s != '\\') { From eabe4be588c1d411b599fed811c2f3545da18642 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 14:37:34 +0200 Subject: [PATCH 094/129] Pre-size dictionaries when unpickling (cherry picked from commit 2102b34e2fb030166a4cfcacc8d19fc19eae9f38) --- .../graal/python/builtins/modules/pickle/PUnpickler.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index 2fa8f5f11a..32f19e5e26 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -1239,7 +1239,7 @@ private void loadDict(VirtualFrame frame, PUnpickler self) { throw raise(PythonBuiltinClassType.UnpicklingError, ErrorMessages.ODD_NR_ITEMS_FOR_S, "DICT"); } - HashingStorage storage = EmptyStorage.INSTANCE; + HashingStorage storage = PDict.createNewStorage((j - i) / 2); for (k = i + 1; k < j; k += 2) { key = self.stack.data[k - 1]; value = self.stack.data[k]; @@ -1736,6 +1736,9 @@ private void doSetItems(VirtualFrame frame, PUnpickler self, int x) { Object dict = self.stack.data[x - 1]; final boolean isBuiltinDict = dict instanceof PDict pDict && PGuards.isBuiltinDict(pDict); + if (isBuiltinDict && ((PDict) dict).getDictStorage() == EmptyStorage.INSTANCE) { + ((PDict) dict).setDictStorage(PDict.createNewStorage((len - x) / 2)); + } for (i = x + 1; i < len; i += 2) { key = self.stack.data[i - 1]; value = self.stack.data[i]; From b27fbaf49bc47a3786c5847e608d59da2b4f34d4 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 15:38:06 +0200 Subject: [PATCH 095/129] Add a few branch probabilities (cherry picked from commit 2212a831a8b2e7e24b2cbff8352eb2adffacbc73) --- .../graal/python/builtins/modules/pickle/PUnpickler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index 32f19e5e26..ed13b21d3e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -362,7 +362,7 @@ public Object memoGet(int idx) { } public void memoPut(int idx, Object value) { - if (idx >= memo.length) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, idx >= memo.length)) { resizeMemoList(idx * 2); assert idx < memo.length; } @@ -540,7 +540,7 @@ protected byte read(VirtualFrame frame, PUnpickler self) { } protected int read(VirtualFrame frame, PUnpickler self, int n) { - if (n <= self.inputLen - self.nextReadIdx) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, n <= self.inputLen - self.nextReadIdx)) { int offset = self.nextReadIdx; self.nextReadIdx += n; return offset; From f2e2e404ce0dd590274f6cd0465a2092de461532 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 15:44:09 +0200 Subject: [PATCH 096/129] Avoid copying buffer in pickle.loads (cherry picked from commit 16e83bf34bdf03185d37ba3666cd88d5919b6a6d) --- .../python/builtins/modules/pickle/PickleModuleBuiltins.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java index 6cc08bb72c..f58154dafd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java @@ -256,8 +256,8 @@ static Object loads(VirtualFrame frame, @SuppressWarnings("unused") PythonModule @Cached PyObjectGetIter getIter) { try { PUnpickler unpickler = PFactory.createUnpickler(language); - byte[] data = bufferLib.getCopiedByteArray(buffer); - unpickler.setStringInput(data, data.length); + byte[] data = bufferLib.getInternalOrCopiedByteArray(buffer); + unpickler.setStringInput(data, bufferLib.getBufferLength(buffer)); unpickler.setInputEncoding(encoding, errors); unpickler.setBuffers(frame, inliningTarget, getIter, buffers); unpickler.setFixImports(fixImports); From 22dd113967709a9e72ce4886572f37d9d006803f Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 19:05:17 +0200 Subject: [PATCH 097/129] Profile file reads in unpickle (cherry picked from commit 1a5c6500cda87a9f6010ffe6f0693d62a21ab440) --- .../graal/python/builtins/modules/pickle/PUnpickler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index ed13b21d3e..f534ad21d8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -406,6 +406,8 @@ public abstract static class BasePickleReadNode extends PicklerNodes.BasePickleN @Child private TruffleString.ParseIntNode tsParseIntNode; + @CompilationFinal private boolean seenFileRead; + // we only need the reference, doesn't matter that the object may not yet be fully // constructed @SuppressWarnings("this-escape") private InteropCallData interopCallData = InteropCallData.createFor(this); @@ -545,6 +547,10 @@ protected int read(VirtualFrame frame, PUnpickler self, int n) { self.nextReadIdx += n; return offset; } + if (!seenFileRead) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenFileRead = true; + } return readImpl(frame, self, n); } From 87630e222fa2ddf3eefb9b9ceba71198a05e2c38 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 21:03:39 +0200 Subject: [PATCH 098/129] Add fast paths for pickling/unpickling large longs (cherry picked from commit 3047bf54509bb294c09b9672755ddf8879943184) --- .../builtins/modules/pickle/PPickler.java | 100 ++++++------------ .../builtins/objects/ints/IntNodes.java | 28 +++++ 2 files changed, 63 insertions(+), 65 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 73114ca26d..77df6fbd65 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -55,7 +55,6 @@ import static com.oracle.graal.python.nodes.StringLiterals.T_NEWLINE; import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; -import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.PicklingError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; @@ -88,8 +87,6 @@ import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis; import com.oracle.graal.python.builtins.objects.floats.PFloat; import com.oracle.graal.python.builtins.objects.function.PFunction; -import com.oracle.graal.python.builtins.objects.ints.IntNodes; -import com.oracle.graal.python.builtins.objects.ints.IntNodesFactory; import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; @@ -627,9 +624,6 @@ public abstract static class SaveNode extends PicklerNodes.BasePickleNode { @Child private SaveNode recursiveSaveNode2; @Child private SaveNode recursiveSaveNode3; - @Child private IntNodes.PyLongSign pyLongSign; - @Child private IntNodes.PyLongNumBits pyLongNumBits; - @Child private IntNodes.PyLongAsByteArray pyLongAsByteArray; @Child private ListNodes.ConstructListNode constructListNode; @Child private TypeNodes.IsTypeNode isTypeNode; @Child private FlushToFileNode flushToFileNode; @@ -761,30 +755,6 @@ protected FlushToFileNode ensureFlushToFileNode() { return flushToFileNode; } - protected int getSign(Object value) { - if (pyLongSign == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - pyLongSign = insert(IntNodesFactory.PyLongSignNodeGen.create()); - } - return pyLongSign.execute(value); - } - - protected int getNumBits(Object value) { - if (pyLongNumBits == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - pyLongNumBits = insert(IntNodesFactory.PyLongNumBitsNodeGen.create()); - } - return pyLongNumBits.execute(value); - } - - protected byte[] longAsBytes(Object value, int size, boolean bigEndian) { - if (pyLongAsByteArray == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - pyLongAsByteArray = insert(IntNodesFactory.PyLongAsByteArrayNodeGen.create()); - } - return pyLongAsByteArray.executeCached(value, size, bigEndian); - } - protected Object createList(VirtualFrame frame, Object iterable) { if (constructListNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -1523,61 +1493,61 @@ private void saveLong(PPickler pickler, int proto, int value) { } } - private void saveLong(VirtualFrame frame, PPickler pickler, int proto, long value) { + private void saveLong(PPickler pickler, int proto, long value) { int intValue = (int) value; if (intValue == value) { saveLong(pickler, proto, intValue); } else { - saveLongLarge(frame, pickler, proto, value); + saveLongLarge(pickler, proto, value); } } private void saveLong(VirtualFrame frame, PPickler pickler, int proto, PInt value) { try { - saveLong(frame, pickler, proto, value.longValueExact()); + saveLong(pickler, proto, value.longValueExact()); } catch (OverflowException e) { saveLongLarge(frame, pickler, proto, value); } } - private void saveLongLarge(VirtualFrame frame, PPickler pickler, int proto, Object obj) { + private void saveLongLarge(PPickler pickler, int proto, long value) { if (proto >= 2) { - // Linear-time pickling. - final int sign = getSign(obj); - assert sign != 0; // Zero was handled by the int code above - - final int nbits = getNumBits(obj); - // How many bytes do we need? There are nbits >> 3 full bytes of data, and nbits & 7 - // leftover bits. If there are any leftover bits, then we clearly need another byte. - // What's not so obvious is that we *probably* need another byte even if there - // aren't any leftovers: the most-significant bit of the most-significant byte acts - // like a sign bit, and it's usually got a sense opposite of the one we need. The - // exception is ints of the form -(2**(8*j-1)) for j > 0. Such an int is its own - // 256's-complement, so has the right sign bit even without the extra byte. That's a - // pain to check for in advance, though, so we always grab an extra byte at the - // start, and cut it back later if possible. + // Count the significant bits excluding the sign extension, then add a sign bit. + int nbits = Long.SIZE - Long.numberOfLeadingZeros(value < 0 ? ~value : value); int nbytes = (nbits >> 3) + 1; - if (Long.compareUnsigned(nbytes, 0x7fffffffL) > 0) { - throw raise(OverflowError, ErrorMessages.S_TO_LARGE_TO_PICKLE, "int"); - } - byte[] pdata = longAsBytes(obj, nbytes, false); - // If the int is negative, this may be a byte more than needed. This is so iff the - // MSB is all redundant sign bits. - if (sign < 0 && nbytes > 1 && pdata[nbytes - 1] == (byte) 0xff && (pdata[nbytes - 2] & 0x80) != 0) { - nbytes--; + pickler.writeByteOp(this, PickleUtils.OPCODE_LONG1, nbytes); + pickler.ensureBufferSpace(this, nbytes); + for (int i = 0; i < nbytes; i++) { + pickler.outputBuffer[pickler.outputLen++] = (byte) value; + value >>= Byte.SIZE; } + } else { + TruffleString repr = ensureTsFromLongNode().execute(value, TS_ENCODING, true); + pickler.write(this, PickleUtils.OPCODE_LONG); + pickler.writeASCII(this, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_L_NEW_LINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + } + } + + private void saveLongLarge(VirtualFrame frame, PPickler pickler, int proto, PInt value) { + if (proto >= 2) { + // BigInteger already provides the minimal signed two's-complement representation. + byte[] data = value.toByteArray(); + int nbytes = data.length; if (nbytes < 256) { pickler.writeByteOp(this, PickleUtils.OPCODE_LONG1, nbytes); } else { pickler.writeIntOp(this, PickleUtils.OPCODE_LONG4, nbytes); } - - pickler.write(this, pdata, nbytes); - + pickler.ensureBufferSpace(this, nbytes); + // BigInteger's bytes are big endian; pickle requires little endian. + for (int i = nbytes - 1; i >= 0; i--) { + pickler.outputBuffer[pickler.outputLen++] = data[i]; + } } else { - TruffleString repr = repr(frame, obj); + TruffleString repr = repr(frame, value); pickler.write(this, PickleUtils.OPCODE_LONG); - pickler.writeASCII(this, asStringStrict(repr), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); pickler.writeASCII(this, T_L_NEW_LINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } @@ -1889,7 +1859,7 @@ private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceSto int proto = pickler.getProto(); if (storage.length() == 1) { opcodeBoundary(frame, pickler); - saveLong(frame, pickler, proto, storage.getLongItemNormalized(0)); + saveLong(pickler, proto, storage.getLongItemNormalized(0)); pickler.write(this, PickleUtils.OPCODE_APPEND); return; } @@ -1900,7 +1870,7 @@ private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceSto pickler.write(this, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { opcodeBoundary(frame, pickler); - saveLong(frame, pickler, proto, storage.getLongItemNormalized(i)); + saveLong(pickler, proto, storage.getLongItemNormalized(i)); } pickler.write(this, PickleUtils.OPCODE_APPENDS); } @@ -2002,7 +1972,7 @@ private void storeLongTupleElements(VirtualFrame frame, PPickler pickler, LongSe int proto = pickler.getProto(); for (int i = 0; i < storage.length(); i++) { opcodeBoundary(frame, pickler); - saveLong(frame, pickler, proto, storage.getLongItemNormalized(i)); + saveLong(pickler, proto, storage.getLongItemNormalized(i)); } } @@ -2348,7 +2318,7 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa return; } else if (obj instanceof Long value) { profileSeen(SEEN_LONG); - saveLong(frame, pickler, proto, value); + saveLong(pickler, proto, value); return; } else if (obj instanceof PInt value && PGuards.isBuiltinPInt(value)) { profileSeen(SEEN_PINT); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java index fd4f0cdae8..5767768938 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java @@ -201,6 +201,9 @@ static Object doOther(Node inliningTarget, byte[] data, int offset, int length, @Cached InlinedBranchProfile fastPath2, @Cached InlinedBranchProfile fastPath4, @Cached InlinedBranchProfile fastPath8, + @Cached InlinedBranchProfile variablePath, + @Cached InlinedBranchProfile fastPathVariable, + @Cached InlinedBranchProfile overlong, @Cached InlinedBranchProfile generic, @Cached PRaiseNode raiseNode) { NumericSupport support = littleEndian ? NumericSupport.littleEndian() : NumericSupport.bigEndian(); @@ -224,6 +227,31 @@ static Object doOther(Node inliningTarget, byte[] data, int offset, int length, } } } + variablePath.enter(inliningTarget); + int remaining = length; + int index = littleEndian ? offset + length - 1 : offset; + int step = littleEndian ? -1 : 1; + boolean negative = signed && length > 0 && data[index] < 0; + if (remaining > Long.BYTES) { + overlong.enter(inliningTarget); + // Ignore redundant sign or zero extension beyond the width of a long. + byte padding = (byte) (negative ? -1 : 0); + while (remaining > Long.BYTES && data[index] == padding) { + index += step; + remaining--; + } + } + // For eight bytes, the remaining sign bit must agree with the original sign. + // This also excludes unsigned values greater than Long.MAX_VALUE. + if (remaining < Long.BYTES || (remaining == Long.BYTES && (data[index] < 0) == negative)) { + fastPathVariable.enter(inliningTarget); + long value = negative ? -1L : 0L; + for (int i = 0; i < remaining; i++) { + value = (value << Byte.SIZE) | (data[index] & 0xffL); + index += step; + } + return value; + } generic.enter(inliningTarget); try { BigInteger integer = support.getBigInteger(data, offset, length, signed); From 3852462fc3b74a9adef45277aa3de34137654183 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 22:28:27 +0200 Subject: [PATCH 099/129] Avoid boundary in getDottedPath (cherry picked from commit 538816c84f61dfb0c6d3fdf478ddfdf327243b0b) --- .../builtins/modules/pickle/PicklerNodes.java | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 70c443df35..58eefbaac4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -46,7 +46,6 @@ import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; -import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; @@ -74,7 +73,6 @@ 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.function.PKeyword; -import com.oracle.graal.python.builtins.objects.str.StringUtils; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.lib.PyIterCheckNode; import com.oracle.graal.python.lib.PyIterNextNode; @@ -150,7 +148,7 @@ abstract static class BasePickleNode extends Node { @Child private TruffleString.FromByteArrayNode tsFromByteArrayNode; @Child private TruffleString.FromByteArrayWithCompactionUTF32Node tsFromByteArrayWithCompactionNode; @Child private TruffleString.CodePointLengthNode tsCodePointLengthNode; - @Child private TruffleString.IndexOfStringNode tsIndexOfStringNode; + @Child private TruffleString.IndexOfCodePointNode tsIndexOfCodePointNode; @Child private TruffleString.SubstringNode tsSubstringNode; @Child private TruffleString.EqualNode tsEqualNode; @Child private TruffleString.SwitchEncodingNode tsSwitchEncodingNode; @@ -200,12 +198,12 @@ protected TruffleString.CodePointLengthNode ensureTsCodePointLengthNode() { return tsCodePointLengthNode; } - protected TruffleString.IndexOfStringNode ensureTsIndexOfStringNode() { - if (tsIndexOfStringNode == null) { + protected TruffleString.IndexOfCodePointNode ensureTsIndexOfCodePointNode() { + if (tsIndexOfCodePointNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - tsIndexOfStringNode = insert(TruffleString.IndexOfStringNode.create()); + tsIndexOfCodePointNode = insert(TruffleString.IndexOfCodePointNode.create()); } - return tsIndexOfStringNode; + return tsIndexOfCodePointNode; } protected TruffleString.SubstringNode ensureTsSubstringNode() { @@ -574,9 +572,39 @@ public static Pair getDeepAttribute(VirtualFrame frame, PyObject return Pair.create(object, parent); } + private TruffleString[] splitDottedPath(TruffleString name) { + int length = ensureTsCodePointLengthNode().execute(name, TS_ENCODING); + TruffleString.IndexOfCodePointNode indexOf = ensureTsIndexOfCodePointNode(); + int firstDot = length == 0 ? -1 : indexOf.execute(name, '.', 0, length, TS_ENCODING); + if (firstDot < 0) { + return new TruffleString[]{name}; + } + + // Count the components so that we can allocate the result without growing or copying it. + int parts = 2; + int start = firstDot + 1; + while (start < length) { + int dot = indexOf.execute(name, '.', start, length, TS_ENCODING); + if (dot < 0) { + break; + } + parts++; + start = dot + 1; + } + TruffleString[] dottedPath = new TruffleString[parts]; + TruffleString.SubstringNode substring = ensureTsSubstringNode(); + start = 0; + int part = 0; + for (int dot = firstDot; dot >= 0; dot = start < length ? indexOf.execute(name, '.', start, length, TS_ENCODING) : -1) { + dottedPath[part++] = substring.execute(name, start, dot - start, TS_ENCODING, false); + start = dot + 1; + } + dottedPath[part] = substring.execute(name, start, length - start, TS_ENCODING, false); + return dottedPath; + } + public TruffleString[] getDottedPath(Object obj, TruffleString name) { - TruffleString[] dottedPath = StringUtils.split(name, T_DOT, ensureTsCodePointLengthNode(), ensureTsIndexOfStringNode(), ensureTsSubstringNode(), ensureTsEqualNode()); - assert dottedPath.length > 0; + TruffleString[] dottedPath = splitDottedPath(name); for (int i = 0; i < dottedPath.length; i++) { if (ensureTsEqualNode().execute(dottedPath[i], T_LOCALS, TS_ENCODING)) { if (obj == null) { From 50e3cb01f4bba6625210f6bbf801fcf10823ee12 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 22:54:32 +0200 Subject: [PATCH 100/129] Cache unpickled names (cherry picked from commit d0c6a40826ad3273d05dc5be9e89bf6418be18b7) --- .../builtins/modules/pickle/PPickler.java | 6 +-- .../builtins/modules/pickle/PicklerNodes.java | 48 +++++++++++++++++-- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 77df6fbd65..74a87d4cce 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -697,7 +697,7 @@ public TruffleString asStringStrict(Object value) { return string; } - private static boolean checkModule(VirtualFrame frame, PyObjectLookupAttr lookup, Object moduleName, Object module, Object global, TruffleString[] dottedPath) { + private static boolean checkModule(VirtualFrame frame, PicklerNodes.LookupGlobalAttributeNode lookup, Object moduleName, Object module, Object global, TruffleString[] dottedPath) { if (module == PNone.NONE) { return false; } @@ -728,7 +728,7 @@ public TruffleString whichModule(VirtualFrame frame, PythonContext context, Obje while (nextNode.executeCached(storage, it)) { Object value = getValueNode.executeCached(storage, it); Object key = getKeyNode.executeCached(storage, it); - if (checkModule(frame, getLookupAttrNode(), moduleName, value, global, dottedPath)) { + if (checkModule(frame, getLookupGlobalAttrNode(), moduleName, value, global, dottedPath)) { return asStringStrict(key); } } @@ -2182,7 +2182,7 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, } catch (PException e) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_IMPORT_OF_MODULE_S_FAILED, obj, moduleName); } - final Pair pair = getDeepAttribute(frame, getLookupAttrNode(), module, dottedPath); + final Pair pair = getDeepAttribute(frame, getLookupGlobalAttrNode(), module, dottedPath); if (pair == null) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_ATTR_LOOKUP_FAIL_S_S, obj, globalName, moduleName); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 58eefbaac4..3c35ea9f85 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -102,6 +102,11 @@ import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.LoopNode; @@ -110,6 +115,28 @@ import com.oracle.truffle.api.strings.TruffleString; public final class PicklerNodes { + @GenerateInline(false) + @ImportStatic(PythonUtils.class) + abstract static class LookupGlobalAttributeNode extends Node { + abstract Object execute(VirtualFrame frame, Object receiver, TruffleString name); + + // Unpickling decodes fresh strings. Give attribute lookup a stable name identity without + // caching the attribute value or interning arbitrary pickle contents. + @Specialization(guards = "equal.execute(name, cachedName, TS_ENCODING)", limit = "3") + static Object cached(VirtualFrame frame, Object receiver, TruffleString name, + @Cached("name") TruffleString cachedName, + @Cached TruffleString.EqualNode equal, + @Exclusive @Cached(inline = false) PyObjectLookupAttr lookup) { + return lookup.executeCached(frame, receiver, cachedName); + } + + @Specialization(replaces = "cached") + static Object generic(VirtualFrame frame, Object receiver, TruffleString name, + @Exclusive @Cached(inline = false) PyObjectLookupAttr lookup) { + return lookup.executeCached(frame, receiver, name); + } + } + abstract static class BasePickleNode extends Node { private static final TruffleString T_LOCALS = tsLiteral(""); public static final TruffleString T_CODEC_RAW_UNICODE_ESCAPE = tsLiteral("raw_unicode_escape"); @@ -143,6 +170,7 @@ abstract static class BasePickleNode extends Node { @Child private GetClassNode getClassNode; @Child private PyObjectSizeNode sizeNode; @Child private PyObjectLookupAttr lookupAttrNode; + @Child private LookupGlobalAttributeNode lookupGlobalAttrNode; @Child private BytesNodes.ToBytesNode toBytesNode; @Child private PyObjectReprAsTruffleStringNode reprNode; @Child private TruffleString.FromByteArrayNode tsFromByteArrayNode; @@ -398,6 +426,14 @@ protected PyObjectLookupAttr getLookupAttrNode() { return lookupAttrNode; } + protected LookupGlobalAttributeNode getLookupGlobalAttrNode() { + if (lookupGlobalAttrNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + lookupGlobalAttrNode = insert(PicklerNodesFactory.LookupGlobalAttributeNodeGen.create()); + } + return lookupGlobalAttrNode; + } + protected Object lookupAttribute(Frame frame, Object receiver, TruffleString name) { return getLookupAttrNode().executeCached(frame, receiver, name); } @@ -557,12 +593,12 @@ public TruffleString asString(Object value) { } } - public static Pair getDeepAttribute(VirtualFrame frame, PyObjectLookupAttr lookup, Object obj, TruffleString[] names) { + public static Pair getDeepAttribute(VirtualFrame frame, LookupGlobalAttributeNode lookup, Object obj, TruffleString[] names) { Object parent = null; Object object = obj; for (int i = 0; i < names.length; i++) { parent = object; - object = lookup.executeCached(frame, parent, names[i]); + object = lookup.execute(frame, parent, names[i]); if (object == NO_VALUE) { LoopNode.reportLoopCount(lookup, i); return null; @@ -621,14 +657,18 @@ public TruffleString[] getDottedPath(Object obj, TruffleString name) { public Object getattribute(VirtualFrame frame, Object obj, TruffleString name, boolean allowQualname) { if (allowQualname) { TruffleString[] dottedPath = getDottedPath(obj, name); - Pair result = getDeepAttribute(frame, getLookupAttrNode(), obj, dottedPath); + Pair result = getDeepAttribute(frame, getLookupGlobalAttrNode(), obj, dottedPath); if (result != null) { return result.getLeft(); } else { throw raise(AttributeError, ErrorMessages.CANT_GET_ATTRIBUTE_S_ON_S, name, getReprNode().execute(frame, null, obj)); } } else { - return lookupAttributeStrict(frame, obj, name); + Object attr = getLookupGlobalAttrNode().execute(frame, obj, name); + if (attr == NO_VALUE) { + throw raise(TypeError, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, attr, name); + } + return attr; } } From 188235359f9dc417a90e9cb8c71a1f1b685dd5c1 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 23:16:07 +0200 Subject: [PATCH 101/129] Use ImportName in unpickler (cherry picked from commit 2934d6d06f051082ece0dedf588e7ea0c2697148) --- .../builtins/modules/pickle/PUnpickler.java | 35 +++++++++---------- .../builtins/modules/pickle/PicklerNodes.java | 34 +++++++++++++----- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index f534ad21d8..bbec803c47 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -174,7 +174,6 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode; -import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; @@ -684,9 +683,8 @@ public abstract static class FindClassNode extends BasePickleReadNode { public abstract Object execute(VirtualFrame frame, PUnpickler unpickler, TruffleString module, TruffleString name); @Specialization - Object find(VirtualFrame frame, PUnpickler unpickler, TruffleString module, TruffleString name, - @Cached("createFor($node)") BoundaryCallData boundaryCallData) { - return findClass(frame, boundaryCallData, PythonContext.get(this).getCore(), unpickler, module, name); + Object find(VirtualFrame frame, PUnpickler unpickler, TruffleString module, TruffleString name) { + return findClass(frame, PythonContext.get(this).getCore(), unpickler, module, name); } } @@ -1331,7 +1329,7 @@ private void loadObj(VirtualFrame frame, Node inliningTarget, PUnpickler self, P pDataPush(self, obj); } - private void loadInst(VirtualFrame frame, Node inliningTarget, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self, PyObjectCallMethodObjArgs callMethod) { + private void loadInst(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PUnpickler self, PyObjectCallMethodObjArgs callMethod) { Object cls = null; Object obj = null; int i = marker(self); @@ -1351,7 +1349,7 @@ private void loadInst(VirtualFrame frame, Node inliningTarget, BoundaryCallData throw badReadLine(); } Object className = decodeASCII(frame, s, s.length - 1, T_ERRORS_STRICT); - cls = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, className); + cls = findClass(frame, ctx.getCore(), self, moduleName, className); } assert cls != null; @@ -1451,7 +1449,7 @@ private void doAppend(VirtualFrame frame, PUnpickler self, int x) { } } - private void loadGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self) { + private void loadGlobal(VirtualFrame frame, PythonContext ctx, PUnpickler self) { Object global = null; TruffleString globalName; byte[] s = readLine(frame, self); @@ -1467,14 +1465,14 @@ private void loadGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P } globalName = PickleUtils.decodeUTF8Strict(s, s.length - 1, ensureTsFromByteArray(), ensureTsSwitchEncodingNode()); if (globalName != null) { - global = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, globalName); + global = findClass(frame, ctx.getCore(), self, moduleName, globalName); } } pDataPush(self, global); } - private void loadStackGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self) { + private void loadStackGlobal(VirtualFrame frame, PythonContext ctx, PUnpickler self) { Object globalName = null; Object moduleName = null; try { @@ -1486,7 +1484,7 @@ private void loadStackGlobal(VirtualFrame frame, BoundaryCallData boundaryCallDa if (!PGuards.isString(moduleName) || !PGuards.isString(globalName)) { throw raise(PythonBuiltinClassType.UnpicklingError, ErrorMessages.S_REQ_STR, "STACK_GLOBAL"); } - Object global = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, globalName); + Object global = findClass(frame, ctx.getCore(), self, moduleName, globalName); pDataPush(self, global); } @@ -1841,7 +1839,7 @@ private void loadFrame(VirtualFrame frame, PUnpickler self) { self.nextReadIdx -= frameLen; } - private void loadExtension(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self, int nbytes) { + private void loadExtension(VirtualFrame frame, PythonContext ctx, PUnpickler self, int nbytes) { assert (nbytes == 1 || nbytes == 2 || nbytes == 4); // the nbytes bytes after the opcode int codeOffset = read(frame, self, nbytes); @@ -1887,7 +1885,7 @@ private void loadExtension(VirtualFrame frame, BoundaryCallData boundaryCallData } // Load the object. - obj = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, className); + obj = findClass(frame, ctx.getCore(), self, moduleName, className); // Cache code -> obj. setDictItem(frame, st.extensionCache, code, obj); @@ -1901,7 +1899,6 @@ private void loadBool(PUnpickler self, boolean bool) { @Specialization public Object load(VirtualFrame frame, PUnpickler self, @Bind Node inliningTarget, - @Cached("createFor($node)") BoundaryCallData boundaryCallData, @Cached GetCachedTpSlotsNode getSlots, @Cached CallSlotTpNewNode callNew, @Cached ExecutePositionalStarargsNode expandArgs, @@ -2072,7 +2069,7 @@ public Object load(VirtualFrame frame, PUnpickler self, continue; case OPCODE_INST: profileSeen(SEEN_INST); - loadInst(frame, inliningTarget, boundaryCallData, ctx, self, callMethod); + loadInst(frame, inliningTarget, ctx, self, callMethod); continue; case OPCODE_NEWOBJ: profileSeen(SEEN_NEWOBJ); @@ -2084,11 +2081,11 @@ public Object load(VirtualFrame frame, PUnpickler self, continue; case OPCODE_GLOBAL: profileSeen(SEEN_GLOBAL); - loadGlobal(frame, boundaryCallData, ctx, self); + loadGlobal(frame, ctx, self); continue; case OPCODE_STACK_GLOBAL: profileSeen(SEEN_STACK_GLOBAL); - loadStackGlobal(frame, boundaryCallData, ctx, self); + loadStackGlobal(frame, ctx, self); continue; case OPCODE_APPEND: profileSeen(SEEN_APPEND); @@ -2176,15 +2173,15 @@ public Object load(VirtualFrame frame, PUnpickler self, continue; case OPCODE_EXT1: profileSeen(SEEN_EXT1); - loadExtension(frame, boundaryCallData, ctx, self, 1); + loadExtension(frame, ctx, self, 1); continue; case OPCODE_EXT2: profileSeen(SEEN_EXT2); - loadExtension(frame, boundaryCallData, ctx, self, 2); + loadExtension(frame, ctx, self, 2); continue; case OPCODE_EXT4: profileSeen(SEEN_EXT4); - loadExtension(frame, boundaryCallData, ctx, self, 4); + loadExtension(frame, ctx, self, 4); continue; case OPCODE_NEWTRUE: profileSeen(SEEN_NEWTRUE); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 3c35ea9f85..93a2fded58 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -47,8 +47,8 @@ import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; -import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -60,6 +60,7 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltins; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltinsFactory; +import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; import com.oracle.graal.python.builtins.objects.common.HashingStorage; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.CachedHashingStorageGetItem; @@ -73,6 +74,7 @@ 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.function.PKeyword; +import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.lib.PyIterCheckNode; import com.oracle.graal.python.lib.PyIterNextNode; @@ -94,9 +96,11 @@ import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.nodes.statement.AbstractImportNode.ImportName; +import com.oracle.graal.python.nodes.statement.AbstractImportNodeFactory.ImportNameNodeGen; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; -import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; +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.runtime.sequence.storage.SequenceStorage; @@ -160,6 +164,7 @@ abstract static class BasePickleNode extends Node { @Child private CastToTruffleStringNode castToTruffleStringNode; @Child private SequenceNodes.GetSequenceStorageNode getSequenceStorageNode; @Child private CallNode callNode; + @Child private ImportName importNameNode; @Child private ExecutePositionalStarargsNode getArgsNode; @Child private ExpandKeywordStarargsNode getKwArgsNode; @Child private PyLongFromUnicodeObject pyLongFromUnicodeObject; @@ -711,11 +716,11 @@ private Pair getMapping(VirtualFrame frame, PDict return Pair.create(moduleName, globalName); } - public Object findClass(VirtualFrame frame, BoundaryCallData boundaryCallData, Python3Core core, PUnpickler self, Object moduleName, Object globalName) { - return findClass(frame, boundaryCallData, core, self, castToString(moduleName), castToString(globalName)); + public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, Object moduleName, Object globalName) { + return findClass(frame, core, self, castToString(moduleName), castToString(globalName)); } - public Object findClass(VirtualFrame frame, BoundaryCallData boundaryCallData, Python3Core core, PUnpickler self, TruffleString moduleName, TruffleString globalName) { + public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, TruffleString moduleName, TruffleString globalName) { // Try to map the old names used in Python 2.x to the new ones used in Python 3.x. We do // this only with old pickle protocols and when the user has not disabled the feature. TruffleString mName = moduleName; @@ -726,9 +731,22 @@ public Object findClass(VirtualFrame frame, BoundaryCallData boundaryCallData, P gName = to3Mapping.getRight(); } - // we don't use PyImport_GetModule here, because it can return partially-initialised - // modules, which then cause the getattribute to fail. - Object module = importModule(frame, boundaryCallData, mName); + if (importNameNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + importNameNode = insert(ImportNameNodeGen.create()); + } + // ImportName checks initialization for cached modules and honors custom import hooks. + // With an empty fromlist, a dotted import returns the top-level package, so look up + // the requested module by its full name after importing for side effects. + importNameNode.execute(frame, PythonContext.get(this), core.getBuiltins(), mName, PNone.NONE, PythonUtils.EMPTY_TRUFFLESTRING_ARRAY, 0); + Object module = getDictItem(frame, core.getSysModules(), mName); + if (module == null) { + errorProfile.enter(); + throw PRaiseNode.raiseStatic(this, KeyError, new Object[]{mName}); + } + if (!(module instanceof PythonModule)) { + throw raise(PythonBuiltinClassType.NotImplementedError, ErrorMessages.PUTTING_NON_MODULE_OBJECTS_IN_SYS_MODULES_IS_NOT_SUPPORTED); + } return getattribute(frame, module, gName, self.getProto() >= 4); } } From 889c458a2959035e3c12312d41f8bcc214bed3ee Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 1 Oct 2026 23:36:30 +0200 Subject: [PATCH 102/129] Push members down from BasePickleNode (cherry picked from commit 427c4fb120c4f5f796ea211a253ba6be579c1a66) --- .../builtins/modules/pickle/PPickler.java | 14 +-- .../builtins/modules/pickle/PUnpickler.java | 90 ++++++++++++++++- .../builtins/modules/pickle/PicklerNodes.java | 96 +------------------ 3 files changed, 99 insertions(+), 101 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 74a87d4cce..3ef61a98cc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -40,6 +40,8 @@ */ package com.oracle.graal.python.builtins.modules.pickle; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; import static com.oracle.graal.python.nodes.ErrorMessages.MUST_BE_STR_NOT_P; @@ -68,6 +70,7 @@ import org.graalvm.collections.Pair; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PNotImplemented; @@ -481,12 +484,6 @@ private void writeIntOp(Node node, byte opcode, long value) { outputBuffer[outputLen++] = intByte4(value); } - private void write(Node node, byte[] bytes, int dataLen) { - ensureBufferSpace(node, dataLen); - PythonUtils.arraycopy(bytes, 0, outputBuffer, outputLen, dataLen); - outputLen += dataLen; - } - private void ensureBufferSpace(Node node, int dataLen) { boolean needNewFrame = isFraming() && frameStart == -1; int n = CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; @@ -2160,6 +2157,11 @@ private void saveType(VirtualFrame frame, PythonContext ctx, PPickler pickler, i } } + protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { + PickleState state = getGlobalState(core); + return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); + } + private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object name) { PickleState st = getGlobalState(ctx.getCore()); Object gName; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index bbec803c47..56f7e032aa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -111,12 +111,15 @@ import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.PICKLE_PROTOCOL_HIGHEST; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.PREFETCH; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.READ_WHOLE_LINE; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_IMPORT_MAPPING; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_NAME_MAPPING; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_PEEK; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_PERSISTENT_LOAD; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_READ; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_READINTO; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_READLINE; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.getValidIntString; +import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.BuiltinNames.T_ADD; import static com.oracle.graal.python.nodes.BuiltinNames.T_APPEND; import static com.oracle.graal.python.nodes.BuiltinNames.T_EXTEND; @@ -126,11 +129,15 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SETSTATE__; import static com.oracle.graal.python.nodes.StringLiterals.T_ASCII_UPPERCASE; import static com.oracle.graal.python.nodes.StringLiterals.T_STRICT; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import org.graalvm.collections.Pair; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.buffer.BufferFlags; @@ -155,6 +162,7 @@ import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.memoryview.MemoryViewBuiltins; import com.oracle.graal.python.builtins.objects.memoryview.MemoryViewBuiltinsFactory; +import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.builtins.objects.set.PSet; import com.oracle.graal.python.builtins.objects.tuple.PTuple; @@ -166,6 +174,7 @@ import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectLookupAttr; +import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; import com.oracle.graal.python.lib.PyObjectSetAttrO; import com.oracle.graal.python.lib.PyObjectSetItem; import com.oracle.graal.python.lib.PyTupleCheckNode; @@ -174,6 +183,9 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode; +import com.oracle.graal.python.nodes.statement.AbstractImportNode.ImportName; +import com.oracle.graal.python.nodes.statement.AbstractImportNodeFactory.ImportNameNodeGen; +import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; @@ -396,6 +408,9 @@ public void clearMemo() { // inner nodes public abstract static class BasePickleReadNode extends PicklerNodes.BasePickleNode { + @Child private CastToTruffleStringNode castToTruffleStringNode; + @Child private ImportName importNameNode; + @Child private PyObjectReprAsTruffleStringNode reprNode; @Child private PyMemoryViewFromObject memoryViewNode; @Child private MemoryViewBuiltins.ToReadonlyNode toReadonlyNode; @Child private PythonBufferAcquireLibrary bufferAcquireLibrary; @@ -409,7 +424,80 @@ public abstract static class BasePickleReadNode extends PicklerNodes.BasePickleN // we only need the reference, doesn't matter that the object may not yet be fully // constructed - @SuppressWarnings("this-escape") private InteropCallData interopCallData = InteropCallData.createFor(this); + @SuppressWarnings("this-escape") private final InteropCallData interopCallData = InteropCallData.createFor(this); + + protected TruffleString castToString(Object value) { + if (castToTruffleStringNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + castToTruffleStringNode = insert(CastToTruffleStringNode.create()); + } + return castToTruffleStringNode.executeCached(value); + } + + private PyObjectReprAsTruffleStringNode getReprNode() { + if (reprNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + reprNode = insert(PyObjectReprAsTruffleStringNode.create()); + } + return reprNode; + } + + public Object getattribute(VirtualFrame frame, Object obj, TruffleString name, boolean allowQualname) { + if (allowQualname) { + TruffleString[] dottedPath = getDottedPath(obj, name); + Pair result = getDeepAttribute(frame, getLookupGlobalAttrNode(), obj, dottedPath); + if (result != null) { + return result.getLeft(); + } else { + throw raise(AttributeError, ErrorMessages.CANT_GET_ATTRIBUTE_S_ON_S, name, getReprNode().execute(frame, null, obj)); + } + } else { + Object attr = getLookupGlobalAttrNode().execute(frame, obj, name); + if (attr == NO_VALUE) { + throw raise(TypeError, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, attr, name); + } + return attr; + } + } + + protected Pair get2To3Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { + PickleState state = getGlobalState(core); + return getMapping(frame, state.nameMapping2To3, state.importMapping2To3, T_CP_NAME_MAPPING, T_CP_IMPORT_MAPPING, moduleName, globalName); + } + + public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, Object moduleName, Object globalName) { + return findClass(frame, core, self, castToString(moduleName), castToString(globalName)); + } + + public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, TruffleString moduleName, TruffleString globalName) { + // Try to map the old names used in Python 2.x to the new ones used in Python 3.x. We do + // this only with old pickle protocols and when the user has not disabled the feature. + TruffleString mName = moduleName; + TruffleString gName = globalName; + if (self.getProto() < 3 && self.isFixImports()) { + final Pair to3Mapping = get2To3Mapping(frame, core, mName, gName); + mName = to3Mapping.getLeft(); + gName = to3Mapping.getRight(); + } + + if (importNameNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + importNameNode = insert(ImportNameNodeGen.create()); + } + // ImportName checks initialization for cached modules and honors custom import hooks. + // With an empty fromlist, a dotted import returns the top-level package, so look up + // the requested module by its full name after importing for side effects. + importNameNode.execute(frame, PythonContext.get(this), core.getBuiltins(), mName, PNone.NONE, PythonUtils.EMPTY_TRUFFLESTRING_ARRAY, 0); + Object module = getDictItem(frame, core.getSysModules(), mName); + if (module == null) { + errorProfile.enter(); + throw PRaiseNode.raiseStatic(this, KeyError, new Object[]{mName}); + } + if (!(module instanceof PythonModule)) { + throw raise(PythonBuiltinClassType.NotImplementedError, ErrorMessages.PUTTING_NON_MODULE_OBJECTS_IN_SYS_MODULES_IS_NOT_SUPPORTED); + } + return getattribute(frame, module, gName, self.getProto() >= 4); + } protected TruffleString.ParseLongNode ensureTsParseLongNode() { if (tsParseLongNode == null) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 93a2fded58..157db2b791 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -40,15 +40,10 @@ */ package com.oracle.graal.python.builtins.modules.pickle; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_IMPORT_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_NAME_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; -import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -60,7 +55,6 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltins; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltinsFactory; -import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; import com.oracle.graal.python.builtins.objects.common.HashingStorage; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.CachedHashingStorageGetItem; @@ -74,7 +68,6 @@ 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.function.PKeyword; -import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.lib.PyIterCheckNode; import com.oracle.graal.python.lib.PyIterNextNode; @@ -82,7 +75,6 @@ import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.PyObjectGetItem; import com.oracle.graal.python.lib.PyObjectLookupAttr; -import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; import com.oracle.graal.python.lib.PyObjectSetItem; import com.oracle.graal.python.lib.PyObjectSizeNode; import com.oracle.graal.python.nodes.ErrorMessages; @@ -96,11 +88,8 @@ import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.GetClassNode; -import com.oracle.graal.python.nodes.statement.AbstractImportNode.ImportName; -import com.oracle.graal.python.nodes.statement.AbstractImportNodeFactory.ImportNameNodeGen; import com.oracle.graal.python.nodes.util.CannotCastException; 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.runtime.sequence.storage.SequenceStorage; @@ -161,10 +150,8 @@ abstract static class BasePickleNode extends Node { @Child private CachedHashingStorageGetItem getHashingStorageItemNode; @Child private SequenceStorageNodes.GetItemScalarNode getSeqStorageItemNode; @Child private PyNumberAsSizeNode asSizeNode; - @Child private CastToTruffleStringNode castToTruffleStringNode; @Child private SequenceNodes.GetSequenceStorageNode getSequenceStorageNode; @Child private CallNode callNode; - @Child private ImportName importNameNode; @Child private ExecutePositionalStarargsNode getArgsNode; @Child private ExpandKeywordStarargsNode getKwArgsNode; @Child private PyLongFromUnicodeObject pyLongFromUnicodeObject; @@ -177,7 +164,6 @@ abstract static class BasePickleNode extends Node { @Child private PyObjectLookupAttr lookupAttrNode; @Child private LookupGlobalAttributeNode lookupGlobalAttrNode; @Child private BytesNodes.ToBytesNode toBytesNode; - @Child private PyObjectReprAsTruffleStringNode reprNode; @Child private TruffleString.FromByteArrayNode tsFromByteArrayNode; @Child private TruffleString.FromByteArrayWithCompactionUTF32Node tsFromByteArrayWithCompactionNode; @Child private TruffleString.CodePointLengthNode tsCodePointLengthNode; @@ -190,7 +176,7 @@ abstract static class BasePickleNode extends Node { @Child private HashingStorageIteratorNext hashingStorageItNext; @Child private HashingStorageIteratorKey hashingStorageItKey; @Child private HashingStorageIteratorValue hashingStorageItValue; - private final BranchProfile errorProfile = BranchProfile.create(); + protected final BranchProfile errorProfile = BranchProfile.create(); protected PException raise(PythonBuiltinClassType type, TruffleString string) { errorProfile.enter(); @@ -279,14 +265,6 @@ protected byte[] toBytes(VirtualFrame frame, Object obj) { return toBytesNode.execute(frame, obj); } - private PyObjectReprAsTruffleStringNode getReprNode() { - if (reprNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - reprNode = insert(PyObjectReprAsTruffleStringNode.create()); - } - return reprNode; - } - protected HashingStorageIterator getHashingStorageIterator(HashingStorage s) { if (getHashingStorageIteratorNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -488,14 +466,6 @@ protected SequenceStorage getSequenceStorage(Object iterator) { return getSequenceStorageNode.executeCached(iterator); } - protected TruffleString castToString(Object value) { - if (castToTruffleStringNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - castToTruffleStringNode = insert(CastToTruffleStringNode.create()); - } - return castToTruffleStringNode.executeCached(value); - } - public int asSizeExact(VirtualFrame frame, Object pyNumber) { if (asSizeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -659,35 +629,7 @@ public TruffleString[] getDottedPath(Object obj, TruffleString name) { return dottedPath; } - public Object getattribute(VirtualFrame frame, Object obj, TruffleString name, boolean allowQualname) { - if (allowQualname) { - TruffleString[] dottedPath = getDottedPath(obj, name); - Pair result = getDeepAttribute(frame, getLookupGlobalAttrNode(), obj, dottedPath); - if (result != null) { - return result.getLeft(); - } else { - throw raise(AttributeError, ErrorMessages.CANT_GET_ATTRIBUTE_S_ON_S, name, getReprNode().execute(frame, null, obj)); - } - } else { - Object attr = getLookupGlobalAttrNode().execute(frame, obj, name); - if (attr == NO_VALUE) { - throw raise(TypeError, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, attr, name); - } - return attr; - } - } - - protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { - PickleState state = getGlobalState(core); - return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); - } - - protected Pair get2To3Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { - PickleState state = getGlobalState(core); - return getMapping(frame, state.nameMapping2To3, state.importMapping2To3, T_CP_NAME_MAPPING, T_CP_IMPORT_MAPPING, moduleName, globalName); - } - - private Pair getMapping(VirtualFrame frame, PDict nameMapping, PDict importMapping, + protected Pair getMapping(VirtualFrame frame, PDict nameMapping, PDict importMapping, TruffleString nameMappingLabel, TruffleString importMappingLabel, TruffleString moduleName, TruffleString globalName) { Object key = PFactory.createTuple(PythonLanguage.get(this), new Object[]{moduleName, globalName}); Object item = getDictItem(frame, nameMapping, key); @@ -715,39 +657,5 @@ private Pair getMapping(VirtualFrame frame, PDict return Pair.create(moduleName, globalName); } - - public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, Object moduleName, Object globalName) { - return findClass(frame, core, self, castToString(moduleName), castToString(globalName)); - } - - public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, TruffleString moduleName, TruffleString globalName) { - // Try to map the old names used in Python 2.x to the new ones used in Python 3.x. We do - // this only with old pickle protocols and when the user has not disabled the feature. - TruffleString mName = moduleName; - TruffleString gName = globalName; - if (self.getProto() < 3 && self.isFixImports()) { - final Pair to3Mapping = get2To3Mapping(frame, core, mName, gName); - mName = to3Mapping.getLeft(); - gName = to3Mapping.getRight(); - } - - if (importNameNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - importNameNode = insert(ImportNameNodeGen.create()); - } - // ImportName checks initialization for cached modules and honors custom import hooks. - // With an empty fromlist, a dotted import returns the top-level package, so look up - // the requested module by its full name after importing for side effects. - importNameNode.execute(frame, PythonContext.get(this), core.getBuiltins(), mName, PNone.NONE, PythonUtils.EMPTY_TRUFFLESTRING_ARRAY, 0); - Object module = getDictItem(frame, core.getSysModules(), mName); - if (module == null) { - errorProfile.enter(); - throw PRaiseNode.raiseStatic(this, KeyError, new Object[]{mName}); - } - if (!(module instanceof PythonModule)) { - throw raise(PythonBuiltinClassType.NotImplementedError, ErrorMessages.PUTTING_NON_MODULE_OBJECTS_IN_SYS_MODULES_IS_NOT_SUPPORTED); - } - return getattribute(frame, module, gName, self.getProto() >= 4); - } } } From 1943631486d5da7f7f56bcb7eb10de03759faa3f Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 2 Oct 2026 10:34:07 +0200 Subject: [PATCH 103/129] Use the same import mechanism in pickler and unpickler (cherry picked from commit a75550eaaee41c3bfa4e556040ee1d186bd9ca1c) --- .../builtins/modules/pickle/PPickler.java | 3 +- .../builtins/modules/pickle/PUnpickler.java | 22 +--------- .../builtins/modules/pickle/PicklerNodes.java | 40 +++++++++++++++++++ 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 3ef61a98cc..5ae2f5cfc7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -55,7 +55,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE__; import static com.oracle.graal.python.nodes.StringLiterals.T_NEWLINE; -import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.PicklingError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; @@ -2180,7 +2179,7 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object module; try { - module = importModule(frame, getBoundaryCallData(), moduleName); + module = importModule(frame, ctx, moduleName); } catch (PException e) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_IMPORT_OF_MODULE_S_FAILED, obj, moduleName); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index 56f7e032aa..fa5874818d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -130,7 +130,6 @@ import static com.oracle.graal.python.nodes.StringLiterals.T_ASCII_UPPERCASE; import static com.oracle.graal.python.nodes.StringLiterals.T_STRICT; import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; -import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; @@ -162,7 +161,6 @@ import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.memoryview.MemoryViewBuiltins; import com.oracle.graal.python.builtins.objects.memoryview.MemoryViewBuiltinsFactory; -import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.builtins.objects.set.PSet; import com.oracle.graal.python.builtins.objects.tuple.PTuple; @@ -183,8 +181,6 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode; -import com.oracle.graal.python.nodes.statement.AbstractImportNode.ImportName; -import com.oracle.graal.python.nodes.statement.AbstractImportNodeFactory.ImportNameNodeGen; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; @@ -409,7 +405,6 @@ public void clearMemo() { // inner nodes public abstract static class BasePickleReadNode extends PicklerNodes.BasePickleNode { @Child private CastToTruffleStringNode castToTruffleStringNode; - @Child private ImportName importNameNode; @Child private PyObjectReprAsTruffleStringNode reprNode; @Child private PyMemoryViewFromObject memoryViewNode; @Child private MemoryViewBuiltins.ToReadonlyNode toReadonlyNode; @@ -480,22 +475,7 @@ public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, T gName = to3Mapping.getRight(); } - if (importNameNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - importNameNode = insert(ImportNameNodeGen.create()); - } - // ImportName checks initialization for cached modules and honors custom import hooks. - // With an empty fromlist, a dotted import returns the top-level package, so look up - // the requested module by its full name after importing for side effects. - importNameNode.execute(frame, PythonContext.get(this), core.getBuiltins(), mName, PNone.NONE, PythonUtils.EMPTY_TRUFFLESTRING_ARRAY, 0); - Object module = getDictItem(frame, core.getSysModules(), mName); - if (module == null) { - errorProfile.enter(); - throw PRaiseNode.raiseStatic(this, KeyError, new Object[]{mName}); - } - if (!(module instanceof PythonModule)) { - throw raise(PythonBuiltinClassType.NotImplementedError, ErrorMessages.PUTTING_NON_MODULE_OBJECTS_IN_SYS_MODULES_IS_NOT_SUPPORTED); - } + Object module = importModule(frame, PythonContext.get(this), mName); return getattribute(frame, module, gName, self.getProto() >= 4); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 157db2b791..92461803a3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -44,6 +44,7 @@ import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -55,6 +56,7 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltins; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltinsFactory; +import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; import com.oracle.graal.python.builtins.objects.common.HashingStorage; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.CachedHashingStorageGetItem; @@ -68,6 +70,7 @@ 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.function.PKeyword; +import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.lib.PyIterCheckNode; import com.oracle.graal.python.lib.PyIterNextNode; @@ -88,13 +91,16 @@ import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.nodes.statement.AbstractImportNode.ImportName; import com.oracle.graal.python.nodes.util.CannotCastException; 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.runtime.sequence.storage.SequenceStorage; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.GenerateInline; @@ -108,6 +114,31 @@ import com.oracle.truffle.api.strings.TruffleString; public final class PicklerNodes { + @GenerateInline(false) + abstract static class ImportModuleNode extends Node { + abstract PythonModule execute(VirtualFrame frame, PythonContext context, TruffleString name); + + @Specialization + static PythonModule doImport(VirtualFrame frame, PythonContext context, TruffleString name, + @Bind Node inliningTarget, + @Cached ImportName importNameNode, + @Cached CachedHashingStorageGetItem getItemNode, + @Cached PRaiseNode raiseNode) { + // ImportName checks initialization for cached modules and honors custom import hooks. + // With an empty fromlist, a dotted import returns the top-level package, so look up + // the requested module by its full name after importing for side effects. + importNameNode.execute(frame, context, context.getBuiltins(), name, PNone.NONE, PythonUtils.EMPTY_TRUFFLESTRING_ARRAY, 0); + Object module = getItemNode.execute(frame, context.getSysModules().getDictStorage(), name); + if (module == null) { + throw raiseNode.raise(inliningTarget, KeyError, new Object[]{name}); + } + if (module instanceof PythonModule pythonModule) { + return pythonModule; + } + throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.NotImplementedError, ErrorMessages.PUTTING_NON_MODULE_OBJECTS_IN_SYS_MODULES_IS_NOT_SUPPORTED); + } + } + @GenerateInline(false) @ImportStatic(PythonUtils.class) abstract static class LookupGlobalAttributeNode extends Node { @@ -163,6 +194,7 @@ abstract static class BasePickleNode extends Node { @Child private PyObjectSizeNode sizeNode; @Child private PyObjectLookupAttr lookupAttrNode; @Child private LookupGlobalAttributeNode lookupGlobalAttrNode; + @Child private ImportModuleNode importModuleNode; @Child private BytesNodes.ToBytesNode toBytesNode; @Child private TruffleString.FromByteArrayNode tsFromByteArrayNode; @Child private TruffleString.FromByteArrayWithCompactionUTF32Node tsFromByteArrayWithCompactionNode; @@ -273,6 +305,14 @@ protected HashingStorageIterator getHashingStorageIterator(HashingStorage s) { return getHashingStorageIteratorNode.executeCached(s); } + protected PythonModule importModule(VirtualFrame frame, PythonContext context, TruffleString name) { + if (importModuleNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + importModuleNode = insert(PicklerNodesFactory.ImportModuleNodeGen.create()); + } + return importModuleNode.execute(frame, context, name); + } + protected HashingStorageIteratorNext ensureHashingStorageIteratorNext() { if (hashingStorageItNext == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); From d24ecaffe092ab30c8def4d93189d56c2ad24a40 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 2 Oct 2026 11:48:09 +0200 Subject: [PATCH 104/129] Improve pickler graph size (cherry picked from commit 29988e99e9f763a838883539ec3b678298c9cf0a) --- .../builtins/modules/pickle/PPickler.java | 78 +++++++------------ .../builtins/modules/pickle/PickleUtils.java | 10 +-- 2 files changed, 29 insertions(+), 59 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 5ae2f5cfc7..21cc0543c9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -445,42 +445,28 @@ private void writeBuffer(Node node, Object buffer, int size, PythonBufferAccessL outputLen += size; } - private static byte intByte1(long value) { - return (byte) (value & 0xff); - } - - private static byte intByte2(long value) { - return (byte) ((value >> 8) & 0xff); - } - - private static byte intByte3(long value) { - return (byte) ((value >> 16) & 0xff); - } - - private static byte intByte4(long value) { - return (byte) ((value >> 24) & 0xff); - } - private void writeByteOp(Node node, byte opcode, long value) { ensureBufferSpace(node, 2); - outputBuffer[outputLen++] = opcode; - outputBuffer[outputLen++] = intByte1(value); + int start = outputLen; + outputBuffer[start] = opcode; + outputBuffer[start + 1] = (byte) value; + outputLen = start + 2; } private void writeShortOp(Node node, byte opcode, long value) { ensureBufferSpace(node, 3); - outputBuffer[outputLen++] = opcode; - outputBuffer[outputLen++] = intByte1(value); - outputBuffer[outputLen++] = intByte2(value); + int start = outputLen; + outputBuffer[start] = opcode; + NumericSupport.littleEndian().putShort(outputBuffer, start + 1, (short) value); + outputLen = start + 3; } private void writeIntOp(Node node, byte opcode, long value) { ensureBufferSpace(node, 5); - outputBuffer[outputLen++] = opcode; - outputBuffer[outputLen++] = intByte1(value); - outputBuffer[outputLen++] = intByte2(value); - outputBuffer[outputLen++] = intByte3(value); - outputBuffer[outputLen++] = intByte4(value); + int start = outputLen; + outputBuffer[start] = opcode; + NumericSupport.littleEndian().putInt(outputBuffer, start + 1, (int) value); + outputLen = start + 5; } private void ensureBufferSpace(Node node, int dataLen) { @@ -504,19 +490,6 @@ private void ensureBufferSpace(Node node, int dataLen) { } } - private boolean bypassBuffer(int dataSize) { - boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; - - if (bypassBuffer) { - assert outputBuffer != null; - // Commit the previous frame. - commitFrame(); - // Disable framing temporarily - framing = false; - } - return bypassBuffer; - } - private void writeRawUnicodeEscape(Node node, TruffleString string, TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexUTF32Node codePointAtIndexNode) { int codePointLength = codePointLengthNode.execute(string, TS_ENCODING); @@ -813,6 +786,18 @@ private void profileSeen(long seen) { } } + private boolean bypassBuffer(PPickler pickler, int dataSize) { + boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; + if (bypassBuffer) { + profileSeen(SEEN_BYPASS_BUFFER); + assert pickler.outputBuffer != null; + // Commit the previous frame before disabling framing temporarily. + pickler.commitFrame(); + pickler.framing = false; + } + return bypassBuffer; + } + private BoundaryCallData getBoundaryCallData() { if (boundaryCallData == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -1600,10 +1585,7 @@ private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, bool assert proto >= 3; int size = bufferLib.getBufferLength(buffer); boolean wasFraming = pickler.framing; - boolean bypassBuffer = pickler.bypassBuffer(size); - if (bypassBuffer) { - profileSeen(SEEN_BYPASS_BUFFER); - } + boolean bypassBuffer = bypassBuffer(pickler, size); if (size <= 0xff) { pickler.writeByteOp(this, PickleUtils.OPCODE_SHORT_BINBYTES, size); @@ -1631,10 +1613,7 @@ private void writeUnicodeBinary(Node node, VirtualFrame frame, PPickler pickler, TruffleString utf8 = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); int size = utf8.byteLength(TruffleString.Encoding.UTF_8); boolean wasFraming = pickler.framing; - boolean bypassBuffer = pickler.bypassBuffer(size); - if (bypassBuffer) { - profileSeen(SEEN_BYPASS_BUFFER); - } + boolean bypassBuffer = bypassBuffer(pickler, size); if (bypassBuffer && pickler.write != null) { pickler.writeIntOp(node, PickleUtils.OPCODE_BINUNICODE, size); @@ -2057,10 +2036,7 @@ private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, int size = bufferLib.getBufferLength(buffer); boolean wasFraming = pickler.framing; - boolean bypassBuffer = pickler.bypassBuffer(size); - if (bypassBuffer) { - profileSeen(SEEN_BYPASS_BUFFER); - } + boolean bypassBuffer = bypassBuffer(pickler, size); // Our sizes are ints, but the protocol expects 8 bytes pickler.ensureBufferSpace(this, 9); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java index 193840a77b..feb9b8f210 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java @@ -59,6 +59,7 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.graal.python.util.NumericSupport; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; @@ -214,14 +215,7 @@ public final class PickleUtils { public static final TruffleString T_PROTO_LE2_FALSE = tsLiteral("I00\n"); public static void writeSize64(byte[] out, int start, int value) { - out[start] = (byte) value; - out[start + 1] = (byte) (value >> 8); - out[start + 2] = (byte) (value >> 16); - out[start + 3] = (byte) (value >> 24); - out[start + 4] = 0; - out[start + 5] = 0; - out[start + 6] = 0; - out[start + 7] = 0; + NumericSupport.littleEndian().putLong(out, start, Integer.toUnsignedLong(value)); } public static int getStringSize(byte[] bytes) { From 1e8391815bc42eb882ec1ecf7092fddc84142788 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 2 Oct 2026 13:31:10 +0200 Subject: [PATCH 105/129] Use separate recursive SaveNodes (cherry picked from commit 90dc553c5a12353244db7d72b6be50147d3ab4ce) --- .../builtins/modules/pickle/PPickler.java | 262 ++++++++++++++---- 1 file changed, 204 insertions(+), 58 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 21cc0543c9..968f29e056 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -589,9 +589,22 @@ public abstract static class SaveNode extends PicklerNodes.BasePickleNode { @CompilationFinal private long seenTypes; private final int depth; - @Child private SaveNode recursiveSaveNode1; - @Child private SaveNode recursiveSaveNode2; - @Child private SaveNode recursiveSaveNode3; + // Keep recursive profiles separate for each role in the pickle stream. + @Child private SaveNode dictKeySaveNode; + @Child private SaveNode dictValueSaveNode; + @Child private SaveNode setElementSaveNode; + @Child private SaveNode listElementSaveNode; + @Child private SaveNode tupleElementSaveNode; + @Child private SaveNode persistentIdSaveNode; + @Child private SaveNode reduceClassSaveNode; + @Child private SaveNode reduceCallableSaveNode; + @Child private SaveNode reduceArgsSaveNode; + @Child private SaveNode reduceKwargsSaveNode; + @Child private SaveNode reduceStateSaveNode; + @Child private SaveNode reduceStateSetterSaveNode; + @Child private SaveNode reduceObjectSaveNode; + @Child private SaveNode globalModuleNameSaveNode; + @Child private SaveNode globalNameSaveNode; @Child private ListNodes.ConstructListNode constructListNode; @Child private TypeNodes.IsTypeNode isTypeNode; @@ -822,51 +835,181 @@ private boolean isTuple(Object object) { return tupleCheckNode.execute(object); } - private void save(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { + private void saveDictKey(VirtualFrame frame, PPickler pickler, Object obj) { if (depth < 0) { - saveDepthExceeded(pickler, obj, persSave); + saveDepthExceeded(pickler, obj, 0); return; } - if (recursiveSaveNode1 == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveSaveNode1 = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + if (dictKeySaveNode == null) { + dictKeySaveNode = createRecursiveSaveNode(); } - if (depth < MAX_RECURSION_DEPTH) { - recursiveSaveNode1.execute(frame, pickler, obj, persSave); - } else { - saveSetupBoundary(frame, recursiveSaveNode1, pickler, obj, persSave); + saveRecursive(frame, dictKeySaveNode, pickler, obj, 0); + } + + private void saveDictValue(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (dictValueSaveNode == null) { + dictValueSaveNode = createRecursiveSaveNode(); } + saveRecursive(frame, dictValueSaveNode, pickler, obj, 0); } - private void save2(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { + private void saveSetElement(VirtualFrame frame, PPickler pickler, Object obj) { if (depth < 0) { - saveDepthExceeded(pickler, obj, persSave); + saveDepthExceeded(pickler, obj, 0); return; } - if (recursiveSaveNode2 == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveSaveNode2 = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + if (setElementSaveNode == null) { + setElementSaveNode = createRecursiveSaveNode(); } - if (depth < MAX_RECURSION_DEPTH) { - recursiveSaveNode2.execute(frame, pickler, obj, persSave); - } else { - saveSetupBoundary(frame, recursiveSaveNode2, pickler, obj, persSave); + saveRecursive(frame, setElementSaveNode, pickler, obj, 0); + } + + private void saveListElement(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (listElementSaveNode == null) { + listElementSaveNode = createRecursiveSaveNode(); } + saveRecursive(frame, listElementSaveNode, pickler, obj, 0); } - private void save3(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { + private void saveTupleElement(VirtualFrame frame, PPickler pickler, Object obj) { if (depth < 0) { - saveDepthExceeded(pickler, obj, persSave); + saveDepthExceeded(pickler, obj, 0); return; } - if (recursiveSaveNode3 == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveSaveNode3 = insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + if (tupleElementSaveNode == null) { + tupleElementSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, tupleElementSaveNode, pickler, obj, 0); + } + + private void savePersistentId(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 1); + return; + } + if (persistentIdSaveNode == null) { + persistentIdSaveNode = createRecursiveSaveNode(); } + saveRecursive(frame, persistentIdSaveNode, pickler, obj, 1); + } + + private void saveReduceClass(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceClassSaveNode == null) { + reduceClassSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceClassSaveNode, pickler, obj, 0); + } + + private void saveReduceCallable(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceCallableSaveNode == null) { + reduceCallableSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceCallableSaveNode, pickler, obj, 0); + } + + private void saveReduceArgs(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceArgsSaveNode == null) { + reduceArgsSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceArgsSaveNode, pickler, obj, 0); + } + + private void saveReduceKwargs(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceKwargsSaveNode == null) { + reduceKwargsSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceKwargsSaveNode, pickler, obj, 0); + } + + private void saveReduceState(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceStateSaveNode == null) { + reduceStateSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceStateSaveNode, pickler, obj, 0); + } + + private void saveReduceStateSetter(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceStateSetterSaveNode == null) { + reduceStateSetterSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceStateSetterSaveNode, pickler, obj, 0); + } + + private void saveReduceObject(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceObjectSaveNode == null) { + reduceObjectSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceObjectSaveNode, pickler, obj, 0); + } + + private void saveGlobalModuleName(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (globalModuleNameSaveNode == null) { + globalModuleNameSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, globalModuleNameSaveNode, pickler, obj, 0); + } + + private void saveGlobalName(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (globalNameSaveNode == null) { + globalNameSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, globalNameSaveNode, pickler, obj, 0); + } + + private SaveNode createRecursiveSaveNode() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + } + + private void saveRecursive(VirtualFrame frame, SaveNode saveNode, PPickler pickler, Object obj, int persSave) { if (depth < MAX_RECURSION_DEPTH) { - recursiveSaveNode3.execute(frame, pickler, obj, persSave); + saveNode.execute(frame, pickler, obj, persSave); } else { - saveSetupBoundary(frame, recursiveSaveNode3, pickler, obj, persSave); + saveSetupBoundary(frame, saveNode, pickler, obj, persSave); } } @@ -986,9 +1129,12 @@ private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, Has i = 0; pickler.write(this, PickleUtils.OPCODE_MARK); while (nextNode.executeCached(storage, it)) { - save(frame, pickler, getKeyNode.executeCached(storage, it), 0); + Object key = getKeyNode.executeCached(storage, it); if (saveValues) { - save2(frame, pickler, getValueNode.executeCached(storage, it), 0); + saveDictKey(frame, pickler, key); + saveDictValue(frame, pickler, getValueNode.executeCached(storage, it)); + } else { + saveSetElement(frame, pickler, key); } if (++i == PickleUtils.BATCHSIZE) { break; @@ -1015,7 +1161,7 @@ private void saveSetHashingStorage(VirtualFrame frame, PPickler pickler, Hashing HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); while (next.executeCached(storage, it)) { Object item = getKeyNode.executeCached(storage, it); - save(frame, pickler, item, 0); + saveSetElement(frame, pickler, item); } } @@ -1078,8 +1224,8 @@ private void saveDictIteratorBatchUnrolled(VirtualFrame frame, PPickler pickler, }, (Object item) -> { SequenceStorage storage = getTupleStorage(item); - save(frame, pickler, getItem(storage, 0), 0); - save2(frame, pickler, getItem(storage, 1), 0); + saveDictKey(frame, pickler, getItem(storage, 0)); + saveDictValue(frame, pickler, getItem(storage, 1)); }); } @@ -1087,7 +1233,7 @@ private void saveListIteratorBatchUnrolled(VirtualFrame frame, PPickler pickler, saveIteratorBatchedUnrolled(frame, pickler, iterator, PickleUtils.OPCODE_APPEND, PickleUtils.OPCODE_APPENDS, (Object item) -> { }, - (Object item) -> save(frame, pickler, item, 0)); + (Object item) -> saveListElement(frame, pickler, item)); } private void saveIterator(VirtualFrame frame, PPickler pickler, Object iterator, byte opcode, Consumer itemConsumer) { @@ -1107,7 +1253,7 @@ private void saveIterator(VirtualFrame frame, PPickler pickler, Object iterator, private void saveListIterator(VirtualFrame frame, PPickler pickler, Object iterator) { saveIterator(frame, pickler, iterator, PickleUtils.OPCODE_APPEND, - (Object item) -> save(frame, pickler, item, 0)); + (Object item) -> saveListElement(frame, pickler, item)); } private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object iterator) { @@ -1117,8 +1263,8 @@ private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object itera throw raise(TypeError, ErrorMessages.MUST_S_ITER_RETURN_2TUPLE, DICT_ITEMS); } SequenceStorage storage = getTupleStorage(item); - save(frame, pickler, getItem(storage, 0), 0); - save2(frame, pickler, getItem(storage, 1), 0); + saveDictKey(frame, pickler, getItem(storage, 0)); + saveDictValue(frame, pickler, getItem(storage, 1)); }); } @@ -1133,7 +1279,7 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object } if (pid != PNone.NONE) { if (isBin(proto)) { - save(frame, pickler, pid, 1); + savePersistentId(frame, pickler, pid); pickler.write(this, PickleUtils.OPCODE_BINPERSID); } else { final TruffleString pidStr = asString(convertToStr(frame, pid)); @@ -1301,9 +1447,9 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, } if (proto >= 4) { - save(frame, pickler, cls, 0); - save2(frame, pickler, args, 0); - save3(frame, pickler, kwargs, 0); + saveReduceClass(frame, pickler, cls); + saveReduceArgs(frame, pickler, args); + saveReduceKwargs(frame, pickler, kwargs); pickler.write(this, PickleUtils.OPCODE_NEWOBJ_EX); } else { PickleState st = getGlobalState(ctx.getCore()); @@ -1322,8 +1468,8 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, } callable = callStarArgsAndKwArgs(frame, st.partial, newargs, kwargs); - save(frame, pickler, callable, 0); - save2(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this)), 0); + saveReduceCallable(frame, pickler, callable); + saveReduceArgs(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this))); pickler.write(this, PickleUtils.OPCODE_REDUCE); } } else if (useNewobj) { @@ -1379,19 +1525,19 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // function. // Save the class and its __new__ arguments - save(frame, pickler, cls, 0); + saveReduceClass(frame, pickler, cls); Object[] newargs = new Object[argtupSize - 1]; for (int i = 1; i < argtupSize; i++) { newargs[i - 1] = getItem(argtupStorage, i); } newargtup = createTuple(newargs); - save2(frame, pickler, newargtup, 0); + saveReduceArgs(frame, pickler, newargtup); pickler.write(this, PickleUtils.OPCODE_NEWOBJ); } else { profileSeen(SEEN_PLAIN_REDUCE); // Not using NEWOBJ - save(frame, pickler, callable, 0); - save2(frame, pickler, argtup, 0); + saveReduceCallable(frame, pickler, callable); + saveReduceArgs(frame, pickler, argtup); pickler.write(this, PickleUtils.OPCODE_REDUCE); } @@ -1424,7 +1570,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, if (state != null) { profileSeen(SEEN_REDUCE_STATE); if (stateSetter == null) { - save(frame, pickler, state, 0); + saveReduceState(frame, pickler, state); pickler.write(this, PickleUtils.OPCODE_BUILD); } else { // If a state_setter is specified, call it instead of load_build to update obj's @@ -1434,9 +1580,9 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // Finally, because state-updating routines only do in-place modification, the // whole operation has to be stack-transparent. Thus, we finally pop the call's // output from the stack. - save(frame, pickler, stateSetter, 0); - save2(frame, pickler, obj, 0); - save3(frame, pickler, state, 0); + saveReduceStateSetter(frame, pickler, stateSetter); + saveReduceObject(frame, pickler, obj); + saveReduceState(frame, pickler, state); pickler.write(this, PickleUtils.OPCODE_TUPLE2); pickler.write(this, PickleUtils.OPCODE_REDUCE); pickler.write(this, PickleUtils.OPCODE_POP); @@ -1666,8 +1812,8 @@ private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { } HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); - save(frame, pickler, getKeyNode.executeCached(storage, it), 0); - save(frame, pickler, getValueNode.executeCached(storage, it), 0); + saveDictKey(frame, pickler, getKeyNode.executeCached(storage, it)); + saveDictValue(frame, pickler, getValueNode.executeCached(storage, it)); pickler.write(this, PickleUtils.OPCODE_SETITEM); } else { // Write in batches of BATCHSIZE. @@ -1786,7 +1932,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { Object item; if (storage.length() == 1) { item = getItem(storage, 0); - save(frame, pickler, item, 0); + saveListElement(frame, pickler, item); pickler.write(this, PickleUtils.OPCODE_APPEND); return; } @@ -1799,7 +1945,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { pickler.write(this, PickleUtils.OPCODE_MARK); while (total < storage.length()) { item = getItem(storage, total); - save(frame, pickler, item, 0); + saveListElement(frame, pickler, item); total++; if (++thisBatch == PickleUtils.BATCHSIZE) { break; @@ -1931,7 +2077,7 @@ private void storeTupleElements(VirtualFrame frame, PPickler pickler, SequenceSt } profileSeen(SEEN_GENERIC_STORAGE); for (int i = 0; i < len; i++) { - save(frame, pickler, getItem(storage, i), 0); + saveTupleElement(frame, pickler, getItem(storage, i)); } } @@ -2214,8 +2360,8 @@ private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, } if (proto >= 4) { - save(frame, pickler, moduleName, 0); - save(frame, pickler, globalName, 0); + saveGlobalModuleName(frame, pickler, moduleName); + saveGlobalName(frame, pickler, globalName); pickler.write(this, PickleUtils.OPCODE_STACK_GLOBAL); } else if (parent != module) { Object reduceValue = createTuple(st.getattr, createTuple(parent, lastname)); From b877bb5897c6111526f33e0e1199c822b26ccd6c Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 8 Oct 2026 22:43:02 +0200 Subject: [PATCH 106/129] Report loop counts in pickle code (cherry picked from commit dff33e71d943f4c22fafe8dd79f0a2ac38dfa58c) --- .../python/builtins/modules/pickle/PPickler.java | 12 ++++++++++++ .../python/builtins/modules/pickle/PUnpickler.java | 2 ++ .../python/builtins/modules/pickle/PicklerNodes.java | 2 ++ 3 files changed, 16 insertions(+) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 968f29e056..a8223a7ab6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -137,6 +137,7 @@ import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -1953,6 +1954,7 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { } pickler.write(this, PickleUtils.OPCODE_APPENDS); } while (total < storage.length()); + LoopNode.reportLoopCount(this, total); } private void batchIntList(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { @@ -1972,8 +1974,10 @@ private void batchIntList(VirtualFrame frame, PPickler pickler, IntSequenceStora opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getIntItemNormalized(i)); } + LoopNode.reportLoopCount(this, batchEnd - batchStart); pickler.write(this, PickleUtils.OPCODE_APPENDS); } + LoopNode.reportLoopCount(this, length / PickleUtils.BATCHSIZE + (length % PickleUtils.BATCHSIZE == 0 ? 0 : 1)); } private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceStorage storage) { @@ -1993,8 +1997,10 @@ private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceSto opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getLongItemNormalized(i)); } + LoopNode.reportLoopCount(this, batchEnd - batchStart); pickler.write(this, PickleUtils.OPCODE_APPENDS); } + LoopNode.reportLoopCount(this, length / PickleUtils.BATCHSIZE + (length % PickleUtils.BATCHSIZE == 0 ? 0 : 1)); } private void batchDoubleList(VirtualFrame frame, PPickler pickler, DoubleSequenceStorage storage) { @@ -2014,8 +2020,10 @@ private void batchDoubleList(VirtualFrame frame, PPickler pickler, DoubleSequenc opcodeBoundary(frame, pickler); saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); } + LoopNode.reportLoopCount(this, batchEnd - batchStart); pickler.write(this, PickleUtils.OPCODE_APPENDS); } + LoopNode.reportLoopCount(this, length / PickleUtils.BATCHSIZE + (length % PickleUtils.BATCHSIZE == 0 ? 0 : 1)); } private void batchList(VirtualFrame frame, PPickler pickler, int proto, Object iterator) { @@ -2079,6 +2087,7 @@ private void storeTupleElements(VirtualFrame frame, PPickler pickler, SequenceSt for (int i = 0; i < len; i++) { saveTupleElement(frame, pickler, getItem(storage, i)); } + LoopNode.reportLoopCount(this, len); } private void storeIntTupleElements(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { @@ -2087,6 +2096,7 @@ private void storeIntTupleElements(VirtualFrame frame, PPickler pickler, IntSequ opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getIntItemNormalized(i)); } + LoopNode.reportLoopCount(this, storage.length()); } private void storeLongTupleElements(VirtualFrame frame, PPickler pickler, LongSequenceStorage storage) { @@ -2095,6 +2105,7 @@ private void storeLongTupleElements(VirtualFrame frame, PPickler pickler, LongSe opcodeBoundary(frame, pickler); saveLong(pickler, proto, storage.getLongItemNormalized(i)); } + LoopNode.reportLoopCount(this, storage.length()); } private void storeDoubleTupleElements(VirtualFrame frame, PPickler pickler, DoubleSequenceStorage storage) { @@ -2103,6 +2114,7 @@ private void storeDoubleTupleElements(VirtualFrame frame, PPickler pickler, Doub opcodeBoundary(frame, pickler); saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); } + LoopNode.reportLoopCount(this, storage.length()); } private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PTuple obj) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index fa5874818d..b70dc9e32c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -1318,6 +1318,7 @@ private void loadDict(VirtualFrame frame, PUnpickler self) { storage = setHashingStorageItem(frame, storage, key, value); } + LoopNode.reportLoopCount(this, (j - i) / 2); self.stack.clear(i); pDataPush(self, PFactory.createDict(PythonLanguage.get(this), storage)); } @@ -1821,6 +1822,7 @@ private void doSetItems(VirtualFrame frame, PUnpickler self, int x) { } } + LoopNode.reportLoopCount(this, (len - x) / 2); self.stack.clear(x); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 92461803a3..3815619a8d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -642,6 +642,7 @@ private TruffleString[] splitDottedPath(TruffleString name) { parts++; start = dot + 1; } + LoopNode.reportLoopCount(this, parts - 2 + (start < length ? 1 : 0)); TruffleString[] dottedPath = new TruffleString[parts]; TruffleString.SubstringNode substring = ensureTsSubstringNode(); start = 0; @@ -650,6 +651,7 @@ private TruffleString[] splitDottedPath(TruffleString name) { dottedPath[part++] = substring.execute(name, start, dot - start, TS_ENCODING, false); start = dot + 1; } + LoopNode.reportLoopCount(this, part); dottedPath[part] = substring.execute(name, start, length - start, TS_ENCODING, false); return dottedPath; } From c097bfd7aaf35f51e9fbacfc5d1dc77c6f80063f Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Mon, 12 Oct 2026 12:21:05 +0200 Subject: [PATCH 107/129] Avoid out-of-bounds access on list mutation in pickler (cherry picked from commit c99ab1c55ff112feab98af7e6925fdb31603530f) --- .../builtins/modules/pickle/PPickler.java | 70 +++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index a8223a7ab6..635f3a8569 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -746,9 +746,9 @@ protected Object createList(VirtualFrame frame, Object iterable) { return constructListNode.execute(frame, iterable); } - public void opcodeBoundary(VirtualFrame frame, PPickler pickler) { + public boolean opcodeBoundary(VirtualFrame frame, PPickler pickler) { if (!pickler.isFraming() || pickler.frameStart == -1) { - return; + return false; } int frameLen = pickler.outputLen - pickler.frameStart - PickleUtils.FRAME_HEADER_SIZE; if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, frameLen >= PickleUtils.FRAME_SIZE_TARGET)) { @@ -760,8 +760,10 @@ public void opcodeBoundary(VirtualFrame frame, PPickler pickler) { if (pickler.write != null) { flushToFile(frame, pickler); pickler.clearBuffer(); + return true; } } + return false; } public static void handleError(PPickler pickler) { @@ -1913,7 +1915,7 @@ private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickl } private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { - final SequenceStorage storage = obj.getSequenceStorage(); + SequenceStorage storage = obj.getSequenceStorage(); if (pickler.persFunc == null) { if (storage instanceof IntSequenceStorage intStorage) { profileSeen(SEEN_INT_STORAGE); @@ -1953,77 +1955,103 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { } } pickler.write(this, PickleUtils.OPCODE_APPENDS); + // It could have been mutated as a side effect of the reduce calls or the file write + storage = obj.getSequenceStorage(); } while (total < storage.length()); LoopNode.reportLoopCount(this, total); } private void batchIntList(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { + opcodeBoundary(frame, pickler); int proto = pickler.getProto(); - if (storage.length() == 1) { - opcodeBoundary(frame, pickler); + int length = storage.length(); + + if (length == 1) { saveLong(pickler, proto, storage.getIntItemNormalized(0)); pickler.write(this, PickleUtils.OPCODE_APPEND); return; } - int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); pickler.write(this, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { - opcodeBoundary(frame, pickler); + boolean didFlush = opcodeBoundary(frame, pickler); + // To make sure we don't go out-of-bounds if the file write mutated the list + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, didFlush && length != storage.length())) { + length = storage.length(); + batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + if (i >= batchEnd) { + break; + } + } saveLong(pickler, proto, storage.getIntItemNormalized(i)); } - LoopNode.reportLoopCount(this, batchEnd - batchStart); pickler.write(this, PickleUtils.OPCODE_APPENDS); } - LoopNode.reportLoopCount(this, length / PickleUtils.BATCHSIZE + (length % PickleUtils.BATCHSIZE == 0 ? 0 : 1)); + LoopNode.reportLoopCount(this, length); } private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceStorage storage) { + opcodeBoundary(frame, pickler); int proto = pickler.getProto(); - if (storage.length() == 1) { - opcodeBoundary(frame, pickler); + int length = storage.length(); + + if (length == 1) { saveLong(pickler, proto, storage.getLongItemNormalized(0)); pickler.write(this, PickleUtils.OPCODE_APPEND); return; } - int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); pickler.write(this, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { - opcodeBoundary(frame, pickler); + boolean didFlush = opcodeBoundary(frame, pickler); + // To make sure we don't go out-of-bounds if the file write mutated the list + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, didFlush && length != storage.length())) { + length = storage.length(); + batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + if (i >= batchEnd) { + break; + } + } saveLong(pickler, proto, storage.getLongItemNormalized(i)); } - LoopNode.reportLoopCount(this, batchEnd - batchStart); pickler.write(this, PickleUtils.OPCODE_APPENDS); } - LoopNode.reportLoopCount(this, length / PickleUtils.BATCHSIZE + (length % PickleUtils.BATCHSIZE == 0 ? 0 : 1)); + LoopNode.reportLoopCount(this, length); } private void batchDoubleList(VirtualFrame frame, PPickler pickler, DoubleSequenceStorage storage) { + opcodeBoundary(frame, pickler); int proto = pickler.getProto(); - if (storage.length() == 1) { - opcodeBoundary(frame, pickler); + int length = storage.length(); + + if (length == 1) { saveFloat(pickler, proto, storage.getDoubleItemNormalized(0)); pickler.write(this, PickleUtils.OPCODE_APPEND); return; } - int length = storage.length(); for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); pickler.write(this, PickleUtils.OPCODE_MARK); for (int i = batchStart; i < batchEnd; i++) { - opcodeBoundary(frame, pickler); + boolean didFlush = opcodeBoundary(frame, pickler); + // To make sure we don't go out-of-bounds if the file write mutated the list + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, didFlush && length != storage.length())) { + length = storage.length(); + batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + if (i >= batchEnd) { + break; + } + } saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); } - LoopNode.reportLoopCount(this, batchEnd - batchStart); pickler.write(this, PickleUtils.OPCODE_APPENDS); } - LoopNode.reportLoopCount(this, length / PickleUtils.BATCHSIZE + (length % PickleUtils.BATCHSIZE == 0 ? 0 : 1)); + LoopNode.reportLoopCount(this, length); } private void batchList(VirtualFrame frame, PPickler pickler, int proto, Object iterator) { From 56e63f2adf2defc30592e5e7d0941cf1c10d97e8 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 13 Oct 2026 14:30:52 +0200 Subject: [PATCH 108/129] Downsize oversized output bytes (cherry picked from commit 50ce7eebbe624842bf83da960ee502716ee2b0c1) --- .../python/builtins/modules/pickle/PPickler.java | 12 +++++++----- .../modules/pickle/PickleModuleBuiltins.java | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index 635f3a8569..68d31392b7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -368,7 +368,6 @@ public void clearMemo() { } public void clearBuffer() { - this.outputBuffer = new byte[this.outputBuffer.length]; this.outputLen = 0; this.frameStart = -1; } @@ -389,9 +388,12 @@ public void commitFrame() { frameStart = -1; } - public PBytes getString(PythonLanguage language) { - commitFrame(); - return PFactory.createBytes(language, outputBuffer, outputLen); + public PBytes getString(PythonLanguage language, boolean copy) { + if (copy || outputBuffer.length > outputLen * 5 / 4) { + return PFactory.createBytes(language, PythonUtils.arrayCopyOf(outputBuffer, outputLen)); + } else { + return PFactory.createBytes(language, outputBuffer, outputLen); + } } private void writeASCII(Node node, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, @@ -2648,7 +2650,7 @@ public void flush(VirtualFrame frame, PPickler pickler, @Cached CallNode callNode) { assert pickler.write != null; // This will commit the frame first - PBytes output = pickler.getString(language); + PBytes output = pickler.getString(language, true); callNode.execute(frame, pickler.write, output); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java index f58154dafd..bc20d0115d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java @@ -197,7 +197,7 @@ Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, O pickler.setProtocol(inliningTarget, raiseNode, protocol, fixImports); pickler.setBufferCallback(inliningTarget, raiseNode, bufferCallback); dumpNode.execute(frame, pickler, obj); - Object result = pickler.getString(language); + Object result = pickler.getString(language, false); reportSizes(pickler); return result; } From 759f8360311f1c59fde5bb3355f306caf9ad87f8 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 13 Oct 2026 14:35:44 +0200 Subject: [PATCH 109/129] Cap the max pickle buffer/memo size estimate at 15 MiB (cherry picked from commit a1b186e482c55074c7e54dcb82a309c11de746f0) --- .../python/builtins/modules/pickle/PickleModuleBuiltins.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java index bc20d0115d..539038ee45 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java @@ -85,6 +85,7 @@ protected List> getNodeFa /** Learns the capacities reached by successful calls at one builtin node. */ private static final class PicklerSizeProfile { private static final int SHIFT = 3; + private static final long MAX_ESTIMATE = (16L * 1024 * 1024) << SHIFT; @CompilationFinal private long outputEstimate = (long) PickleUtils.WRITE_BUF_SIZE << SHIFT; @CompilationFinal private long memoEstimate = (long) MemoTable.INITIAL_CAPACITY << SHIFT; @@ -112,7 +113,7 @@ void report(PPickler pickler) { private static long update(long shiftedEstimate, int capacity) { long estimate = shiftedEstimate >> SHIFT; - return shiftedEstimate + capacity - estimate; + return Math.min(shiftedEstimate + capacity - estimate, MAX_ESTIMATE); } } From 4868cbf6bca06940d50bf762757f36bb6256289a Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 10:54:57 -0700 Subject: [PATCH 110/129] Format PosixModuleBuiltins after the upstream sync's conflict resolution --- .../graal/python/builtins/modules/PosixModuleBuiltins.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 3ad864f859..c474896891 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -332,7 +332,8 @@ public void postInitialize(Python3Core core) { PosixSupport posixSupport = core.getContext().getPosixSupport(); PythonModule posix = PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 - ? core.lookupBuiltinModule(T_NT) : core.lookupBuiltinModule(T_POSIX); + ? core.lookupBuiltinModule(T_NT) + : core.lookupBuiltinModule(T_POSIX); if (posixSupport.getBackend().toJavaStringUncached().equals("java")) { posix.setAttribute(toTruffleStringUncached("geteuid"), PNone.NO_VALUE); From 27e7c3133381e03808a8ad6a31830e8183b0eeb5 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 13:46:06 -0700 Subject: [PATCH 111/129] ci: run builds and tests on Elide's self-hosted runners GitHub-hosted runners are only used for small jobs now: generating the job matrices, merging test reports, post-merge notifications and the website. Everything that builds or tests GraalPy runs on the self-hosted pool: - the jobs generated from ci.jsonnet (extract_matrix.py maps linux-amd64, linux-aarch64 and windows-amd64 to linux-amd64-cipool, linux-arm64-cipool and windows-amd64-cipool), - abi-check, the wheel builds, the weekly downstream tests and the exotic platform tests. --- .github/scripts/extract_matrix.py | 26 +++++++++++-------- .github/workflows/_downstream-test-common.yml | 4 +-- .../workflows/_downstream-test-oracledb.yml | 8 +++--- .github/workflows/build-wheels.yml | 13 ++++------ .github/workflows/ci-unittests.yml | 2 +- .github/workflows/platforms-tests.yml | 2 +- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/.github/scripts/extract_matrix.py b/.github/scripts/extract_matrix.py index 7347eaae72..23320fbea6 100644 --- a/.github/scripts/extract_matrix.py +++ b/.github/scripts/extract_matrix.py @@ -75,17 +75,21 @@ "ECLIPSE": "https://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops4/R-4.26-202211231800/eclipse-SDK-4.26-linux-gtk-x86_64.tar.gz" } -# Github Runners OSS +# Runner labels by required capabilities. Elide's fork builds and tests on its +# self-hosted runner pool, not on GitHub-hosted runners. +LINUX_AMD64_RUNNER = "linux-amd64-cipool" +LINUX_AARCH64_RUNNER = "linux-arm64-cipool" +WINDOWS_AMD64_RUNNER = "windows-amd64-cipool" OSS = { - "ubuntu-latest": ["linux", "amd64"], - "ubuntu-24.04-arm": ["linux", "aarch64"], - "windows-latest": ["windows", "amd64"] + LINUX_AMD64_RUNNER: ["linux", "amd64"], + LINUX_AARCH64_RUNNER: ["linux", "aarch64"], + WINDOWS_AMD64_RUNNER: ["windows", "amd64"] } # Override unavailable Python versions for some OS/Arch / job name combinations PYTHON_VERSIONS = { - "ubuntu-24.04-arm": "3.12.8", - "ubuntu-latest": "3.12.8", + LINUX_AARCH64_RUNNER: "3.12.8", + LINUX_AMD64_RUNNER: "3.12.8", "style-gate": "3.8.12", "style-ecj-gate": "3.8.12", } @@ -119,7 +123,7 @@ def runs_on(self) -> str: for os, caps in OSS.items(): if all(required in capabilities for required in caps): return os - return "ubuntu-latest" + return LINUX_AMD64_RUNNER @cached_property def name(self) -> str: @@ -132,7 +136,7 @@ def targets(self) -> list[str]: @cached_property def env(self) -> dict[str, str]: environment = self.job.get("environment", {}) | DEFAULT_ENV - if self.runs_on == "windows-latest": + if self.runs_on == WINDOWS_AMD64_RUNNER: def _to_windows_env_format(s: str) -> str: # Replace ${VAR} and $VAR with %VAR% s = re.sub(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}", r"%\1%", s) @@ -180,7 +184,7 @@ def system_packages(self) -> list[str]: k = k[3:] if any(excluded in k for excluded in EXCLUDED_SYSTEM_PACKAGES): continue - system_packages.append(f"'{k}'" if self.runs_on != "windows-latest" else f"{k}") + system_packages.append(f"'{k}'" if self.runs_on != WINDOWS_AMD64_RUNNER else f"{k}") return system_packages @cached_property @@ -191,13 +195,13 @@ def python_packages(self) -> list[str]: key = k[4:] if key in PYTHON_PACKAGES_VERSIONS: continue python_packages.append(f"{key}{v}") - return [f"'{pkg}'" if self.runs_on != "windows-latest" else f"{pkg}" for pkg in python_packages] + return [f"'{pkg}'" if self.runs_on != WINDOWS_AMD64_RUNNER else f"{pkg}" for pkg in python_packages] def get_download_steps(self, key: str, version: str) -> str: download_link = self.get_download_link(key, version) filename = download_link.split('/')[-1] - if self.runs_on == "windows-latest": + if self.runs_on == WINDOWS_AMD64_RUNNER: return (f""" Invoke-WebRequest -Uri {download_link} -OutFile {filename} Expand-Archive -Path {filename} -DestinationPath . diff --git a/.github/workflows/_downstream-test-common.yml b/.github/workflows/_downstream-test-common.yml index 9d97ce7c52..4f7bbd85ee 100644 --- a/.github/workflows/_downstream-test-common.yml +++ b/.github/workflows/_downstream-test-common.yml @@ -29,10 +29,10 @@ jobs: fail-fast: false matrix: os: - - id: ubuntu-latest + - id: linux-amd64-cipool platform: linux arch: amd64 - - id: macos-latest + - id: macos-arm64-cipool platform: macos arch: aarch64 diff --git a/.github/workflows/_downstream-test-oracledb.yml b/.github/workflows/_downstream-test-oracledb.yml index 5e0717866b..b2104ca753 100644 --- a/.github/workflows/_downstream-test-oracledb.yml +++ b/.github/workflows/_downstream-test-oracledb.yml @@ -25,7 +25,7 @@ permissions: jobs: build-numpy-wheels: - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool env: PACKAGES_TO_BUILD: numpy==2.2.6 steps: @@ -58,7 +58,7 @@ jobs: build-pandas-wheels: needs: build-numpy-wheels - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool env: PACKAGES_TO_BUILD: pandas==2.2.3 PIP_FIND_LINKS: ${{ github.workspace }}/dependency-wheels @@ -99,7 +99,7 @@ jobs: build-pyarrow-wheels: needs: build-numpy-wheels - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool env: PACKAGES_TO_BUILD: pyarrow==20.0.0 PIP_FIND_LINKS: ${{ github.workspace }}/dependency-wheels @@ -163,7 +163,7 @@ jobs: fail-fast: false matrix: os: - - id: ubuntu-latest + - id: linux-amd64-cipool platform: linux arch: amd64 diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 082afd840c..d535bf735a 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -28,15 +28,12 @@ permissions: jobs: build_wheels: + # Elide's fork builds on its self-hosted runner pool, not on GitHub-hosted runners. runs-on: >- - ${{ contains(inputs.platform, 'self-hosted-linux-amd64') && fromJson('["self-hosted", "Linux", "X86"]') || - contains(inputs.platform, 'self-hosted-linux-aarch64') && fromJson('["self-hosted", "Linux", "ARM64"]') || - contains(inputs.platform, 'self-hosted-macos') && fromJson('["self-hosted", "macOS"]') || - contains(inputs.platform, 'self-hosted-windows') && fromJson('["self-hosted", "Windows"]') || - contains(inputs.platform, 'linux-amd64') && fromJson('["ubuntu-latest"]') || - contains(inputs.platform, 'linux-aarch64') && fromJson('["ubuntu-24.04-arm"]') || - contains(inputs.platform, 'windows') && fromJson('["windows-latest"]') || - contains(inputs.platform, 'macos') && fromJson('["macos-latest"]') }} + ${{ contains(inputs.platform, 'aarch64') && contains(inputs.platform, 'linux') && 'linux-arm64-cipool' || + contains(inputs.platform, 'linux') && 'linux-amd64-cipool' || + contains(inputs.platform, 'windows') && 'windows-amd64-cipool' || + contains(inputs.platform, 'macos') && 'macos-arm64-cipool' }} container: >- ${{ contains(inputs.platform, 'linux-amd64') && 'quay.io/pypa/manylinux_2_28_x86_64' || contains(inputs.platform, 'linux-aarch64') && 'quay.io/pypa/manylinux_2_28_aarch64' || diff --git a/.github/workflows/ci-unittests.yml b/.github/workflows/ci-unittests.yml index 91035de4d8..5b1a80fed6 100644 --- a/.github/workflows/ci-unittests.yml +++ b/.github/workflows/ci-unittests.yml @@ -11,7 +11,7 @@ permissions: jobs: abi-check: if: github.event.pull_request.draft == false - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.github/workflows/platforms-tests.yml b/.github/workflows/platforms-tests.yml index f0fea75886..2c2982b3ec 100644 --- a/.github/workflows/platforms-tests.yml +++ b/.github/workflows/platforms-tests.yml @@ -9,7 +9,7 @@ permissions: jobs: centos-ppc64le-test: - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 From 11d3a5ed28b73dcd8e53426bbdc8184dbdf5feb0 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 14:04:17 -0700 Subject: [PATCH 112/129] ci: set up Python with uv on self-hosted Linux and macOS runners actions/setup-python only has interpreters for GitHub's runner images, so it failed on the self-hosted Ubuntu 26.04 runners ("The version '3.12.8' with architecture 'x64' was not found for Ubuntu 26.04"). Install the requested version with uv (python-build-standalone) into a virtualenv with pip and put it first on the PATH; Windows keeps setup-python. --- .github/workflows/ci-matrix-gen.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index 8920a5c6b5..d26fc625c8 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -126,9 +126,25 @@ jobs: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 - if: ${{ matrix.python_version }} + if: ${{ runner.os == 'Windows' && matrix.python_version }} with: python-version: ${{ matrix.python_version }} + # actions/setup-python only has interpreters for GitHub's own runner images, so on + # the self-hosted Linux and macOS runners the version comes from uv (python-build-standalone), + # in a virtualenv with pip that is put first on the PATH. + - name: Set up Python with uv + if: ${{ runner.os != 'Windows' && matrix.python_version }} + shell: bash + env: + UV_VERSION: 0.12.20 + PYTHON_VERSION: ${{ matrix.python_version }} + run: | + export UV_INSTALL_DIR="$RUNNER_TEMP/uv/bin" UV_PYTHON_INSTALL_DIR="$RUNNER_TEMP/uv/python" UV_NO_MODIFY_PATH=1 + curl -LsSf "https://astral.sh/uv/${UV_VERSION}/install.sh" | sh + rm -rf "$RUNNER_TEMP/python-venv" + "$UV_INSTALL_DIR/uv" venv --seed --python "$PYTHON_VERSION" "$RUNNER_TEMP/python-venv" + echo "$RUNNER_TEMP/python-venv/bin" >> "$GITHUB_PATH" + "$RUNNER_TEMP/python-venv/bin/python" --version - name: Install python packages on Unix if: ${{ runner.os != 'Windows' && matrix.python_packages }} run: | From ec010da1b4c80f2cc4344f50a5f64c924f9fc18f Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 14:35:47 -0700 Subject: [PATCH 113/129] ci: make the build steps work on persistent self-hosted runners Start every build job from an empty workspace (self-hosted runners keep it, so cloning mx next to the checkout failed with "destination path 'mx' already exists"), set a UTF-8 locale as GitHub's runners have (the JDK otherwise can't open the CA certificates with non-ASCII file names), and read the matrix environment with python3 instead of jq, which not every runner has. --- .github/workflows/ci-matrix-gen.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index d26fc625c8..a354fb0244 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -82,6 +82,17 @@ jobs: matrix: include: ${{ fromJson(needs.generate-tier1.outputs.artifact_matrix) }} steps: &buildsteps + # The self-hosted runners keep their workspace between jobs, and these steps clone + # mx and other repositories next to the checkout, so start from an empty workspace. + - name: Clean workspace + if: runner.os != 'Windows' + shell: bash + run: find "${GITHUB_WORKSPACE:?}" -mindepth 1 -maxdepth 1 -exec rm -rf {} + + - name: Clean workspace (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: Get-ChildItem -Force -LiteralPath $env:GITHUB_WORKSPACE | Remove-Item -Recurse -Force + - name: Process matrix downloads if: ${{ matrix.downloads_steps }} run: | @@ -91,8 +102,13 @@ jobs: shell: bash if: runner.os != 'Windows' run: | + # A UTF-8 locale, as on GitHub's runners: the JDK uses it for file names (some CA + # certificates in /etc/ssl/certs have non-ASCII names). + if [ "$RUNNER_OS" = macOS ]; then echo "LANG=en_US.UTF-8" >> $GITHUB_ENV; echo "LC_ALL=en_US.UTF-8" >> $GITHUB_ENV; + else echo "LANG=C.UTF-8" >> $GITHUB_ENV; echo "LC_ALL=C.UTF-8" >> $GITHUB_ENV; fi matrix_env='${{ toJson(matrix.env) }}' - echo $matrix_env | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> tmp.env + # python3 rather than jq, which the self-hosted runners don't all have. + echo $matrix_env | python3 -c 'import json, sys; [print(f"{k}={v}") for k, v in json.load(sys.stdin).items()]' >> tmp.env while IFS= read -r line; do eval "echo \"$line\"" >> $GITHUB_ENV done < tmp.env From 0f7cb5ac90d2af2139c1cfa1bcb6bebffc264920 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 15:02:31 -0700 Subject: [PATCH 114/129] Update the copyright years of two files the fork changed in 2026 --- .../oracle/graal/python/runtime/PythonImageBuildOptions.java | 2 +- .../graal/python/runtime/sequence/storage/SequenceStorage.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java index 37a5d4ef82..2c16b4003c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java index d7d98ffd7f..e09c50cdbb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, 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. From 4e4626aea5e2896fe8527b500445f5a962407c64 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 15:02:31 -0700 Subject: [PATCH 115/129] ci: keep uv's Python, cache and links inside the job's temp directory On some self-hosted runners uv picked up a broken interpreter ("Python installation is missing a _sysconfigdata_ file"). Use only uv-managed interpreters, a per-job cache and copied (not hard-linked) files. --- .github/workflows/ci-matrix-gen.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index a354fb0244..5162526c2c 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -155,7 +155,10 @@ jobs: UV_VERSION: 0.12.20 PYTHON_VERSION: ${{ matrix.python_version }} run: | + # Everything in the job's temp directory, and only uv-managed interpreters: the runners + # can have partial interpreters (and a shared uv cache) left by earlier jobs. export UV_INSTALL_DIR="$RUNNER_TEMP/uv/bin" UV_PYTHON_INSTALL_DIR="$RUNNER_TEMP/uv/python" UV_NO_MODIFY_PATH=1 + export UV_CACHE_DIR="$RUNNER_TEMP/uv/cache" UV_LINK_MODE=copy UV_PYTHON_PREFERENCE=only-managed curl -LsSf "https://astral.sh/uv/${UV_VERSION}/install.sh" | sh rm -rf "$RUNNER_TEMP/python-venv" "$UV_INSTALL_DIR/uv" venv --seed --python "$PYTHON_VERSION" "$RUNNER_TEMP/python-venv" From c034e12fba3f286625716eb6f547fd915e23baa3 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 15:20:16 -0700 Subject: [PATCH 116/129] ci: install uv's Python afresh in every job The runner temp directory is not emptied between jobs on the self-hosted runners, so a partial interpreter left by an earlier job was reused without downloading ("Python installation is missing a _sysconfigdata_ file"). --- .github/workflows/ci-matrix-gen.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index 5162526c2c..0271d06a19 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -159,6 +159,9 @@ jobs: # can have partial interpreters (and a shared uv cache) left by earlier jobs. export UV_INSTALL_DIR="$RUNNER_TEMP/uv/bin" UV_PYTHON_INSTALL_DIR="$RUNNER_TEMP/uv/python" UV_NO_MODIFY_PATH=1 export UV_CACHE_DIR="$RUNNER_TEMP/uv/cache" UV_LINK_MODE=copy UV_PYTHON_PREFERENCE=only-managed + # The temp directory survives between jobs on these runners: a partial interpreter from an + # earlier job would be reused ("Python installation is missing a _sysconfigdata_ file"). + rm -rf "$RUNNER_TEMP/uv" curl -LsSf "https://astral.sh/uv/${UV_VERSION}/install.sh" | sh rm -rf "$RUNNER_TEMP/python-venv" "$UV_INSTALL_DIR/uv" venv --seed --python "$PYTHON_VERSION" "$RUNNER_TEMP/python-venv" From b75b3039018ebf26ba58c130947c857b3f247248 Mon Sep 17 00:00:00 2001 From: stepan Date: Tue, 13 Oct 2026 14:18:42 +0200 Subject: [PATCH 117/129] Add megamorphic attribute access benchmark (cherry picked from commit 706d73347962e78f11ab0ea55e151458de7f388f) --- .../micro/attribute-access-megamorphic.py | 164 ++++++++++++++++++ mx.graalpython/copyrights/overrides | 1 + mx.graalpython/mx_graalpython_bench_param.py | 2 + 3 files changed, 167 insertions(+) create mode 100644 graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py diff --git a/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py b/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py new file mode 100644 index 0000000000..ecfc0455e3 --- /dev/null +++ b/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py @@ -0,0 +1,164 @@ +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. +# Copyright (c) 2013, Regents of the University of California +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# micro benchmark: megamorphic attribute access inspired by richards + +iteration = 20000 + + +class TaskState(object): + pass + + +class Task(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task0(Task): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task1(Task0): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task2(Task1): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task3(Task2): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task4(Task): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task5(Task4): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task6(Task5): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task7(Task6): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task8(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task9(Task8): + def __init__(self, foo): + Task8.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task10(Task9): + def __init__(self, foo): + Task8.__init__(self, foo) + + +class Task11(Task10): + def __init__(self, foo): + Task8.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task12(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task13(Task12): + def __init__(self, foo): + Task12.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task14(Task13): + def __init__(self, foo): + Task12.__init__(self, foo) + + +class Task15(Task14): + def __init__(self, foo): + Task12.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +TASK_LIST = [Task0(0), Task1(1), Task2(2), Task3(3), + Task4(4), Task5(5), Task6(6), Task7(7), + Task8(8), Task9(9), Task10(10), Task11(11), + Task12(12), Task13(13), Task14(14), Task15(15)] + + +def do_stuff(): + task_list = TASK_LIST + total = 0 + for i in range(iteration): + for t in task_list: + total = (total + t.foo) % 7 + + return total + + +def measure(num): + result = 0 + for i in range(num): # 50000 + result |= do_stuff() + + return result + + +def __benchmark__(num=1000): + return measure(num) + + +def run(): + __benchmark__(num=10) + diff --git a/mx.graalpython/copyrights/overrides b/mx.graalpython/copyrights/overrides index 556e94fda8..36df899701 100644 --- a/mx.graalpython/copyrights/overrides +++ b/mx.graalpython/copyrights/overrides @@ -33,6 +33,7 @@ graalpython/com.oracle.graal.python.benchmarks/python/meso/spectralnorm3.py,benc graalpython/com.oracle.graal.python.benchmarks/python/meso/threadring.py,benchmarks.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/arith-binop.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/arith-modulo-sized.py,zippy.copyright +graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-polymorphic.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-bool.py,zippy.copyright diff --git a/mx.graalpython/mx_graalpython_bench_param.py b/mx.graalpython/mx_graalpython_bench_param.py index 3100fa3cfe..9ad50704fe 100644 --- a/mx.graalpython/mx_graalpython_bench_param.py +++ b/mx.graalpython/mx_graalpython_bench_param.py @@ -64,6 +64,7 @@ MICRO_BENCHMARKS = { 'arith-binop': ITER_10 + ['5'], 'arith-modulo-sized': ITER_10 + ['500'], + 'attribute-access-megamorphic': ITER_10 + ['200'], 'attribute-access-polymorphic': ITER_10 + ['1000'], 'attribute-access': ITER_15 + ['5000'], 'attribute-access-super': ITER_20 + ['5_000'], @@ -161,6 +162,7 @@ 'if-generic': ITER_10 + WARMUP_2 + ['500000'], 'if-generic-non-builtin': ITER_10 + WARMUP_2 + ['500000'], 'if-polymorph': ITER_10 + WARMUP_2 + ['1000000'], + 'attribute-access-megamorphic': ITER_6 + WARMUP_2 + ['13'], 'attribute-access-polymorphic': ITER_6 + WARMUP_2 + ['20'], 'attribute-access': ITER_6 + WARMUP_2 + ['100'], 'attribute-access-super': ITER_6 + WARMUP_2 + ['40'], From f976561f6f477b004a8c35e6e74daaeb974c9d95 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 13 Oct 2026 15:33:49 +0200 Subject: [PATCH 118/129] Add a range specialization to tuple constructor (cherry picked from commit d742f8676518b699722a733533c1a6e613cbd1f4) --- .../python/nodes/builtins/TupleNodes.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java index 375f0f9eaf..89716be70a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java @@ -52,12 +52,14 @@ import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.CreateStorageFromIteratorNode; import com.oracle.graal.python.builtins.objects.iterator.IteratorNodes; import com.oracle.graal.python.builtins.objects.list.PList; +import com.oracle.graal.python.builtins.objects.range.PIntRange; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyTupleCheckNode; import com.oracle.graal.python.nodes.PGuards; import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.NativeObjectSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; @@ -73,6 +75,7 @@ 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.LoopNode; public abstract class TupleNodes { @@ -101,6 +104,23 @@ static PTuple list(PList iterable, return PFactory.createTuple(language, copyNode.execute(inliningTarget, iterable.getSequenceStorage())); } + @Specialization + static PTuple range(PIntRange range, + @Bind Node inliningTarget, + @Bind PythonLanguage language) { + int start = range.getIntStart(); + int step = range.getIntStep(); + int len = range.getIntLength(); + int[] array = new int[len]; + int value = start; + for (int i = 0; i < len; i++) { + array[i] = value; + value += step; + } + LoopNode.reportLoopCount(inliningTarget, len); + return PFactory.createTuple(language, new IntSequenceStorage(array)); + } + @Specialization(guards = "isNativeTuple(iterable)") static PTuple nativeTuple(PythonAbstractNativeObject iterable, @Bind Node inliningTarget, From cda0f007b9be8f8cdbf607fc94115deda95233c0 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 13 Oct 2026 18:39:00 +0200 Subject: [PATCH 119/129] Untag transient test (cherry picked from commit 71c7d3479f06202d971d2dc8f27e9dbadf23ffa7) --- .../src/tests/unittest_tags/test_multiprocessing_spawn.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt index 9e9e08893b..e8b63d57ff 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt @@ -60,7 +60,8 @@ test.test_multiprocessing_spawn.test_manager.WithManagerTestSemaphore.test_bound test.test_multiprocessing_spawn.test_manager.WithManagerTestSemaphore.test_semaphore @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.ChallengeResponseTest.test_challengeresponse @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.MiscTestCase.test__all__ @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github -test.test_multiprocessing_spawn.test_misc.MiscTestCase.test_large_pool @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64-github +# GR-80580 +!test.test_multiprocessing_spawn.test_misc.MiscTestCase.test_large_pool @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64-github test.test_multiprocessing_spawn.test_misc.MiscTestCase.test_spawn_sys_executable_none_allows_import @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.OtherTest.test_answer_challenge_auth_failure @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.OtherTest.test_deliver_challenge_auth_failure @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github From 0d91f61b23f40950fb8d833d3485224de5ec40f5 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 17:56:08 -0700 Subject: [PATCH 120/129] Re-create native compression support when patching a pre-initialized context patchRuntimeInformation() only re-seeded the hash secret and patched the package paths. The native zlib, bz2 and lzma supports are created during image build without native access, so their native functions are null, and in native standalones (which patch a pre-initialized context) BZ2Compressor and BZ2Decompressor failed with a NullPointerException in NativeBz2Support.createStream. This broke the tagged test_tarfile CommandLineTest tests, which run `python -m tarfile` on .tar.bz2 files in the native standalone. Re-create the native supports, the locale, the time zone and the int max str digits from the run-time environment, as upstream's setupRuntimeInformation does when patching. --- .../graal/python/runtime/PythonContext.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 faa508e02e..245ac686a7 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 @@ -1480,8 +1480,23 @@ private void setupRuntimeInformation(boolean isPatching) { isInitialized = true; } + /** + * Runtime information of a pre-initialized context that was captured at image build time and + * must be taken from the run-time environment instead. The native compression supports are + * created without native access during pre-initialization (their native functions are + * {@code null}), so unless they are re-created here, {@code bz2}, {@code zlib} and {@code lzma} + * fail with a {@link NullPointerException} in native standalones. + */ private void patchRuntimeInformation() { initializeHashSecret(); + initializeLocale(); + currentZoneId = env.getTimeZone(); + setIntMaxStrDigits(getOption(PythonOptions.IntMaxStrDigits)); + if (!PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES) { + nativeZlib = NativeZlibSupport.createNative(this, ""); + nativeBz2lib = NativeBz2Support.createNative(this, ""); + nativeLZMA = NativeLZMASupport.createNative(this, ""); + } patchPackagePaths(T_STD_LIB_PLACEHOLDER, getStdlibHome()); repairFrozenPackagePaths(); isInitialized = true; From a706659489d67a2408d49ebbf73e01a6c056a665 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 17:56:08 -0700 Subject: [PATCH 121/129] ci: skip the GraalOS resources job and make the Windows Maven gate runnable python-graalos-resources needs GRAALPY_GRAALOS_ARTIFACT_BASE_URL, an Oracle-internal overlay import that is empty in the public ci.jsonnet, so it fails identically in upstream's GitHub Actions; python-resource-variants consumes its artifact. Exclude both from the generated matrix. python-junit-maven-gate-windows failed because the self-hosted Windows runner has no Chocolatey and no preinstalled Maven; download Maven directly when choco is missing. The gate then builds a delvewheel venv, which needs CPython >= 3.12, so give that job Python 3.12.8 instead of ci.jsonnet's 3.8 (upstream's run fails at that point). --- .github/scripts/extract_matrix.py | 9 +++++++++ .github/workflows/ci-matrix-gen.yml | 31 ++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/.github/scripts/extract_matrix.py b/.github/scripts/extract_matrix.py index 23320fbea6..b5e2ed0df4 100644 --- a/.github/scripts/extract_matrix.py +++ b/.github/scripts/extract_matrix.py @@ -68,6 +68,12 @@ "cpython-gate", "darwin", + + # python-graalos-resources downloads the GraalOS runtime from an Oracle-internal + # location (GRAALPY_GRAALOS_ARTIFACT_BASE_URL, an overlay import that is empty in the + # public ci.jsonnet) and python-resource-variants consumes that artifact. Both fail + # the same way in upstream's own GitHub Actions runs. + "graalos", ) DOWNLOADS_LINKS = { @@ -92,6 +98,9 @@ LINUX_AMD64_RUNNER: "3.12.8", "style-gate": "3.8.12", "style-ecj-gate": "3.8.12", + # The Maven JUnit gate builds a delvewheel venv, which needs CPython >= 3.12 (or an + # Oracle-internal ARTIFACT_DOWNLOAD_SCRIPT); ci.jsonnet's 3.8 fails there upstream as well. + "python-junit-maven-gate-windows": "3.12.8", } EXCLUDED_SYSTEM_PACKAGES = { diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index 0271d06a19..3633befbf5 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -200,12 +200,33 @@ jobs: if: ${{ runner.os == 'Windows' && matrix.system_packages }} run: | $packages = '${{ matrix.system_packages }}' -split ' ' + # The self-hosted Windows runners have no Chocolatey (and no preinstalled Maven, unlike + # GitHub's images), so Maven is downloaded directly when choco is missing; cmake is + # already on their PATH. + $haveChoco = [bool](Get-Command choco -ErrorAction SilentlyContinue) foreach ($pkg in $packages) { - try { - choco install $pkg -y - } catch { - Write-Host "Failed to install $pkg, skipping." - Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Yellow + if ($haveChoco) { + try { + choco install $pkg -y + } catch { + Write-Host "Failed to install $pkg, skipping." + Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Yellow + } + } elseif ($pkg -eq 'maven' -and -not (Get-Command mvn -ErrorAction SilentlyContinue)) { + $mavenVersion = '3.9.9' + $mavenDir = Join-Path $env:RUNNER_TEMP 'maven' + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $mavenDir + New-Item -ItemType Directory -Force $mavenDir | Out-Null + $zip = Join-Path $mavenDir "apache-maven-$mavenVersion-bin.zip" + Invoke-WebRequest -Uri "https://archive.apache.org/dist/maven/maven-3/$mavenVersion/binaries/apache-maven-$mavenVersion-bin.zip" -OutFile $zip + Expand-Archive -Path $zip -DestinationPath $mavenDir + $mavenBin = Join-Path $mavenDir "apache-maven-$mavenVersion\bin" + $mavenBin | Out-File -FilePath $env:GITHUB_PATH -Append + & (Join-Path $mavenBin 'mvn.cmd') --batch-mode --version + } elseif (Get-Command $pkg -ErrorAction SilentlyContinue) { + Write-Host "$pkg is already available: $((Get-Command $pkg).Source)" + } else { + Write-Host "No choco on this runner and no fallback for $pkg, skipping." -ForegroundColor Yellow } } From 8b2e58e25f35f454e6a4f7f20aece9f41739b0e4 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 18:08:29 -0700 Subject: [PATCH 122/129] ci: only apt-get abigail-tools in abi-check when abidiff is missing The self-hosted runners already have it, and an apt-get install there fails whenever dpkg has a half-configured package left by another job (the Maven install pulled openjdk-25-jre-headless, whose postinst fails on a runner without /usr/share/man/man1). --- .github/workflows/ci-unittests.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-unittests.yml b/.github/workflows/ci-unittests.yml index 5b1a80fed6..11fcfc3e2a 100644 --- a/.github/workflows/ci-unittests.yml +++ b/.github/workflows/ci-unittests.yml @@ -18,8 +18,13 @@ jobs: - name: Install libabigail shell: bash run: | - sudo apt-get update - sudo apt-get install -y abigail-tools + # The self-hosted runners keep abigail-tools installed; only touch apt when it is + # missing, so a broken dpkg state left by another job's package install does not fail + # the check. + if ! command -v abidiff >/dev/null; then + sudo apt-get update + sudo apt-get install -y abigail-tools + fi - name: Get mx and labsjdk shell: bash From 66f322e3dfc01374f7b7c7b728e2bfbfc136c312 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 18:29:08 -0700 Subject: [PATCH 123/129] ci: do not run mvn --version right after downloading Maven on Windows The JDK is only fetched in a later step, so the check failed with 'No external JVM found in PATH' and took the step with it. --- .github/workflows/ci-matrix-gen.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index 3633befbf5..bdfa56c688 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -222,7 +222,8 @@ jobs: Expand-Archive -Path $zip -DestinationPath $mavenDir $mavenBin = Join-Path $mavenDir "apache-maven-$mavenVersion\bin" $mavenBin | Out-File -FilePath $env:GITHUB_PATH -Append - & (Join-Path $mavenBin 'mvn.cmd') --batch-mode --version + # Not verified with `mvn --version` here: the JDK is only fetched in a later step. + Write-Host "Installed Maven $mavenVersion to $mavenBin" } elseif (Get-Command $pkg -ErrorAction SilentlyContinue) { Write-Host "$pkg is already available: $((Get-Command $pkg).Source)" } else { From fc2e7968fe2bebc80156e940878292c3a15abc15 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 19:46:25 -0700 Subject: [PATCH 124/129] Initialize the hash secret for fresh (non-pre-initialized) contexts again Fork commit 4b503ff03b moved the patching of pre-initialized contexts into patchRuntimeInformation() and, in doing so, dropped upstream's initializeHashSecret() call from the fresh-context path of setupRuntimeInformation(). Contexts that are not patched from a pre-initialized image, such as the JVM standalone, therefore kept an all-zero hash secret: hash randomization was effectively disabled there and the InitializationEntropySource was never consulted for it, which is what tests/test_entropy_subprocess.py detects (the child never opens the entropy device, or consumes 24 bytes fewer than expected). Restore upstream's call, guarded by !env.isPreInitialization() as before; the patching path keeps its existing call. --- .../src/com/oracle/graal/python/runtime/PythonContext.java | 3 +++ 1 file changed, 3 insertions(+) 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 245ac686a7..5a21500c0a 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 @@ -1458,6 +1458,9 @@ private void setupRuntimeInformation(boolean isPatching) { patchRuntimeInformation(); return; } + if (!env.isPreInitialization()) { + initializeHashSecret(); + } initializeLocale(); currentZoneId = env.getTimeZone(); setIntMaxStrDigits(getOption(PythonOptions.IntMaxStrDigits)); From 97beb9ecc69213704f2dbbb046601e9f6a3bb19a Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 19:48:04 -0700 Subject: [PATCH 125/129] ci: download Maven on Linux when apt-get leaves no mvn on the PATH python-junit-maven-gate-linux-amd64 failed with "No such file or directory: 'mvn'" on a self-hosted runner whose dpkg state is broken: the maven package is unpacked but unconfigured there, and the apt-get failure is tolerated by the install loop. Fall back to a direct download of Maven for jobs that list it, as the Windows step already does. --- .github/workflows/ci-matrix-gen.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index bdfa56c688..6b759207b7 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -188,6 +188,19 @@ jobs: for pkg in ${{ matrix.system_packages }}; do sudo apt-get -qq install "$pkg" || true done + # apt failures are tolerated above, and on a self-hosted runner whose dpkg state is + # broken the maven package can be unpacked but unconfigured (no /usr/bin/mvn), so + # fall back to a direct Maven download when the job needs it and mvn is missing. + case " ${{ matrix.system_packages }} " in *"'maven'"*) + if ! command -v mvn >/dev/null; then + maven_version=3.9.9 + maven_dir="$RUNNER_TEMP/maven" + rm -rf "$maven_dir" && mkdir -p "$maven_dir" + curl -fsSL "https://archive.apache.org/dist/maven/maven-3/$maven_version/binaries/apache-maven-$maven_version-bin.tar.gz" | tar -xz -C "$maven_dir" + echo "$maven_dir/apache-maven-$maven_version/bin" >> "$GITHUB_PATH" + echo "Installed Maven $maven_version to $maven_dir (mvn was not on the PATH after apt-get)" + fi + ;; esac - name: Install system packages on macOS if: ${{ runner.os == 'macOS' && matrix.system_packages }} run: | From 079e5ff628de61b0e9df53e24e3d9ae7c2bde363 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 21:55:29 -0700 Subject: [PATCH 126/129] ci: give the Windows JUnit gate CPython 3.12 as well python-junit-gate-windows runs punittest, which also goes through get_path_with_patchelf and so needs CPython >= 3.12 for the delvewheel venv, like the Maven JUnit gate. --- .github/scripts/extract_matrix.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/scripts/extract_matrix.py b/.github/scripts/extract_matrix.py index b5e2ed0df4..00c9683c12 100644 --- a/.github/scripts/extract_matrix.py +++ b/.github/scripts/extract_matrix.py @@ -98,8 +98,9 @@ LINUX_AMD64_RUNNER: "3.12.8", "style-gate": "3.8.12", "style-ecj-gate": "3.8.12", - # The Maven JUnit gate builds a delvewheel venv, which needs CPython >= 3.12 (or an + # The JUnit gates build a delvewheel venv, which needs CPython >= 3.12 (or an # Oracle-internal ARTIFACT_DOWNLOAD_SCRIPT); ci.jsonnet's 3.8 fails there upstream as well. + "python-junit-gate-windows": "3.12.8", "python-junit-maven-gate-windows": "3.12.8", } From 3eaa7599d19362151241502ff818a0449bf2e8ca Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 13 Oct 2026 21:55:29 -0700 Subject: [PATCH 127/129] Untag two hanging asyncio subprocess tests on linux-aarch64-github PollEventLoopTests.test_subprocess_close_after_finish and test_subprocess_wait_no_same_group time out after 600s in python-tagged-unittest-gate-batch1-linux-aarch64 on the self-hosted runners. test_subprocess_close_after_finish fails the same way in upstream's own GitHub Actions runs (oracle/graalpython run 38434376885, batch1 on x86_64), so these are known-flaky under the GitHub tag set; the linux-x86_64-github tag is kept where the test passes. --- .../src/tests/unittest_tags/test_asyncio.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt index d9183e9829..620734e24c 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt @@ -190,13 +190,14 @@ test.test_asyncio.test_events.PollEventLoopTests.test_run_until_complete @ darwi test.test_asyncio.test_events.PollEventLoopTests.test_run_until_complete_stopped @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_server_close @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_ssl_connect_accepted_socket @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_close_after_finish @ linux-aarch64-github,linux-x86_64-github +# test_subprocess_close_after_finish and test_subprocess_wait_no_same_group hang (600s timeout) +# on the linux-aarch64 GitHub runners; the former also fails in upstream GitHub Actions runs. +test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_close_after_finish @ linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_exec_invalid_args @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github # GR-80225 !test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_exitcode @ darwin-arm64,linux-aarch64-github !test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_shell @ linux-aarch64-github,linux-x86_64 test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_shell_invalid_args @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_wait_no_same_group @ linux-aarch64-github test.test_asyncio.test_events.PollEventLoopTests.test_timeout_rounding @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_unclosed_pipe_transport @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_write_pipe @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github From ac8a6607bcc806349a947f25f812dff7744a5e97 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Wed, 14 Oct 2026 13:54:03 -0700 Subject: [PATCH 128/129] Untag OS-vs-JDK tzdata dependent system-transition tests for the GitHub tag sets ZoneInfoTest[...].test_system_transitions reads the transitions from the OS tzdata in /usr/share/zoneinfo (the path is hard-coded in datetimetester) and compares them with datetime.fromtimestamp(), which GraalPy backs with the JDK's tz rules. The self-hosted linux-aarch64 runners carry Ubuntu 26.04's tzdata 2026c, which changed Africa/Casablanca, Africa/El_Aaiun and America/Edmonton for 2026 relative to the labsjdk's bundled tzdata, so those six cases fail there (python-tagged-unittest-gate-batch6); the amd64 runners will follow once their tzdata is updated. Drop the *-github tags for exactly those cases; the darwin and non-GitHub linux tags are kept. --- .../src/tests/unittest_tags/test_datetime.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt index 577d7e5728..1d87d58c54 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt @@ -1038,10 +1038,13 @@ test.datetimetester.ZoneInfoTest[Africa/Cairo]_Pure.test_gaps @ darwin-arm64,dar test.datetimetester.ZoneInfoTest[Africa/Cairo]_Pure.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +# The system-transition checks for the zones below compare the OS tzdata (/usr/share/zoneinfo) +# with the JDK tz rules that back time.localtime; they fail on the self-hosted GitHub runners +# whose tzdata (2026c) is newer than the labsjdk's, so they are not expected on the *-github tag sets. +test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/Ceuta]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Ceuta]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Ceuta]_Fast.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github @@ -1084,10 +1087,10 @@ test.datetimetester.ZoneInfoTest[Africa/Douala]_Pure.test_gaps @ darwin-arm64,da test.datetimetester.ZoneInfoTest[Africa/Douala]_Pure.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/Freetown]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Freetown]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Freetown]_Fast.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64 @@ -1592,11 +1595,11 @@ test.datetimetester.ZoneInfoTest[America/Dominica]_Pure.test_gaps @ darwin-arm64 test.datetimetester.ZoneInfoTest[America/Dominica]_Pure.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_system_transitions @ linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_system_transitions @ linux-aarch64,linux-x86_64 !test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_system_transitions @ darwin-arm64 test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_system_transitions @ linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_system_transitions @ linux-aarch64,linux-x86_64 !test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_system_transitions @ darwin-arm64 test.datetimetester.ZoneInfoTest[America/Eirunepe]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Eirunepe]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github From ec7170977577f37e4ee6a2f96b163030ae44c9b6 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Wed, 14 Oct 2026 14:23:44 -0700 Subject: [PATCH 129/129] Untag the hanging asyncio no-pipe subprocess tests on linux-amd64-github too PollEventLoopTests.test_subprocess_close_after_finish also timed out in python-tagged-unittest-gate-batch1-linux-amd64 (run 38513924640), so the hang is not specific to aarch64. It reproduces locally on a JVM standalone (8 of 48 runs under parallel load): the test waits for a subprocess with no pipes, so only asyncio's SIGCHLD handler can wake the event loop, but signal.set_wakeup_fd is a no-op stub in GraalPy and the Python handler only runs as an async action once the main thread leaves its native poll(), which only happens when the kernel delivers the signal to that very thread. A real set_wakeup_fd implementation is being prepared separately on fix/signal-set-wakeup-fd. --- .../src/tests/unittest_tags/test_asyncio.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt index 620734e24c..6de50c6cd2 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt @@ -190,9 +190,13 @@ test.test_asyncio.test_events.PollEventLoopTests.test_run_until_complete @ darwi test.test_asyncio.test_events.PollEventLoopTests.test_run_until_complete_stopped @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_server_close @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_ssl_connect_accepted_socket @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -# test_subprocess_close_after_finish and test_subprocess_wait_no_same_group hang (600s timeout) -# on the linux-aarch64 GitHub runners; the former also fails in upstream GitHub Actions runs. -test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_close_after_finish @ linux-x86_64-github +# test_subprocess_close_after_finish, test_subprocess_wait_no_same_group (and the already excluded +# test_subprocess_exitcode) hang until the 600s timeout on the linux-amd64 and linux-aarch64 GitHub +# runners, and the first also fails in upstream's GitHub Actions runs. Root cause: they wait for a +# subprocess with no pipes, so only the SIGCHLD handler can wake the event loop, but +# signal.set_wakeup_fd is a stub in GraalPy and the handler never runs while the main thread is +# blocked in poll() unless the kernel happens to deliver the signal to that thread. A real +# implementation is in progress on branch fix/signal-set-wakeup-fd. test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_exec_invalid_args @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github # GR-80225 !test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_exitcode @ darwin-arm64,linux-aarch64-github