diff --git a/graalpython/com.oracle.graal.python.cext/src/abstract.c b/graalpython/com.oracle.graal.python.cext/src/abstract.c index d2c2f1cd76..e10c44ba5d 100644 --- a/graalpython/com.oracle.graal.python.cext/src/abstract.c +++ b/graalpython/com.oracle.graal.python.cext/src/abstract.c @@ -2983,9 +2983,13 @@ PyObject_GetIter(PyObject *o) return res; } } -#if 0 // GraalPy change PyObject * PyObject_GetAIter(PyObject *o) { + // GraalPy change: upcall for managed objects + if (points_to_py_handle_space(o)) { + return GraalPyPrivate_Object_GetAIter(o); + } + PyTypeObject *t = Py_TYPE(o); unaryfunc f; @@ -3002,7 +3006,7 @@ PyObject_GetAIter(PyObject *o) { } return it; } -#endif // GraalPy change + int PyIter_Check(PyObject *obj) { @@ -3010,7 +3014,7 @@ PyIter_Check(PyObject *obj) return (tp->tp_iternext != NULL && tp->tp_iternext != &_PyObject_NextNotImplemented); } -#if 0 // GraalPy change + int PyAIter_Check(PyObject *obj) { @@ -3020,6 +3024,7 @@ PyAIter_Check(PyObject *obj) tp->tp_as_async->am_anext != &_PyObject_NextNotImplemented); } +#if 0 // GraalPy change /* Return next item. * If an error occurs, return NULL. PyErr_Occurred() will be true. * If the iteration terminates normally, return NULL and clear the diff --git a/graalpython/com.oracle.graal.python.cext/src/capi.c b/graalpython/com.oracle.graal.python.cext/src/capi.c index c58e2eaf5b..90a636123a 100644 --- a/graalpython/com.oracle.graal.python.cext/src/capi.c +++ b/graalpython/com.oracle.graal.python.cext/src/capi.c @@ -43,6 +43,7 @@ #include #include "pycore_crossinterp.h" // _PyCrossInterpreterData +#include "pycore_dtoa.h" // _PyDtoa_Init #include "pycore_gc.h" // _PyGC_InitState #include "pycore_object.h" // _Py_GetConstant_Init #include "pycore_time.h" // _PyTime_round_t, _Py_clock_info_t @@ -618,6 +619,7 @@ PyAPI_FUNC(PyThreadState **) initialize_graal_capi(void **builtin_closures, GCSt initialize_bufferprocs(); initialize_gc_types_related_slots(); _PyFloat_InitState(NULL); + _PyDtoa_Init(_PyInterpreterState_GET()); // TODO: initialize during cext initialization doesn't work at the moment Py_FileSystemDefaultEncoding = "utf-8"; // strdup(PyUnicode_AsUTF8(GraalPyPrivate_FileSystemDefaultEncoding())); diff --git a/graalpython/com.oracle.graal.python.cext/src/listobject.c b/graalpython/com.oracle.graal.python.cext/src/listobject.c index f001263af4..08550223d4 100644 --- a/graalpython/com.oracle.graal.python.cext/src/listobject.c +++ b/graalpython/com.oracle.graal.python.cext/src/listobject.c @@ -48,7 +48,7 @@ _list_clear(PyListObject *a) /* Because XDECREF can recursively invoke operations on this list, we make it empty first. */ - i = GraalPyPrivate_List_ClearManagedOrGetItems((PyObject *)a, &item); + i = GraalPyPrivate_List_TruncateNativeStorage((PyObject *)a, &item); if (i > 0) { assert(item != NULL); while (--i >= 0) { diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py index f21d45bfba..dd2183eb2b 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py @@ -120,6 +120,38 @@ def _reference_next(args): except BaseException: raise SystemError + +class Iterator: + def __iter__(self): + return self + + def __next__(self): + raise StopIteration + + +class Iterable: + def __iter__(self): + return Iterator() + + +class AsyncIterator: + def __aiter__(self): + return self + + async def __anext__(self): + raise StopAsyncIteration + + +class AsyncIterable: + def __aiter__(self): + return AsyncIterator() + + +class BadAsyncIterable: + def __aiter__(self): + return object() + + def raise_type_error(): raise TypeError @@ -741,6 +773,48 @@ def test___name__(self): class TestAbstract(CPyExtTestCase): + test_PyIter_Check = CPyExtFunction( + lambda args: hasattr(type(args[0]), "__next__"), + lambda: ( + (iter(()),), + (Iterator(),), + (Iterable(),), + (AsyncIterator(),), + (object(),), + ), + resultspec="i", + argspec="O", + arguments=["PyObject* object"], + ) + + test_PyAIter_Check = CPyExtFunction( + lambda args: hasattr(type(args[0]), "__anext__"), + lambda: ( + (AsyncIterator(),), + (AsyncIterable(),), + (Iterator(),), + (object(),), + ), + resultspec="i", + argspec="O", + arguments=["PyObject* object"], + ) + + test_PyObject_GetAIter = CPyExtFunction( + lambda args: aiter(args[0]), + lambda: ( + (AsyncIterator(),), + (AsyncIterable(),), + (BadAsyncIterable(),), + (Iterator(),), + (object(),), + ), + resultspec="O", + argspec="O", + arguments=["PyObject* object"], + cmpfunc=lambda x, y: type(x) is type(y) and (not isinstance(x, BaseException) or str(x) == str(y)), + ) + test_PyNumber_Absolute = CPyExtFunction( lambda args: abs(args[0]), _default_unarop_args, diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_ceval.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_ceval.py index 468e694a04..a7307bb8a4 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_ceval.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_ceval.py @@ -89,6 +89,33 @@ def test_PyEval_GetGlobals(self): ) assert Tester.get_globals() is globals() + def test_PyEval_GetLocals(self): + Tester = CPyExtType( + "GetLocalsTester", + code=""" + static PyObject* get_locals(PyObject* unused) { + return Py_NewRef(PyEval_GetLocals()); + } + """, + tp_methods='{"get_locals", (PyCFunction)get_locals, METH_NOARGS | METH_STATIC, NULL}', + ) + + value = 1 + first = Tester.get_locals() + assert first["value"] == 1 + first["value"] = 2 + assert value == 1 + + marker = object() + second = Tester.get_locals() + assert second is first + assert second["value"] == 1 + assert second["marker"] is marker + + namespace = {"Tester": Tester} + exec("result = Tester.get_locals()", namespace) + assert namespace["result"] is namespace + def test_PyEval_GetFrameObjects(self): Tester = CPyExtType( "GetFrameObjectsTester", diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_frame.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_frame.py index 2cae728410..64ac7b9aaa 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_frame.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_frame.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, 2024, 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 @@ -39,7 +39,7 @@ import sys -from . import CPyExtTestCase, CPyExtFunction, unhandled_error_compare +from . import CPyExtTestCase, CPyExtFunction, CPyExtType, unhandled_error_compare test_frame = sys._getframe(0) test_frame_no_back = test_frame @@ -49,6 +49,24 @@ class TestMisc(CPyExtTestCase): + def test_PyFrame_GetLocals_proxy(self): + Tester = CPyExtType( + "GetFrameLocalsTester", + code=""" + static PyObject* get_locals(PyObject* unused, PyObject* frame) { + return PyFrame_GetLocals((PyFrameObject*)frame); + } + """, + tp_methods='{"get_locals", (PyCFunction)get_locals, METH_O | METH_STATIC, NULL}', + ) + + value = 1 + frame = sys._getframe() + locals_proxy = Tester.get_locals(frame) + assert type(locals_proxy) is type(frame.f_locals) + locals_proxy["value"] = 2 + assert value == 2 + test_PyFrame_GetCode = CPyExtFunction( lambda args: args[0].f_code, lambda: ( diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_list.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_list.py index 277fd020c1..33cc7b430c 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_list.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_list.py @@ -116,6 +116,14 @@ def _reference_extend(args): return listObj +def _reference_clear(args): + listObj = args[0] + if not isinstance(listObj, list): + raise SystemError("expected list type") + listObj.clear() + return listObj + + def _wrap_list_fun(fun, since=0, default=None): def wrapped_fun(args): if not isinstance(args[0], list): @@ -506,3 +514,26 @@ def test_clear_native_storage_gc(self): callfunction="wrap_PyList_Reverse", cmpfunc=unhandled_error_compare ) + + test_PyList_Clear = CPyExtFunction( + _reference_clear, + lambda: ( + ([],), + ([1, 2, 3],), + (DummyListSubclass([1, 2, 3]),), + ((),), + (DummyClass(),), + ), + code='''PyObject* wrap_PyList_Clear(PyObject* list) { + if (PyList_Clear(list)) { + return NULL; + } + return Py_NewRef(list); + } + ''', + resultspec="O", + argspec='O', + arguments=["PyObject* list"], + callfunction="wrap_PyList_Clear", + cmpfunc=unhandled_error_compare + ) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py index 38fd5ec4d2..057259dd59 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py @@ -136,6 +136,15 @@ def _reference_from_native_bytes(args): return int.from_bytes(data, byteorder, signed=signed) +def _reference_from_unsigned_native_bytes(args): + data, flags = args + if flags == -1 or flags & 2: + byteorder = sys.byteorder + else: + byteorder = 'little' if flags & 1 else 'big' + return int.from_bytes(data, byteorder, signed=False) + + def _reference_as_native_bytes(args): value, size, flags, expected_size = args if flags == -1 or flags & 2: @@ -219,6 +228,13 @@ def _int_examples(): class TestPyLong(CPyExtTestCase): + test_PyLong_GetInfo = CPyExtFunction( + lambda args: sys.int_info, + lambda: ((),), + resultspec="O", + argspec="", + arguments=[], + ) def test_native_long_subtype_has_native_layout(self): NativeLongWithMember = CPyExtType( @@ -708,6 +724,26 @@ def test_native_long_subtype_has_native_layout(self): cmpfunc=unhandled_error_compare, ) + test_PyLong_FromUnsignedNativeBytes = CPyExtFunction( + _reference_from_unsigned_native_bytes, + lambda: ( + (b'', 0), + (b'\x00', 0), + (b'\xff', 0), + (b'\xff', 4), + (b'\x80\x00', 0), + (b'\x80\x00', 1), + (b'\x00\x80', 1), + (b'\xff\x00', 2), + (b'\xff\x00', 3), + (b'\x01\x23\x45\x67\x89\xab\xcd\xef\x01', 0), + ), + resultspec="O", + argspec="y#i", + arguments=["const char* buffer", "Py_ssize_t size", "int flags"], + cmpfunc=unhandled_error_compare, + ) + test_PyLong_AsNativeBytes = CPyExtFunction( _reference_as_native_bytes, lambda: ( 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 4c56340692..f0039a3fbc 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 @@ -171,7 +171,6 @@ import com.oracle.graal.python.compiler.ParserCallbacksImpl; import com.oracle.graal.python.compiler.bytecode_dsl.BytecodeDSLCompiler; import com.oracle.graal.python.lib.IteratorExhausted; -import com.oracle.graal.python.lib.PyAIterCheckNode; import com.oracle.graal.python.lib.PyBytesCheckNode; import com.oracle.graal.python.lib.PyCallableCheckNode; import com.oracle.graal.python.lib.PyEvalGetGlobals; @@ -191,6 +190,7 @@ import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectDir; import com.oracle.graal.python.lib.PyObjectFormat; +import com.oracle.graal.python.lib.PyObjectGetAIter; import com.oracle.graal.python.lib.PyObjectGetAttr; import com.oracle.graal.python.lib.PyObjectGetAttrO; import com.oracle.graal.python.lib.PyObjectGetIter; @@ -2428,21 +2428,8 @@ public abstract static class AIter extends PythonUnaryBuiltinNode { @Specialization static Object doGeneric(VirtualFrame frame, Object arg, @Bind Node inliningTarget, - @Cached GetObjectSlotsNode getSlots, - @Cached CallSlotUnaryNode callSlot, - @Cached PyAIterCheckNode checkNode, - @Cached GetClassNode getClassNode, - @Cached PRaiseNode raiseNode) { - TpSlots slots = getSlots.execute(inliningTarget, arg); - if (slots.am_aiter() == null) { - throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.OBJECT_NOT_ASYNC_ITERABLE, arg); - } - Object asyncIterator = callSlot.execute(frame, inliningTarget, slots.am_aiter(), arg); - if (!checkNode.execute(inliningTarget, asyncIterator)) { - throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.AITER_RETURNED_NOT_ASYNC_ITERATOR, - getClassNode.execute(inliningTarget, asyncIterator)); - } - return asyncIterator; + @Cached PyObjectGetAIter getAIter) { + return getAIter.execute(frame, inliningTarget, arg); } } 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 53a2cdf266..28c8dd4eda 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 @@ -540,7 +540,7 @@ public void initialize(Python3Core core) { 2, // FLT_RADIX 1 // FLT_ROUNDS )); - addBuiltinConstant("int_info", PFactory.createStructSeq(language, INT_INFO_DESC, 32, 4, INT_DEFAULT_MAX_STR_DIGITS, INT_MAX_STR_DIGITS_THRESHOLD)); + addBuiltinConstant("int_info", createIntInfo(language)); addBuiltinConstant("hash_info", PFactory.createStructSeq(language, HASH_INFO_DESC, 64, // width HASH_MODULUS, // modulus @@ -600,6 +600,10 @@ public void initialize(Python3Core core) { postInitialize0(core); } + public static PTuple createIntInfo(PythonLanguage language) { + return PFactory.createStructSeq(language, INT_INFO_DESC, 32, 4, INT_DEFAULT_MAX_STR_DIGITS, INT_MAX_STR_DIGITS_THRESHOLD); + } + public void postInitialize0(Python3Core core) { super.postInitialize(core); PythonModule sys = core.lookupBuiltinModule(T_SYS); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCEvalBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCEvalBuiltins.java index ca70773d50..ba9df964e7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCEvalBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCEvalBuiltins.java @@ -65,6 +65,7 @@ import com.oracle.graal.python.builtins.objects.code.CodeNodes; import com.oracle.graal.python.builtins.objects.code.PCode; import com.oracle.graal.python.builtins.objects.common.SequenceNodes; +import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.frame.PFrame; import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PFunction; @@ -185,6 +186,27 @@ static long PyEval_GetGlobals() { return globals != null ? ToNativeBorrowedNode.executeUncached(globals) : NULLPTR; } + @CApiBuiltin(ret = PyObjectBorrowed, args = {}, call = Direct) + static long PyEval_GetLocals() { + PFrame frame = ReadFrameNode.getUncached().getCurrentPythonFrame(null, CallerFlags.NEEDS_LOCALS); + if (frame == null) { + throw PRaiseNode.raiseStatic(null, SystemError, ErrorMessages.FRAME_DOES_NOT_EXIST); + } + Object locals = GetFrameLocalsNode.executeUncached(frame, true); + if (frame.getCustomLocals() != null) { + return ToNativeBorrowedNode.executeUncached(locals); + } + PDict localsSnapshot = (PDict) locals; + PDict localsCache = frame.getEvalLocalsCache(); + if (localsCache == null) { + localsCache = localsSnapshot; + frame.setEvalLocalsCache(localsCache); + } else { + localsCache.update(localsSnapshot); + } + return ToNativeBorrowedNode.executeUncached(localsCache); + } + @CApiBuiltin(ret = PyObjectRawPointer, args = {}, call = Direct) static long PyEval_GetFrameGlobals() { PythonObject globals = PyEvalGetGlobals.executeUncached(null); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFrameBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFrameBuiltins.java index a494d0790a..8776470c07 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFrameBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFrameBuiltins.java @@ -48,6 +48,7 @@ import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer; import static com.oracle.graal.python.runtime.PythonContext.NATIVE_NULL; +import com.oracle.graal.python.PythonLanguage; 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.CApiUnaryBuiltinNode; @@ -55,7 +56,9 @@ import com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor; import com.oracle.graal.python.builtins.objects.frame.FrameBuiltins; import com.oracle.graal.python.builtins.objects.frame.PFrame; -import com.oracle.graal.python.nodes.frame.GetFrameLocalsNode; +import com.oracle.graal.python.nodes.frame.ReadFrameNode; +import com.oracle.graal.python.runtime.CallerFlags; +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.Specialization; @@ -94,8 +97,12 @@ abstract static class PyFrame_GetLocals extends CApiUnaryBuiltinNode { @Specialization static Object get(PFrame frame, @Bind Node inliningTarget, - @Cached GetFrameLocalsNode getFrameLocalsNode) { - return getFrameLocalsNode.execute(null, inliningTarget, frame, false); + @Cached ReadFrameNode readFrameNode) { + frame = readFrameNode.ensureFresh(null, frame, CallerFlags.NEEDS_MATERIALIZED_LOCALS); + if (frame.getCustomLocals() != null) { + return frame.getCustomLocals(); + } + return PFactory.createFrameLocalsProxy(PythonLanguage.get(inliningTarget), frame); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextListBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextListBuiltins.java index 3b0101af52..7b25500031 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextListBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextListBuiltins.java @@ -66,9 +66,7 @@ import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiTernaryBuiltinNode; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode; import com.oracle.graal.python.builtins.objects.PNone; -import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; -import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.XDecRefPointerNode; import com.oracle.graal.python.builtins.objects.cext.capi.PySequenceArrayWrapper; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.GetItemScalarNode; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ListGeneralizationNode; @@ -85,6 +83,7 @@ import com.oracle.graal.python.nodes.builtins.TupleNodes.ConstructTupleNode; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.graal.python.runtime.sequence.storage.EmptySequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.NativeObjectSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; @@ -360,31 +359,33 @@ static int error(@SuppressWarnings("unused") Object self, } } + @CApiBuiltin(ret = Int, args = {PyObject}, call = Direct) + abstract static class PyList_Clear extends CApiUnaryBuiltinNode { + + @Specialization + static int clear(PList self) { + self.setSequenceStorage(EmptySequenceStorage.INSTANCE); + return 0; + } + + @Fallback + static int error(@SuppressWarnings("unused") Object self, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC); + } + } + @CApiBuiltin(ret = INT64_T, args = {PyObject, Pointer}, call = Ignored) - abstract static class GraalPyPrivate_List_ClearManagedOrGetItems extends CApiBinaryBuiltinNode { + abstract static class GraalPyPrivate_List_TruncateNativeStorage extends CApiBinaryBuiltinNode { @Specialization - static long doGeneric(PList self, long outItems, - @Bind Node inliningTarget, - @Cached XDecRefPointerNode xDecRefPointerNode) { + static long doGeneric(PList self, long outItems) { SequenceStorage sequenceStorage = self.getSequenceStorage(); if (sequenceStorage instanceof NativeObjectSequenceStorage nativeStorage) { writePtr(outItems, nativeStorage.getPtr()); int length = nativeStorage.length(); nativeStorage.setNewLength(0); return length; - } else { - assert sequenceStorage instanceof ObjectSequenceStorage; - ObjectSequenceStorage objectStorage = (ObjectSequenceStorage) sequenceStorage; - - for (int i = objectStorage.length(); --i >= 0;) { - Object item = objectStorage.getObjectItemNormalized(i); - if (item instanceof PythonAbstractNativeObject nativeObject) { - xDecRefPointerNode.execute(inliningTarget, nativeObject.getPtr()); - // replace the item to avoid re-visiting - objectStorage.setObjectItemNormalized(i, PNone.NONE); - } - } } return 0; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextLongBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextLongBuiltins.java index c1c13d3356..8d2b01e021 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextLongBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextLongBuiltins.java @@ -58,14 +58,15 @@ import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.SIZE_T; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.UNSIGNED_CHAR_PTR; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.UNSIGNED_LONG_LONG; -import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.readByteArrayElements; import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; +import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.readByteArrayElements; import java.math.BigInteger; import java.nio.ByteOrder; import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.modules.SysModuleBuiltins; 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; @@ -74,26 +75,26 @@ import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.CastToNativeLongNode; +import com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor; 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.capi.transitions.ArgDescriptor; import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.ConvertPIntToPrimitiveNode; import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.TransformPExceptionToNativeCachedNode; import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodesFactory.ConvertPIntToPrimitiveNodeGen; import com.oracle.graal.python.builtins.objects.ints.IntBuiltins; import com.oracle.graal.python.builtins.objects.ints.IntNodes; import com.oracle.graal.python.builtins.objects.ints.PInt; +import com.oracle.graal.python.lib.PyLongCheckNode; import com.oracle.graal.python.lib.PyLongFromDoubleNode; import com.oracle.graal.python.lib.PyLongFromUnicodeObject; -import com.oracle.graal.python.lib.PyLongCheckNode; import com.oracle.graal.python.lib.PyNumberIndexNode; -import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.util.CastToJavaBigIntegerNode; import com.oracle.graal.python.runtime.exception.PException; +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; @@ -112,6 +113,12 @@ public final class PythonCextLongBuiltins { + @CApiBuiltin(ret = PyObjectTransfer, args = {}, call = Direct) + static long PyLong_GetInfo() { + Object result = SysModuleBuiltins.createIntInfo(PythonLanguage.get(null)); + return PythonToNativeInternalNode.executeNewRefUncached(result); + } + @CApiBuiltin(ret = Py_ssize_t, args = {PyLongObject}, call = Ignored) abstract static class GraalPyPrivate_Long_DigitCount extends CApiUnaryBuiltinNode { @@ -379,12 +386,7 @@ static long PyLong_AsNativeBytes(long objectPtr, long buffer, long size, int fla throw PRaiseNode.raiseStatic(null, ValueError, ErrorMessages.CANNOT_CONVERT_NEGATIVE_INT); } - boolean littleEndian; - if (flags == -1 || (flags & NATIVE_ENDIAN) != 0) { - littleEndian = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; - } else { - littleEndian = (flags & LITTLE_ENDIAN) != 0; - } + boolean littleEndian = resolveEndianness(flags); if (size > 0) { writeNativeBytes(buffer, size, value, littleEndian); } @@ -448,16 +450,34 @@ static long PyLong_FromNativeBytes(long buffer, long size, int flags) { if (size != (int) size) { throw PRaiseNode.raiseStatic(null, OverflowError, ErrorMessages.BYTE_ARRAY_TOO_LONG_TO_CONVERT_TO_INT); } + boolean littleEndian = resolveEndianness(flags); + boolean signed = flags == -1 || (flags & UNSIGNED_BUFFER) == 0; + byte[] bytes = readByteArrayElements(buffer, 0, (int) size); + Object result = IntNodes.PyLongFromByteArray.executeUncached(bytes, littleEndian, signed); + return PythonToNativeInternalNode.executeNewRefUncached(result); + } + + @CApiBuiltin(ret = PyObjectTransfer, args = {CONST_VOID_PTR, SIZE_T, Int}, call = Direct) + static long PyLong_FromUnsignedNativeBytes(long buffer, long size, int flags) { + if (buffer == 0) { + throw PythonCextBuiltins.badInternalCall("PyLong_FromUnsignedNativeBytes", "buffer"); + } + if (size != (int) size) { + throw PRaiseNode.raiseStatic(null, OverflowError, ErrorMessages.BYTE_ARRAY_TOO_LONG_TO_CONVERT_TO_INT); + } + boolean littleEndian = resolveEndianness(flags); + byte[] bytes = readByteArrayElements(buffer, 0, (int) size); + Object result = IntNodes.PyLongFromByteArray.executeUncached(bytes, littleEndian, false); + return PythonToNativeInternalNode.executeNewRefUncached(result); + } + + private static boolean resolveEndianness(int flags) { boolean littleEndian; if (flags == -1 || (flags & NATIVE_ENDIAN) != 0) { littleEndian = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; } else { littleEndian = (flags & LITTLE_ENDIAN) != 0; } - boolean signed = flags == -1 || (flags & UNSIGNED_BUFFER) == 0; - byte[] bytes = readByteArrayElements(buffer, 0, (int) size); - Object result = IntNodes.PyLongFromByteArray.executeUncached(bytes, littleEndian, signed); - return PythonToNativeInternalNode.executeNewRefUncached(result); + return littleEndian; } - } 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 ee1e0c73d9..5f115f4d17 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 @@ -115,6 +115,7 @@ import com.oracle.graal.python.lib.PyObjectDelItem; import com.oracle.graal.python.lib.PyObjectDir; import com.oracle.graal.python.lib.PyObjectFormat; +import com.oracle.graal.python.lib.PyObjectGetAIter; import com.oracle.graal.python.lib.PyObjectGetAttr; import com.oracle.graal.python.lib.PyObjectGetAttrO; import com.oracle.graal.python.lib.PyObjectGetIter; @@ -710,6 +711,13 @@ static Object ascii(Object obj, Object spec, } } + @CApiBuiltin(ret = PyObjectRawPointer, args = {PyObjectRawPointer}, call = Ignored) + static long GraalPyPrivate_Object_GetAIter(long objectPtr) { + Object object = NativeToPythonInternalNode.executeUncached(objectPtr, false); + Object result = PyObjectGetAIter.executeUncached(object); + return PythonToNativeInternalNode.executeNewRefUncached(result); + } + @CApiBuiltin(ret = PyObjectRawPointer, args = {PyObjectRawPointer}, call = Ignored) static long GraalPyPrivate_Object_GetIter(long objectPtr) { Object object = NativeToPythonInternalNode.executeUncached(objectPtr, false); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java index 5781dce48c..e9409c0443 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java @@ -434,6 +434,7 @@ public final class CApiFunction { @CApiBuiltin(name = "PyObject_GenericHash", ret = Py_hash_t, args = {PyObjectReturn}, call = CImpl) @CApiBuiltin(name = "PyObject_GenericSetAttr", ret = Int, args = {PyObject, PyObject, PyObject}, call = CImpl) @CApiBuiltin(name = "PyObject_GenericSetDict", ret = Int, args = {PyObject, PyObject, Pointer}, call = CImpl) + @CApiBuiltin(name = "PyObject_GetAIter", ret = PyObject, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyObject_GetAttr", ret = PyObject, args = {PyObject, PyObject}, call = CImpl) @CApiBuiltin(name = "PyObject_GetAttrString", ret = PyObject, args = {PyObject, ConstCharPtrAsTruffleString}, call = CImpl) @CApiBuiltin(name = "PyObject_GetBuffer", ret = Int, args = {PyObject, PY_BUFFER_PTR, Int}, call = CImpl) @@ -641,7 +642,7 @@ public final class CApiFunction { @CApiBuiltin(name = "_Py_c_prod", ret = PY_COMPLEX, args = {PY_COMPLEX, PY_COMPLEX}, call = CImpl) @CApiBuiltin(name = "_Py_c_quot", ret = PY_COMPLEX, args = {PY_COMPLEX, PY_COMPLEX}, call = CImpl) @CApiBuiltin(name = "_Py_c_sum", ret = PY_COMPLEX, args = {PY_COMPLEX, PY_COMPLEX}, call = CImpl) - @CApiBuiltin(name = "PyAIter_Check", ret = Int, args = {PyObject}, call = NotImplemented) + @CApiBuiltin(name = "PyAIter_Check", ret = Int, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyAsyncGen_New", ret = PyObject, args = {PyFrameObject, PyObject, PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyByteArray_Concat", ret = PyObject, args = {PyObject, PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyByteArray_FromObject", ret = PyObject, args = {PyObject}, call = NotImplemented) @@ -710,7 +711,6 @@ public final class CApiFunction { @CApiBuiltin(name = "PyEval_EvalFrameEx", ret = PyObject, args = {PyFrameObject, Int}, call = NotImplemented) @CApiBuiltin(name = "PyEval_GetFuncDesc", ret = ConstCharPtrAsTruffleString, args = {PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyEval_GetFuncName", ret = ConstCharPtrAsTruffleString, args = {PyObject}, call = NotImplemented) - @CApiBuiltin(name = "PyEval_GetLocals", ret = PyObject, args = {}, call = NotImplemented) @CApiBuiltin(name = "PyEval_ReleaseThread", ret = Void, args = {PyThreadState}, call = NotImplemented) @CApiBuiltin(name = "PyEval_SetProfile", ret = Void, args = {PY_TRACEFUNC, PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyEval_SetTrace", ret = Void, args = {PY_TRACEFUNC, PyObject}, call = NotImplemented) @@ -767,9 +767,6 @@ public final class CApiFunction { @CApiBuiltin(name = "PyInterpreterState_New", ret = PyInterpreterState, args = {}, call = NotImplemented) @CApiBuiltin(name = "PyInterpreterState_Next", ret = PyInterpreterState, args = {PyInterpreterState}, call = CImpl) @CApiBuiltin(name = "PyInterpreterState_ThreadHead", ret = PyThreadState, args = {PyInterpreterState}, call = CImpl) - @CApiBuiltin(name = "PyList_Clear", ret = PrimitiveResult32, args = {PyObjectReturn}, call = NotImplemented) - @CApiBuiltin(name = "PyLong_FromUnsignedNativeBytes", ret = PyObjectReturn, args = {CONST_VOID_PTR, SIZE_T, PrimitiveResult32}, call = NotImplemented) - @CApiBuiltin(name = "PyLong_GetInfo", ret = PyObject, args = {}, call = NotImplemented) @CApiBuiltin(name = "PyMarshal_ReadLastObjectFromFile", ret = PyObject, args = {FILE_PTR}, call = NotImplemented) @CApiBuiltin(name = "PyMarshal_ReadLongFromFile", ret = PrimitiveResult64, args = {FILE_PTR}, call = NotImplemented) @CApiBuiltin(name = "PyMarshal_ReadObjectFromFile", ret = PyObject, args = {FILE_PTR}, call = NotImplemented) @@ -801,7 +798,6 @@ public final class CApiFunction { @CApiBuiltin(name = "PyObject_CallFinalizer", ret = Void, args = {PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyObject_CallFinalizerFromDealloc", ret = Int, args = {PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyObject_GET_WEAKREFS_LISTPTR", ret = PyObjectPtr, args = {PyObject}, call = NotImplemented) - @CApiBuiltin(name = "PyObject_GetAIter", ret = PyObject, args = {PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyObject_GetArenaAllocator", ret = Void, args = {PYOBJECTARENAALLOCATOR_PTR}, call = NotImplemented) @CApiBuiltin(name = "PyObject_SetArenaAllocator", ret = Void, args = {PYOBJECTARENAALLOCATOR_PTR}, call = NotImplemented) @CApiBuiltin(name = "PyPickleBuffer_FromObject", ret = PyObject, args = {PyObject}, call = NotImplemented) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java index e27735a81d..1586d626b3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java @@ -89,6 +89,7 @@ public final class PFrame extends PythonBuiltinObject { private int jumpDestLine = DISALLOW_JUMPS; private Object localTraceFun = null; private PDict extraLocals; + private PDict evalLocalsCache; private boolean traceLine = true; @@ -134,6 +135,18 @@ public void setExtraLocals(PDict extraLocals) { this.extraLocals = extraLocals; } + /** + * A frame-owned dictionary used to provide the borrowed-reference semantics of + * {@code PyEval_GetLocals} for optimized frames. + */ + public PDict getEvalLocalsCache() { + return evalLocalsCache; + } + + public void setEvalLocalsCache(PDict evalLocalsCache) { + this.evalLocalsCache = evalLocalsCache; + } + // TODO: frames: this is a large object, think about how to make this // smaller public static final class Reference { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java index bddb9b39ba..33b3964444 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/CommonGeneratorBuiltins.java @@ -171,12 +171,17 @@ static Object cachedBytecodeDSL(VirtualFrame frame, Node inliningTarget, PGenera generatorResult = callNode.call(callArguments); } finally { IndirectCalleeContext.exit(threadState, state); + ref.setCallerInfo(PFrame.Reference.EMPTY); } } else { callContext.executePrepareCall(frame, generatorArguments, rootNode.getCallerFlags()); PFrame.Reference ref = PArguments.getCurrentFrameInfo(generatorArguments); ref.setCallerInfo(PArguments.getCallerFrameInfo(generatorArguments)); - generatorResult = callNode.call(callArguments); + try { + generatorResult = callNode.call(callArguments); + } finally { + ref.setCallerInfo(PFrame.Reference.EMPTY); + } } } catch (PException e) { throw handleException(self, inliningTarget, errorProfile, raiseNode, e); @@ -219,12 +224,17 @@ static Object genericBytecodeDSL(VirtualFrame frame, Node inliningTarget, PGener generatorResult = callNode.call(callTarget, callArguments); } finally { IndirectCalleeContext.exit(threadState, state); + ref.setCallerInfo(PFrame.Reference.EMPTY); } } else { callContext.executePrepareCall(frame, generatorArguments, rootNode.getCallerFlags()); PFrame.Reference ref = PArguments.getCurrentFrameInfo(generatorArguments); ref.setCallerInfo(PArguments.getCallerFrameInfo(generatorArguments)); - generatorResult = callNode.call(callTarget, callArguments); + try { + generatorResult = callNode.call(callTarget, callArguments); + } finally { + ref.setCallerInfo(PFrame.Reference.EMPTY); + } } } catch (PException e) { throw handleException(self, inliningTarget, errorProfile, raiseNode, e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java index 03a745363c..527eb31b09 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java @@ -28,7 +28,6 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; -import com.oracle.graal.python.builtins.objects.frame.PFrame; import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; @@ -218,9 +217,6 @@ public final boolean isFinished() { public final void markAsFinished() { finished = true; - // A generator frame is no longer executing after completion, so it must not retain the - // frame that resumed it as its Python-level f_back reference. - PArguments.getCurrentFrameInfo(frame.getArguments()).setCallerInfo(PFrame.Reference.EMPTY); } @Override diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetAIter.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetAIter.java new file mode 100644 index 0000000000..f9fe3ba863 --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetAIter.java @@ -0,0 +1,88 @@ +/* + * 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.lib; + +import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.objects.type.TpSlots; +import com.oracle.graal.python.builtins.objects.type.TpSlots.GetObjectSlotsNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotUnaryFunc.CallSlotUnaryNode; +import com.oracle.graal.python.nodes.ErrorMessages; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.truffle.api.dsl.Cached; +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.frame.Frame; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +/** Equivalent to PyObject_GetAIter. */ +@GenerateUncached +@GenerateCached +@GenerateInline(inlineByDefault = true) +public abstract class PyObjectGetAIter extends Node { + public static Object executeUncached(Object object) { + return PyObjectGetAIterNodeGen.getUncached().execute(null, null, object); + } + + public abstract Object execute(Frame frame, Node inliningTarget, Object object); + + @Specialization + static Object doGeneric(VirtualFrame frame, Node inliningTarget, Object object, + @Cached GetObjectSlotsNode getSlots, + @Cached CallSlotUnaryNode callSlot, + @Cached PyAIterCheckNode checkNode, + @Cached GetClassNode getClassNode, + @Cached PRaiseNode raiseNode) { + TpSlots slots = getSlots.execute(inliningTarget, object); + if (slots.am_aiter() == null) { + throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.OBJECT_NOT_ASYNC_ITERABLE, object); + } + Object asyncIterator = callSlot.execute(frame, inliningTarget, slots.am_aiter(), object); + if (!checkNode.execute(inliningTarget, asyncIterator)) { + throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.AITER_RETURNED_NOT_ASYNC_ITERATOR, + getClassNode.execute(inliningTarget, asyncIterator)); + } + return asyncIterator; + } +} diff --git a/graalpython/lib-python/3/dis.py b/graalpython/lib-python/3/dis.py index 1893f7888c..4b12037c06 100644 --- a/graalpython/lib-python/3/dis.py +++ b/graalpython/lib-python/3/dis.py @@ -7,12 +7,17 @@ # GraalPy change: remove all the _opcode imports and dependent stuff -# GraalPy change: add a dummy opmap to make coverage happy +# GraalPy change: add dummy opcode metadata for coverage.py opmap = { + "EXTENDED_ARG": -1, + "JUMP_FORWARD": -1, "RETURN_VALUE": -1, "YIELD_VALUE": -1, "YIELD_FROM": -1, } +opname = [] +hasjabs = [] +hasjrel = [] __all__ = ["code_info", "dis", "disassemble", "distb", "disco", "findlinestarts", "findlabels", "show_code",