Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions graalpython/com.oracle.graal.python.cext/src/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -3002,15 +3006,15 @@ PyObject_GetAIter(PyObject *o) {
}
return it;
}
#endif // GraalPy change

int
PyIter_Check(PyObject *obj)
{
PyTypeObject *tp = Py_TYPE(obj);
return (tp->tp_iternext != NULL &&
tp->tp_iternext != &_PyObject_NextNotImplemented);
}
#if 0 // GraalPy change

int
PyAIter_Check(PyObject *obj)
{
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions graalpython/com.oracle.graal.python.cext/src/capi.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <time.h>

#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
Expand Down Expand Up @@ -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()));
Expand Down
2 changes: 1 addition & 1 deletion graalpython/com.oracle.graal.python.cext/src/listobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
)
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading