diff --git a/graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/EngineOptionsTests.java b/graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/EngineOptionsTests.java index 1f9824edae..b547ff5300 100644 --- a/graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/EngineOptionsTests.java +++ b/graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/EngineOptionsTests.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 @@ -41,6 +41,7 @@ package com.oracle.graal.python.test.integration; import static com.oracle.graal.python.test.integration.Utils.IS_WINDOWS; +import static com.oracle.graal.python.test.integration.Utils.SUPPORTS_PANAMA; import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeFalse; @@ -57,7 +58,9 @@ public void engineOptions() { assertEquals("java", doit(engine, null)); assertEquals("java", doit(engine, "java")); - assertEquals("native", doit(engine, "native")); + // Native POSIX requires native access downcalls. When unavailable on JDK < 22 in JVM mode, + // requesting the native backend intentionally falls back to Java. + assertEquals(SUPPORTS_PANAMA ? "native" : "java", doit(engine, "native")); engine.close(); } diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py index a1962cbb30..ab78524174 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2024, 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 @@ -119,7 +119,7 @@ class TestCodeobject(CPyExtTestCase): ], cmpfunc=lambda cr, pr: isinstance(cr, types.CodeType), ) - + test_PyCode_NewWithPosOnlyArgs = CPyExtFunction( lambda args: args, lambda: ( @@ -148,6 +148,82 @@ class TestCodeobject(CPyExtTestCase): cmpfunc=lambda cr, pr: isinstance(cr, types.CodeType), ) + test_PyCode_NewWithPosOnlyArgs_native_tuples = CPyExtFunction( + lambda args: args, + lambda: ( + tuple(), + ), + code=""" + static PyObject* make_tuple(const char *a, const char *b, const char *c) { + PyObject *tuple = PyTuple_New(3); + if (tuple == NULL) { + return NULL; + } + PyObject *item0 = PyUnicode_FromString(a); + PyObject *item1 = PyUnicode_FromString(b); + PyObject *item2 = PyUnicode_FromString(c); + if (item0 == NULL || item1 == NULL || item2 == NULL) { + Py_XDECREF(item0); + Py_XDECREF(item1); + Py_XDECREF(item2); + Py_DECREF(tuple); + return NULL; + } + PyTuple_SET_ITEM(tuple, 0, item0); + PyTuple_SET_ITEM(tuple, 1, item1); + PyTuple_SET_ITEM(tuple, 2, item2); + return tuple; + } + + static PyCodeObject* wrap_PyCode_NewWithPosOnlyArgs_native_tuples(PyObject* ignored) { + PyObject *code = PyBytes_FromStringAndSize("", 0); + PyObject *consts = PyTuple_New(0); + PyObject *names = PyTuple_New(0); + PyObject *varnames = make_tuple("a", "b", "c"); + PyObject *freevars = PyTuple_New(0); + PyObject *cellvars = PyTuple_New(0); + PyObject *filename = PyUnicode_FromString("filename"); + PyObject *name = PyUnicode_FromString("name"); + PyObject *qualname = PyUnicode_FromString("module.name"); + PyObject *linetable = PyBytes_FromStringAndSize("", 0); + PyObject *exceptiontable = PyBytes_FromStringAndSize("", 0); + PyCodeObject *result = NULL; + + if (code == NULL || consts == NULL || names == NULL || varnames == NULL || + freevars == NULL || cellvars == NULL || filename == NULL || name == NULL || + qualname == NULL || linetable == NULL || exceptiontable == NULL) { + goto done; + } + result = PyUnstable_Code_NewWithPosOnlyArgs( + 1, 0, 2, 3, 4, 0, + code, consts, names, varnames, + freevars, cellvars, + filename, name, qualname, + 1, linetable, exceptiontable); + + done: + Py_XDECREF(code); + Py_XDECREF(consts); + Py_XDECREF(names); + Py_XDECREF(varnames); + Py_XDECREF(freevars); + Py_XDECREF(cellvars); + Py_XDECREF(filename); + Py_XDECREF(name); + Py_XDECREF(qualname); + Py_XDECREF(linetable); + Py_XDECREF(exceptiontable); + return result; + } + """, + resultspec="O", + resulttype="PyCodeObject*", + argspec="", + arguments=["PyObject* ignored"], + callfunction="wrap_PyCode_NewWithPosOnlyArgs_native_tuples", + cmpfunc=lambda cr, pr: isinstance(cr, types.CodeType), + ) + test_PyCode_Addr2Line = CPyExtFunction( reference_PyCode_Addr2Line, lambda: ( diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_robotparser.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_robotparser.txt index 5ee3aa92a4..78bd330c92 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_robotparser.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_robotparser.txt @@ -35,9 +35,9 @@ test.test_robotparser.InvalidCrawlDelayTest.test_site_maps @ darwin-arm64,linux- test.test_robotparser.InvalidRequestRateTest.test_bad_urls @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_robotparser.InvalidRequestRateTest.test_good_urls @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_robotparser.InvalidRequestRateTest.test_site_maps @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github -test.test_robotparser.NetworkTestCase.test_basic @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github -test.test_robotparser.NetworkTestCase.test_can_fetch @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github -test.test_robotparser.NetworkTestCase.test_read_404 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_robotparser.NetworkTestCase.test_basic @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64-github +test.test_robotparser.NetworkTestCase.test_can_fetch @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64-github +test.test_robotparser.NetworkTestCase.test_read_404 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64-github test.test_robotparser.PasswordProtectedSiteTestCase.testPasswordProtectedSite @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_robotparser.RejectAllRobotsTest.test_bad_urls @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_robotparser.RejectAllRobotsTest.test_good_urls @ 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/code/CodeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java index ee5f900fa9..c409ab4877 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java @@ -49,9 +49,9 @@ import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PNotImplemented; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; -import com.oracle.graal.python.builtins.objects.bytes.PBytes; +import com.oracle.graal.python.builtins.objects.bytes.BytesNodes.GetBytesStorage; import com.oracle.graal.python.builtins.objects.code.CodeBuiltinsClinicProviders.CodeConstructorNodeClinicProviderGen; -import com.oracle.graal.python.builtins.objects.common.SequenceNodes; +import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; 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; @@ -61,12 +61,15 @@ import com.oracle.graal.python.compiler.CodeUnit; import com.oracle.graal.python.compiler.OpCodes; import com.oracle.graal.python.compiler.SourceMap; +import com.oracle.graal.python.lib.PyBytesCheckNode; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectHashNode; +import com.oracle.graal.python.lib.PyTupleCheckNode; import com.oracle.graal.python.lib.RichCmpOp; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PGuards; import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.builtins.TupleNodes.GetTupleStorage; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode; @@ -124,23 +127,32 @@ public abstract static class CodeConstructorNode extends PythonClinicBuiltinNode static PCode call(VirtualFrame frame, @SuppressWarnings("unused") Object cls, int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, - PBytes codestring, PTuple constants, PTuple names, PTuple varnames, + Object codestring, Object constants, Object names, Object varnames, TruffleString filename, TruffleString name, TruffleString qualname, - int firstlineno, PBytes linetable, @SuppressWarnings("unused") PBytes exceptiontable, - PTuple freevars, PTuple cellvars, + int firstlineno, Object linetable, Object exceptiontable, + Object freevars, Object cellvars, @Bind Node inliningTarget, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Cached CodeNodes.CreateCodeNode createCodeNode, - @Cached SequenceNodes.GetObjectArrayNode getObjectArrayNode, + @Cached GetBytesStorage getBytesStorage, + @Cached GetTupleStorage getTupleStorage, + @Cached SequenceStorageNodes.ToArrayNode toArrayNode, + @Cached PyBytesCheckNode bytesCheckNode, + @Cached PyTupleCheckNode tupleCheckNode, @Cached CastToTruffleStringNode castToTruffleStringNode) { - byte[] codeBytes = bufferLib.getCopiedByteArray(codestring); - byte[] linetableBytes = bufferLib.getCopiedByteArray(linetable); - - Object[] constantsArr = getObjectArrayNode.execute(inliningTarget, constants); - TruffleString[] namesArr = objectArrayToTruffleStringArray(inliningTarget, getObjectArrayNode.execute(inliningTarget, names), castToTruffleStringNode); - TruffleString[] varnamesArr = objectArrayToTruffleStringArray(inliningTarget, getObjectArrayNode.execute(inliningTarget, varnames), castToTruffleStringNode); - TruffleString[] freevarsArr = objectArrayToTruffleStringArray(inliningTarget, getObjectArrayNode.execute(inliningTarget, freevars), castToTruffleStringNode); - TruffleString[] cellcarsArr = objectArrayToTruffleStringArray(inliningTarget, getObjectArrayNode.execute(inliningTarget, cellvars), castToTruffleStringNode); + byte[] codeBytes = getBytes(inliningTarget, codestring, bytesCheckNode, getBytesStorage, bufferLib); + byte[] linetableBytes = getBytes(inliningTarget, linetable, bytesCheckNode, getBytesStorage, bufferLib); + checkBytes(inliningTarget, exceptiontable, bytesCheckNode); + + Object[] constantsArr = getTupleArray(inliningTarget, constants, tupleCheckNode, getTupleStorage, toArrayNode); + TruffleString[] namesArr = objectArrayToTruffleStringArray(inliningTarget, + getTupleArray(inliningTarget, names, tupleCheckNode, getTupleStorage, toArrayNode), castToTruffleStringNode); + TruffleString[] varnamesArr = objectArrayToTruffleStringArray(inliningTarget, + getTupleArray(inliningTarget, varnames, tupleCheckNode, getTupleStorage, toArrayNode), castToTruffleStringNode); + TruffleString[] freevarsArr = objectArrayToTruffleStringArray(inliningTarget, + getTupleArray(inliningTarget, freevars, tupleCheckNode, getTupleStorage, toArrayNode), castToTruffleStringNode); + TruffleString[] cellcarsArr = objectArrayToTruffleStringArray(inliningTarget, + getTupleArray(inliningTarget, cellvars, tupleCheckNode, getTupleStorage, toArrayNode), castToTruffleStringNode); return createCodeNode.execute(frame, argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize, flags, @@ -150,15 +162,27 @@ static PCode call(VirtualFrame frame, @SuppressWarnings("unused") Object cls, in firstlineno, linetableBytes); } - @Fallback - @SuppressWarnings("unused") - static PCode call(Object cls, Object argcount, Object kwonlyargcount, Object posonlyargcount, - Object nlocals, Object stacksize, Object flags, - Object codestring, Object constants, Object names, Object varnames, - Object filename, Object name, Object qualname, - Object firstlineno, Object linetable, Object exceptiontable, - Object freevars, Object cellvars, - @Bind Node inliningTarget) { + private static byte[] getBytes(Node inliningTarget, Object object, PyBytesCheckNode bytesCheckNode, + GetBytesStorage getBytesStorage, PythonBufferAccessLibrary bufferLib) { + checkBytes(inliningTarget, object, bytesCheckNode); + return bufferLib.getCopiedByteArray(getBytesStorage.execute(inliningTarget, object)); + } + + private static void checkBytes(Node inliningTarget, Object object, PyBytesCheckNode bytesCheckNode) { + if (!bytesCheckNode.execute(inliningTarget, object)) { + throw invalidArgs(inliningTarget); + } + } + + private static Object[] getTupleArray(Node inliningTarget, Object object, PyTupleCheckNode tupleCheckNode, + GetTupleStorage getTupleStorage, SequenceStorageNodes.ToArrayNode toArrayNode) { + if (!tupleCheckNode.execute(inliningTarget, object)) { + throw invalidArgs(inliningTarget); + } + return toArrayNode.execute(inliningTarget, getTupleStorage.execute(inliningTarget, object)); + } + + private static RuntimeException invalidArgs(Node inliningTarget) { throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.INVALID_ARGS, "code"); } diff --git a/mx.graalpython/mx_graalpython.py b/mx.graalpython/mx_graalpython.py index d252beb5b3..b660579a63 100644 --- a/mx.graalpython/mx_graalpython.py +++ b/mx.graalpython/mx_graalpython.py @@ -1083,8 +1083,8 @@ def graalpy_standalone_home(standalone_type, enterprise=False, dev=False, build= launcher = os.path.join(python_home, 'bin', _graalpy_launcher()) out = mx.OutputCapture() - mx.run([launcher, "-c", "print(__graalpython__.is_bytecode_dsl_interpreter)"], nonZeroIsFatal=False, out=out, err=out) - is_bytecode_dsl_interpreter = out.data.strip() == "True" + mx.run([launcher, "-c", "print('__GRAALPY_BYTECODE_DSL_INTERPRETER__ =', __graalpython__.is_bytecode_dsl_interpreter)"], nonZeroIsFatal=False, out=out, err=out) + is_bytecode_dsl_interpreter = "__GRAALPY_BYTECODE_DSL_INTERPRETER__ = True" in out.data if is_bytecode_dsl_interpreter != BYTECODE_DSL_INTERPRETER: requested = "Bytecode DSL" if BYTECODE_DSL_INTERPRETER else "Manual" actual = "Bytecode DSL" if is_bytecode_dsl_interpreter else "Manual" diff --git a/mx.graalpython/suite.py b/mx.graalpython/suite.py index 6edf3e0770..3927be5d8b 100644 --- a/mx.graalpython/suite.py +++ b/mx.graalpython/suite.py @@ -53,7 +53,7 @@ }, { "name": "tools", - "version": "05a7c7f5dffbd2dccab1cabf1e13a200bffe0673", + "version": "57dfd6f81702c93d7707a9cd101ae1348307d612", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"}, @@ -61,7 +61,7 @@ }, { "name": "regex", - "version": "05a7c7f5dffbd2dccab1cabf1e13a200bffe0673", + "version": "57dfd6f81702c93d7707a9cd101ae1348307d612", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"},