diff --git a/graalpython/com.oracle.graal.python.cext/src/abstract.c b/graalpython/com.oracle.graal.python.cext/src/abstract.c index 6e5e2c08c2..c7aaa5b41b 100644 --- a/graalpython/com.oracle.graal.python.cext/src/abstract.c +++ b/graalpython/com.oracle.graal.python.cext/src/abstract.c @@ -1453,8 +1453,6 @@ PyIndex_Check(PyObject *obj) return _PyIndex_Check(obj); } - -#if 0 // GraalPy change /* Return a Python int from the object item. Can return an instance of int subclass. Raise TypeError if the result is not an int @@ -1470,6 +1468,12 @@ _PyNumber_Index(PyObject *item) if (PyLong_Check(item)) { return Py_NewRef(item); } + + // GraalPy change: upcall for managed objects + if (points_to_py_handle_space(item)) { + return GraalPyPrivate_PyNumber_Index(item); + } + if (!_PyIndex_Check(item)) { PyErr_Format(PyExc_TypeError, "'%.200s' object cannot be interpreted " @@ -1511,11 +1515,14 @@ PyNumber_Index(PyObject *item) { PyObject *result = _PyNumber_Index(item); if (result != NULL && !PyLong_CheckExact(result)) { - Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + if (points_to_py_handle_space(result)) { + Py_SETREF(result, GraalPyPrivate_PyNumber_IndexCopy(result)); + } else { + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + } } return result; } -#endif // GraalPy change /* Return an error on Overflow only if err is not NULL*/ @@ -2880,10 +2887,15 @@ _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls) return recursive_issubclass(derived, cls); } - +#endif // GraalPy change PyObject * PyObject_GetIter(PyObject *o) { + // GraalPy change: upcall for managed objects + if (points_to_py_handle_space(o)) { + return GraalPyPrivate_Object_GetIter(o); + } + PyTypeObject *t = Py_TYPE(o); getiterfunc f; @@ -2905,7 +2917,7 @@ PyObject_GetIter(PyObject *o) return res; } } - +#if 0 // GraalPy change PyObject * PyObject_GetAIter(PyObject *o) { PyTypeObject *t = Py_TYPE(o); @@ -2924,7 +2936,7 @@ PyObject_GetAIter(PyObject *o) { } return it; } - +#endif // GraalPy change int PyIter_Check(PyObject *obj) { @@ -2932,7 +2944,7 @@ PyIter_Check(PyObject *obj) return (tp->tp_iternext != NULL && tp->tp_iternext != &_PyObject_NextNotImplemented); } - +#if 0 // GraalPy change int PyAIter_Check(PyObject *obj) { diff --git a/graalpython/com.oracle.graal.python.cext/src/dictobject.c b/graalpython/com.oracle.graal.python.cext/src/dictobject.c index 1abc5634f3..14faebd390 100644 --- a/graalpython/com.oracle.graal.python.cext/src/dictobject.c +++ b/graalpython/com.oracle.graal.python.cext/src/dictobject.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2024, 2025, Oracle and/or its affiliates. +/* Copyright (c) 2024, 2026, Oracle and/or its affiliates. * Copyright (C) 1996-2024 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -3086,7 +3086,7 @@ PyDict_Copy(PyObject *o) Py_DECREF(copy); return NULL; } - +#endif // GraalPy change Py_ssize_t PyDict_Size(PyObject *mp) { @@ -3094,9 +3094,12 @@ PyDict_Size(PyObject *mp) PyErr_BadInternalCall(); return -1; } + if (points_to_py_handle_space(mp)) { + return GraalPyPrivate_Object_Size(mp); + } return ((PyDictObject *)mp)->ma_used; } - +#if 0 // GraalPy change PyObject * PyDict_Keys(PyObject *mp) { diff --git a/graalpython/com.oracle.graal.python.cext/src/longobject.c b/graalpython/com.oracle.graal.python.cext/src/longobject.c index 58eb4997e7..b2d0dc0a86 100644 --- a/graalpython/com.oracle.graal.python.cext/src/longobject.c +++ b/graalpython/com.oracle.graal.python.cext/src/longobject.c @@ -335,8 +335,16 @@ PyLong_FromLong(long ival) return PyLong_FromLongLong((long long) ival); } -#if 0 // GraalPy change #define PYLONG_FROM_UINT(INT_TYPE, ival) \ + do { \ + if ((ival) <= INT32_MAX) { \ + return int32_to_pointer((int)(ival)); \ + } \ + return GraalPyPrivate_Long_FromUnsignedLongLong((unsigned long long)(ival)); \ + } while(0) + +#if 0 // GraalPy change +#define PYLONG_FROM_UINT_CPYTHON(INT_TYPE, ival) \ do { \ if (IS_SMALL_UINT(ival)) { \ return get_small_int((sdigit)(ival)); \ @@ -359,6 +367,7 @@ PyLong_FromLong(long ival) } \ return (PyObject *)v; \ } while(0) +#endif // GraalPy change /* Create a new int object from a C unsigned long int */ @@ -404,6 +413,7 @@ PyLong_FromDouble(double dval) return PyLong_FromLong((long)dval); } +#if 0 // GraalPy change PyLongObject *v; double frac; int i, ndig, expo, neg; @@ -439,8 +449,9 @@ PyLong_FromDouble(double dval) _PyLong_FlipSign(v); } return (PyObject *)v; -} #endif // GraalPy change + return GraalPyPrivate_Long_FromDouble(dval); +} /* Checking for overflow in PyLong_AsLong is a PITA since C doesn't define * anything about what happens when a signed integer operation overflows, @@ -615,20 +626,27 @@ PyLong_AsUnsignedLongMask(PyObject *op) return (unsigned long) GraalPyPrivate_Long_AsPrimitive(op, MODE_COERCE_MASK, sizeof(unsigned long)); } -#if 0 // GraalPy change int _PyLong_Sign(PyObject *vv) { + assert(vv != NULL); + if (points_to_py_int_handle(vv)) { + int64_t value = pointer_to_int64(vv); + return (value > 0) - (value < 0); + } + PyLongObject *v = (PyLongObject *)vv; assert(v != NULL); assert(PyLong_Check(v)); +#if 0 // GraalPy change if (_PyLong_IsCompact(v)) { return _PyLong_CompactSign(v); } return _PyLong_NonCompactSign(v); -} #endif // GraalPy change + return 1 - (GraalPyPrivate_Long_lv_tag(v) & SIGN_MASK); +} static int bit_length_digit(digit x) @@ -640,10 +658,19 @@ bit_length_digit(digit x) return _Py_bit_length((unsigned long)x); } -#if 0 // GraalPy change size_t _PyLong_NumBits(PyObject *vv) { + assert(vv != NULL); + if (points_to_py_int_handle(vv)) { + int64_t value = pointer_to_int64(vv); + unsigned long magnitude = value < 0 ? (unsigned long)-value : (unsigned long)value; + return (size_t)_Py_bit_length(magnitude); + } + + return GraalPyPrivate_Long_NumBits(vv); + +#if 0 // GraalPy change PyLongObject *v = (PyLongObject *)vv; size_t result = 0; Py_ssize_t ndigits; @@ -669,8 +696,10 @@ _PyLong_NumBits(PyObject *vv) PyErr_SetString(PyExc_OverflowError, "int has too many bits " "to express in a platform size_t"); return (size_t)-1; +#endif // GraalPy change } +#if 0 // GraalPy change PyObject * _PyLong_FromByteArray(const unsigned char* bytes, size_t n, int little_endian, int is_signed) @@ -929,9 +958,9 @@ PyLong_FromVoidPtr(void *p) return PyLong_FromUnsignedLongLong((uint64_t)p); } -#if 0 // GraalPy change /* Get a C pointer from an int object. */ +#if 0 // GraalPy change void * PyLong_AsVoidPtr(PyObject *vv) { @@ -964,6 +993,16 @@ PyLong_AsVoidPtr(PyObject *vv) return NULL; return (void *)x; } +#else +void * +PyLong_AsVoidPtr(PyObject *vv) +{ + if (points_to_py_int_handle(vv)) { + return (void *)(uintptr_t)pointer_to_int64(vv); + } + + return (void *)GraalPyPrivate_Long_AsVoidPtr(vv); +} #endif // GraalPy change /* Initial long long support by Chris Herborth (chrish@qnx.com), later @@ -6178,6 +6217,13 @@ PyUnstable_Long_CompactValue(const PyLongObject* op) { #endif // GraalPy change +#undef PyUnstable_Long_IsCompact + +int +PyUnstable_Long_IsCompact(const PyLongObject* op) { + return GraalPyPrivate_Long_lv_tag(op) < (2 << NON_SIZE_BITS); +} + #undef PyUnstable_Long_CompactValue Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject *op) { diff --git a/graalpython/com.oracle.graal.python.cext/src/object.c b/graalpython/com.oracle.graal.python.cext/src/object.c index f8c6cadb2e..449cd46818 100644 --- a/graalpython/com.oracle.graal.python.cext/src/object.c +++ b/graalpython/com.oracle.graal.python.cext/src/object.c @@ -1776,7 +1776,6 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context) } -#if 0 // GraalPy change /* Test a value used as condition, e.g., in a while or if statement. Return -1 if an error occurred */ @@ -1790,6 +1789,9 @@ PyObject_IsTrue(PyObject *v) return 0; if (v == Py_None) return 0; + // GraalPy change: upcall for managed objects + if (points_to_py_handle_space(v)) + return GraalPyPrivate_Object_IsTrue(v); else if (Py_TYPE(v)->tp_as_number != NULL && Py_TYPE(v)->tp_as_number->nb_bool != NULL) res = (*Py_TYPE(v)->tp_as_number->nb_bool)(v); @@ -1804,7 +1806,6 @@ PyObject_IsTrue(PyObject *v) /* if it is negative, it should be either -1 or -2 */ return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int); } -#endif // GraalPy change /* equivalent of 'not v' Return -1 if an error occurred */ @@ -1819,7 +1820,6 @@ PyObject_Not(PyObject *v) return res == 0; } -#if 0 // GraalPy change /* Test whether an object can be called */ int @@ -1830,6 +1830,7 @@ PyCallable_Check(PyObject *x) return Py_TYPE(x)->tp_call != NULL; } +#if 0 // GraalPy change /* Helper for PyObject_Dir without arguments: returns the local scope. */ static PyObject * 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 70553a19ff..383ea8038b 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 @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -90,6 +90,19 @@ def _reference_index(args): return result +def _reference_index_exact(args): + result = _reference_index(args) + result = result.__index__() + return type(result).__name__, result + + +def _reference_private_index(args): + if isinstance(args[0], int): + return type(args[0]).__name__, args[0] + result = _reference_index(args) + return type(result).__name__, result + + def _reference_asssize_t(args): v = args[0] err = args[1] @@ -237,6 +250,12 @@ def __index__(self): return 0xCAFE +class DummyIndexableIntSubclass(): + + def __index__(self): + return DummyIntSubclass() + + class DummyIntSubclass(int): def __int__(self): @@ -1006,9 +1025,10 @@ class TestAbstract(CPyExtTestCase): ) test_PyNumber_Index = CPyExtFunction( - _reference_index, + _reference_index_exact, lambda: ( (0,), + (True,), (1,), (-1,), (1.0,), @@ -1016,12 +1036,56 @@ class TestAbstract(CPyExtTestCase): (0x7FFFFFFF,), (0x7FFFFFFFFFFFFFFF,), (DummyIntable(),), + (DummyIndexableIntSubclass(),), (DummyIntSubclass(),), (NoNumber(),), ), resultspec="O", argspec='O', arguments=["PyObject* v"], + code=''' + PyObject* wrap_PyNumber_Index(PyObject* v) { + PyObject* result = PyNumber_Index(v); + if (result == NULL) { + return NULL; + } + PyObject* type_name = PyUnicode_FromString(Py_TYPE(result)->tp_name); + PyObject* tuple = PyTuple_Pack(2, type_name, result); + Py_DECREF(type_name); + Py_DECREF(result); + return tuple; + } + ''', + callfunction="wrap_PyNumber_Index", + cmpfunc=unhandled_error_compare + ) + + test__PyNumber_Index = CPyExtFunction( + _reference_private_index, + lambda: ( + (0,), + (True,), + (DummyIndexable(),), + (DummyIntSubclass(),), + (NoNumber(),), + ), + resultspec="O", + argspec='O', + arguments=["PyObject* v"], + code=''' + PyObject* wrap__PyNumber_Index(PyObject* v) { + PyObject* result = _PyNumber_Index(v); + if (result == NULL) { + return NULL; + } + PyObject* type_name = PyUnicode_FromString(Py_TYPE(result)->tp_name); + PyObject* tuple = PyTuple_Pack(2, type_name, result); + Py_DECREF(type_name); + Py_DECREF(result); + return tuple; + } + ''', + callfunction="wrap__PyNumber_Index", 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 768771a9c3..0686ab33cb 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 @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,10 @@ max_long = 2 ** (long_bits - 1) - 1 min_long = -2 ** (long_bits - 1) max_ulong = 2 ** long_bits +ulonglong_bits = struct.calcsize('Q') * 8 +max_ulonglong = 2 ** ulonglong_bits +size_t_bits = struct.calcsize('P') * 8 +max_size_t = 2 ** size_t_bits ssize_t_bits = struct.calcsize('n') * 8 max_ssize_t = 2 ** (ssize_t_bits - 1) - 1 min_ssize_t = -2 ** (ssize_t_bits - 1) @@ -112,6 +116,15 @@ def _reference_fromvoidptr(args): return n +def _reference_asvoidptr_roundtrip(args): + n = args[0] + if n < min_long or n >= max_ulonglong: + raise OverflowError("Python int too large to convert") + if n < 0: + return _reference_fromvoidptr(args) + return n + + def _reference_fromlong(args): n = args[0] return n @@ -243,16 +256,90 @@ class TestPyLong(CPyExtTestCase): cmpfunc=unhandled_error_compare ) + test_PyLong_FromUnsignedLong = CPyExtFunction( + lambda args: (0, 1, max_ulong - 1), + lambda: ((),), + code=""" + PyObject* wrap_PyLong_FromUnsignedLong() { + PyObject* small = PyLong_FromUnsignedLong(0); + PyObject* one = PyLong_FromUnsignedLong(1); + PyObject* large = PyLong_FromUnsignedLong(ULONG_MAX); + PyObject* result; + if (small == NULL || one == NULL || large == NULL) { + Py_XDECREF(small); + Py_XDECREF(one); + Py_XDECREF(large); + return NULL; + } + result = PyTuple_Pack(3, small, one, large); + Py_DECREF(small); + Py_DECREF(one); + Py_DECREF(large); + return result; + } + """, + resultspec="O", + argspec='', + arguments=[], + callfunction="wrap_PyLong_FromUnsignedLong", + cmpfunc=unhandled_error_compare + ) + + test_PyLong_FromUnsignedLongLong = CPyExtFunction( + lambda args: (0, 1, max_ulonglong - 1), + lambda: ((),), + code=""" + PyObject* wrap_PyLong_FromUnsignedLongLong() { + PyObject* small = PyLong_FromUnsignedLongLong(0); + PyObject* one = PyLong_FromUnsignedLongLong(1); + PyObject* large = PyLong_FromUnsignedLongLong(ULLONG_MAX); + PyObject* result; + if (small == NULL || one == NULL || large == NULL) { + Py_XDECREF(small); + Py_XDECREF(one); + Py_XDECREF(large); + return NULL; + } + result = PyTuple_Pack(3, small, one, large); + Py_DECREF(small); + Py_DECREF(one); + Py_DECREF(large); + return result; + } + """, + resultspec="O", + argspec='', + arguments=[], + callfunction="wrap_PyLong_FromUnsignedLongLong", + cmpfunc=unhandled_error_compare + ) + test_PyLong_FromSize_t = CPyExtFunction( - lambda args: int(args[0]), - lambda: ( - (0,), - (1,), - (0xffffffff,), - ), + lambda args: (0, 1, max_size_t - 1), + lambda: ((),), + code=""" + PyObject* wrap_PyLong_FromSize_t() { + PyObject* small = PyLong_FromSize_t(0); + PyObject* one = PyLong_FromSize_t(1); + PyObject* large = PyLong_FromSize_t((size_t)-1); + PyObject* result; + if (small == NULL || one == NULL || large == NULL) { + Py_XDECREF(small); + Py_XDECREF(one); + Py_XDECREF(large); + return NULL; + } + result = PyTuple_Pack(3, small, one, large); + Py_DECREF(small); + Py_DECREF(one); + Py_DECREF(large); + return result; + } + """, resultspec="O", - argspec='n', - arguments=["size_t n"], + argspec='', + arguments=[], + callfunction="wrap_PyLong_FromSize_t", cmpfunc=unhandled_error_compare ) @@ -262,6 +349,7 @@ class TestPyLong(CPyExtTestCase): (0.0,), (-1.0,), (-11.123456789123456789,), + (1.0e100,), ), resultspec="O", argspec='d', @@ -284,6 +372,31 @@ class TestPyLong(CPyExtTestCase): cmpfunc=unhandled_error_compare ) + test_PyLong_AsVoidPtr = CPyExtFunction( + _reference_asvoidptr_roundtrip, + lambda: ( + (0,), + (42,), + (-1,), + (0xffffffff,), + (0xffffffffffffffff,), + (0x10000000000000000,), + ), + code="""PyObject* wrap_PyLong_AsVoidPtr(PyObject* obj) { + void* ptr = PyLong_AsVoidPtr(obj); + if (ptr == NULL && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromVoidPtr(ptr); + } + """, + resultspec="O", + argspec='O', + arguments=["PyObject* obj"], + callfunction="wrap_PyLong_AsVoidPtr", + cmpfunc=unhandled_error_compare + ) + test_PyLong_FromVoidPtrAllocated = CPyExtFunction( lambda args: int, lambda: ((None,),), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java index 2c9313427c..e2ddc17e46 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java @@ -40,6 +40,7 @@ */ package com.oracle.graal.python.builtins.modules.cext; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.DeprecationWarning; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.OverflowError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; @@ -63,12 +64,14 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T_KEYS; import static com.oracle.graal.python.nodes.SpecialMethodNames.T_VALUES; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___GETITEM__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INDEX__; import static com.oracle.graal.python.runtime.PythonContext.NATIVE_NULL; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.BuiltinFunctions.BinNode; import com.oracle.graal.python.builtins.modules.BuiltinFunctions.HexNode; import com.oracle.graal.python.builtins.modules.BuiltinFunctions.OctNode; +import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltins; 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.objects.PNone; @@ -91,9 +94,13 @@ import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsSameTypeNode; import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotMpAssSubscript.CallSlotMpAssSubscriptNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotUnaryFunc.CallSlotUnaryNode; import com.oracle.graal.python.lib.IteratorExhausted; import com.oracle.graal.python.lib.PyIterCheckNode; import com.oracle.graal.python.lib.PyIterNextNode; +import com.oracle.graal.python.lib.PyLongCheckExactNode; +import com.oracle.graal.python.lib.PyLongCheckNode; +import com.oracle.graal.python.lib.PyLongCopyNodeGen; import com.oracle.graal.python.lib.PyNumberAddNode; import com.oracle.graal.python.lib.PyNumberAndNode; import com.oracle.graal.python.lib.PyNumberDivmodNode; @@ -167,12 +174,33 @@ public final class PythonCextAbstractBuiltins { private static final TruffleLogger PY_OBJECT_SET_DOC_LOGGER = CApiContext.getLogger(PythonCextAbstractBuiltins.class); /////// PyNumber /////// - @CApiBuiltin(name = "_PyNumber_Index", ret = PyObjectRawPointer, args = {PyObjectRawPointer}, call = Direct, acquireGil = false) - @CApiBuiltin(ret = PyObjectRawPointer, args = {PyObjectRawPointer}, call = Direct, acquireGil = false) - static long PyNumber_Index(long objPtr) { + @CApiBuiltin(ret = PyObjectRawPointer, args = {PyObjectRawPointer}, call = Ignored, acquireGil = false) + static long GraalPyPrivate_PyNumber_Index(long objPtr) { Object obj = NativeToPythonNode.executeRawUncached(objPtr); checkNonNullArgUncached(obj); - Object result = PyNumberIndexNode.executeUncached(obj); + if (PyLongCheckNode.executeUncached(obj)) { + return PythonToNativeNewRefNode.executeLongUncached(obj); + } + TpSlots slots = GetObjectSlotsNode.executeUncached(obj); + if (slots.nb_index() == null) { + throw PRaiseNode.raiseStatic(null, TypeError, ErrorMessages.OBJ_CANNOT_BE_INTERPRETED_AS_INTEGER, obj); + } + Object result = CallSlotUnaryNode.executeUncached(slots.nb_index(), obj); + if (PyLongCheckExactNode.executeUncached(result)) { + return PythonToNativeNewRefNode.executeLongUncached(result); + } + if (!PyLongCheckNode.executeUncached(result)) { + throw PRaiseNode.raiseStatic(null, TypeError, ErrorMessages.INDEX_RETURNED_NON_INT, result); + } + WarningsModuleBuiltins.WarnNode.getUncached().warnFormat(null, null, DeprecationWarning, 1, + ErrorMessages.WARN_P_RETURNED_NON_P, obj, T___INDEX__, "int", result, "int"); + return PythonToNativeNewRefNode.executeLongUncached(result); + } + + @CApiBuiltin(ret = PyObjectRawPointer, args = {PyObjectRawPointer}, call = Ignored, acquireGil = false) + static long GraalPyPrivate_PyNumber_IndexCopy(long objPtr) { + Object obj = NativeToPythonNode.executeRawUncached(objPtr); + Object result = PyLongCopyNodeGen.getUncached().execute(null, obj); return PythonToNativeNewRefNode.executeLongUncached(result); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBytesBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBytesBuiltins.java index 1aeb3fce1d..a2b5466dae 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBytesBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBytesBuiltins.java @@ -104,6 +104,9 @@ public final class PythonCextBytesBuiltins { + /* + * Moving this to native regresses median time by about 1.84x, so leaving it here. + */ @CApiBuiltin(ret = Py_ssize_t, args = {PyObjectRawPointer}, call = Direct) static long PyBytes_Size(long objPtr) { Object obj = NativeToPythonNode.executeRawUncached(objPtr); 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 ae2ce9e9f2..43b78b22ff 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 @@ -53,7 +53,6 @@ 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.PyObjectTransfer; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_hash_t; -import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Void; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.readLong; @@ -275,21 +274,6 @@ public Object fallback(Object dict, @SuppressWarnings("unused") Object key, @Sup } } - @CApiBuiltin(ret = Py_ssize_t, args = {PyObject}, call = Direct) - abstract static class PyDict_Size extends CApiUnaryBuiltinNode { - @Specialization - static long size(PDict dict, - @Bind Node inliningTarget, - @Cached HashingStorageLen lenNode) { - return lenNode.execute(inliningTarget, dict.getDictStorage()); - } - - @Fallback - public long fallback(Object dict) { - throw raiseFallback(dict, PythonBuiltinClassType.PDict); - } - } - @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct) abstract static class PyDict_Copy extends CApiUnaryBuiltinNode { @Specialization diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextIterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextIterBuiltins.java index d2f60fba14..3072377989 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextIterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextIterBuiltins.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 @@ -41,7 +41,6 @@ package com.oracle.graal.python.builtins.modules.cext; import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct; -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.PyObject; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer; @@ -51,25 +50,13 @@ import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode; import com.oracle.graal.python.builtins.objects.iterator.PSequenceIterator; -import com.oracle.graal.python.lib.PyIterCheckNode; 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; -import com.oracle.truffle.api.nodes.Node; public final class PythonCextIterBuiltins { - @CApiBuiltin(ret = Int, args = {PyObject}, call = Direct) - abstract static class PyIter_Check extends CApiUnaryBuiltinNode { - @Specialization - static int check(Object obj, - @Bind Node inliningTarget, - @Cached PyIterCheckNode check) { - return check.execute(inliningTarget, obj) ? 1 : 0; - } - } - @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct) abstract static class PySeqIter_New extends CApiUnaryBuiltinNode { @Specialization 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 039c33c3df..ff5f88b6a5 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 @@ -239,6 +239,10 @@ Object fallback(Object list, @SuppressWarnings("unused") Object iterable) { } } + /* + * A pure-C Py_SIZE implementation regressed mixed managed/native/list-subclass workload by + * about 1.26x. + */ @CApiBuiltin(ret = Py_ssize_t, args = {PyObject}, call = Direct) abstract static class PyList_Size extends CApiUnaryBuiltinNode { 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 5f6a73ecc1..d4ee5628ba 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 @@ -45,23 +45,20 @@ import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Ignored; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_UNSIGNED_CHAR_PTR; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.ConstCharPtrAsTruffleString; -import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.ConstPyLongObject; 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.LONG_LONG; 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.PyLongObject; 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.PyObjectRawPointer; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t; 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; 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 java.math.BigInteger; - import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi5BuiltinNode; @@ -72,6 +69,8 @@ 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.CApiTransitions.NativeToPythonNode; +import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeNewRefNode; 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; @@ -91,7 +90,6 @@ 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; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Exclusive; @@ -105,97 +103,6 @@ public final class PythonCextLongBuiltins { - @CApiBuiltin(ret = Int, args = {PyObject}, call = Direct) - abstract static class _PyLong_Sign extends CApiUnaryBuiltinNode { - - @SuppressWarnings("unused") - @Specialization(guards = "n == 0") - static int sign(int n) { - return 0; - } - - @SuppressWarnings("unused") - @Specialization(guards = "n < 0") - static int signNeg(int n) { - return -1; - } - - @SuppressWarnings("unused") - @Specialization(guards = "n > 0") - static int signPos(int n) { - return 1; - } - - @SuppressWarnings("unused") - @Specialization(guards = "n == 0") - static int sign(long n) { - return 0; - } - - @SuppressWarnings("unused") - @Specialization(guards = "n < 0") - static int signNeg(long n) { - return -1; - } - - @SuppressWarnings("unused") - @Specialization(guards = "n > 0") - static int signPos(long n) { - return 1; - } - - @SuppressWarnings("unused") - @Specialization(guards = "b") - static int signTrue(boolean b) { - return 1; - } - - @SuppressWarnings("unused") - @Specialization(guards = "!b") - static int signFalse(boolean b) { - return 0; - } - - @Specialization - static int sign(PInt n, - @Bind Node inliningTarget, - @Cached InlinedBranchProfile zeroProfile, - @Cached InlinedBranchProfile negProfile) { - if (n.isNegative()) { - negProfile.enter(inliningTarget); - return -1; - } else if (n.isZero()) { - zeroProfile.enter(inliningTarget); - return 0; - } else { - return 1; - } - } - - @SuppressWarnings("unused") - @Specialization(guards = {"!canBeInteger(obj)", "isPIntSubtype(inliningTarget, obj, getClassNode, isSubtypeNode)"}) - static Object signNative(Object obj, - @Bind Node inliningTarget, - @Shared @Cached GetClassNode getClassNode, - @Shared @Cached IsSubtypeNode isSubtypeNode) { - // function returns int, but -1 is expected result for 'n < 0' - throw CompilerDirectives.shouldNotReachHere("not yet implemented"); - } - - @Specialization(guards = {"!isInteger(obj)", "!isPInt(obj)", "!isPIntSubtype(inliningTarget, obj,getClassNode,isSubtypeNode)"}) - static Object sign(@SuppressWarnings("unused") Object obj, - @Bind Node inliningTarget, - @SuppressWarnings("unused") @Shared @Cached GetClassNode getClassNode, - @SuppressWarnings("unused") @Shared @Cached IsSubtypeNode isSubtypeNode) { - // assert(PyLong_Check(v)); - throw CompilerDirectives.shouldNotReachHere(); - } - - protected boolean isPIntSubtype(Node inliningTarget, Object obj, GetClassNode getClassNode, IsSubtypeNode isSubtypeNode) { - return isSubtypeNode.execute(getClassNode.execute(inliningTarget, obj), PythonBuiltinClassType.PInt); - } - } - @CApiBuiltin(ret = Py_ssize_t, args = {PyLongObject}, call = Ignored) abstract static class GraalPyPrivate_Long_DigitCount extends CApiUnaryBuiltinNode { @@ -207,15 +114,10 @@ static long getDC(Object n, } } - @CApiBuiltin(ret = PyObjectTransfer, args = {ArgDescriptor.Double}, call = Direct) - abstract static class PyLong_FromDouble extends CApiUnaryBuiltinNode { - - @Specialization - static Object fromDouble(double d, - @Bind Node inliningTarget, - @Cached PyLongFromDoubleNode pyLongFromDoubleNode) { - return pyLongFromDoubleNode.execute(inliningTarget, d); - } + @CApiBuiltin(ret = PyObjectRawPointer, args = {ArgDescriptor.Double}, call = Ignored, acquireGil = false) + static long GraalPyPrivate_Long_FromDouble(double d) { + Object result = PyLongFromDoubleNode.executeUncached(d); + return PythonToNativeNewRefNode.executeLongUncached(result); } @CApiBuiltin(ret = PyObjectTransfer, args = {ConstCharPtrAsTruffleString, Int}, call = Ignored) @@ -229,20 +131,6 @@ Object fromString(Object s, int base, } } - @CApiBuiltin(ret = Int, args = {ConstPyLongObject}, call = Direct) - abstract static class PyUnstable_Long_IsCompact extends CApiUnaryBuiltinNode { - @Specialization - @TruffleBoundary - static int doI(Object value) { - if (value instanceof Integer || value instanceof Long) { - return 1; - } else if (value instanceof PInt pInt) { - return pInt.fitsIn(PInt.MIN_LONG, PInt.MAX_LONG) ? 1 : 0; - } - return 0; - } - } - @CApiBuiltin(ret = LONG_LONG, args = {PyObject, Int, SIZE_T}, call = Ignored) abstract static class GraalPyPrivate_Long_AsPrimitive extends CApiTernaryBuiltinNode { @@ -292,30 +180,29 @@ static long doSignedLong(long n) { } } - @CApiBuiltin(name = "PyLong_FromSize_t", ret = PyObjectTransfer, args = {SIZE_T}, call = Direct) - @CApiBuiltin(name = "PyLong_FromUnsignedLong", ret = PyObjectTransfer, args = {UNSIGNED_LONG}, call = Direct) - @CApiBuiltin(ret = PyObjectTransfer, args = {UNSIGNED_LONG_LONG}, call = Direct) - abstract static class PyLong_FromUnsignedLongLong extends CApiUnaryBuiltinNode { - - @Specialization(guards = "n >= 0") - static Object doUnsignedLongPositive(long n) { - return n; - } - - @Specialization(guards = "n < 0") - static Object doUnsignedLongNegative(long n, - @Bind PythonLanguage language) { - return PFactory.createInt(language, convertToBigInteger(n)); - } + @CApiBuiltin(ret = PyObjectRawPointer, args = {UNSIGNED_LONG_LONG}, call = Ignored, acquireGil = false) + static long GraalPyPrivate_Long_FromUnsignedLongLong(long n) { + Object result = n >= 0 ? n : PFactory.createInt(PythonLanguage.get(null), PInt.longToUnsignedBigInteger(n)); + return PythonToNativeNewRefNode.executeLongUncached(result); + } - @TruffleBoundary - private static BigInteger convertToBigInteger(long n) { - return BigInteger.valueOf(n).add(BigInteger.ONE.shiftLeft(Long.SIZE)); - } + @CApiBuiltin(ret = SIZE_T, args = {PyObjectRawPointer}, call = Ignored, acquireGil = false) + static long GraalPyPrivate_Long_NumBits(long objPtr) { + Object obj = NativeToPythonNode.executeRawUncached(objPtr); + if (obj instanceof Integer value) { + return Integer.SIZE - Integer.numberOfLeadingZeros(Math.abs(value)); + } else if (obj instanceof Long value) { + return Long.SIZE - Long.numberOfLeadingZeros(Math.abs(value)); + } else if (obj instanceof PInt value) { + return value.bitLength(); + } else if (obj instanceof Boolean value) { + return value ? 1 : 0; + } + throw CompilerDirectives.shouldNotReachHere(); } - @CApiBuiltin(ret = Pointer, args = {PyObject}, call = Direct) - public abstract static class PyLong_AsVoidPtr extends CApiUnaryBuiltinNode { + @CApiBuiltin(ret = Pointer, args = {PyObject}, call = Ignored) + abstract static class GraalPyPrivate_Long_AsVoidPtr extends CApiUnaryBuiltinNode { @Child private ConvertPIntToPrimitiveNode asPrimitiveNode; @Child private TransformPExceptionToNativeCachedNode transformExceptionToNativeNode; @@ -337,13 +224,12 @@ long doPointer(PInt n, try { return n.longValueExact(); } catch (OverflowException e) { - overflowProfile.enter(inliningTarget); - try { - throw raiseNode.raise(inliningTarget, OverflowError, ErrorMessages.PYTHON_INT_TOO_LARGE_TO_CONV_TO, "C long"); - } catch (PException pe) { - ensureTransformExcNode().execute(pe); - return 0; + if (!n.isNegative() && n.bitLength() <= Long.SIZE) { + return n.longValue(); } + overflowProfile.enter(inliningTarget); + transformOverflow(inliningTarget, raiseNode); + return 0; } } @@ -359,7 +245,8 @@ long doGeneric(Object n, try { return asPrimitiveNode.executeLongCached(n, 0, Long.BYTES); } catch (UnexpectedResultException e) { - throw raiseNode.raise(inliningTarget, OverflowError, ErrorMessages.PYTHON_INT_TOO_LARGE_TO_CONV_TO, "C long"); + transformOverflow(inliningTarget, raiseNode); + return 0; } } catch (PException e) { ensureTransformExcNode().execute(e); @@ -367,6 +254,14 @@ long doGeneric(Object n, } } + private void transformOverflow(Node inliningTarget, PRaiseNode raiseNode) { + try { + throw raiseNode.raise(inliningTarget, OverflowError, ErrorMessages.PYTHON_INT_TOO_LARGE_TO_CONV_TO, "C long"); + } catch (PException pe) { + ensureTransformExcNode().execute(pe); + } + } + private TransformPExceptionToNativeCachedNode ensureTransformExcNode() { if (transformExceptionToNativeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -445,12 +340,4 @@ static Object convert(long charPtr, long size, int littleEndian, int signed, } } - @CApiBuiltin(ret = SIZE_T, args = {PyObject}, call = Direct) - abstract static class _PyLong_NumBits extends CApiUnaryBuiltinNode { - @Specialization - static long numBits(Object obj, - @Cached IntBuiltins.BitLengthNode bitLengthNode) { - return bitLengthNode.execute(obj); - } - } } 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 3f393b3324..e478b59271 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 @@ -90,7 +90,9 @@ import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.HandleContext; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.HandlePointerConverter; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonInternalNode; +import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonObjectReference; +import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeNewRefNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.UpdateHandleTableReferenceNode; import com.oracle.graal.python.builtins.objects.cext.structs.CFields; import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess; @@ -104,7 +106,6 @@ import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.TypeNodes; import com.oracle.graal.python.lib.PyBytesCheckNode; -import com.oracle.graal.python.lib.PyCallableCheckNode; import com.oracle.graal.python.lib.PyLongCheckNode; import com.oracle.graal.python.lib.PyObjectAsFileDescriptor; import com.oracle.graal.python.lib.PyObjectAsciiAsObjectNode; @@ -476,6 +477,10 @@ static int hasAttr(Object obj, Object attr, } } + /* + * Moving this to pure-C regresses, because creating the TypeError through the C error API is + * slower than upcalling and raising from Java. + */ @CApiBuiltin(ret = Py_hash_t, args = {PyObject}, call = Direct) abstract static class PyObject_HashNotImplemented extends CApiUnaryBuiltinNode { @Specialization @@ -485,13 +490,10 @@ static long unhashable(Object obj, } } - @CApiBuiltin(ret = Int, args = {PyObject}, call = Direct) - abstract static class PyObject_IsTrue extends CApiUnaryBuiltinNode { - @Specialization - static int isTrue(Object obj, - @Cached PyObjectIsTrueNode isTrueNode) { - return isTrueNode.execute(null, obj) ? 1 : 0; - } + @CApiBuiltin(ret = Int, args = {PyObjectRawPointer}, call = Ignored) + static int GraalPyPrivate_Object_IsTrue(long objPtr) { + Object obj = NativeToPythonNode.executeRawUncached(objPtr); + return PyObjectIsTrueNode.executeUncached(obj) ? 1 : 0; } @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct) @@ -678,16 +680,17 @@ static Object ascii(Object obj, Object spec, } } - @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct) - abstract static class PyObject_GetIter extends CApiUnaryBuiltinNode { - @Specialization - static Object iter(Object object, - @Bind Node inliningTarget, - @Cached PyObjectGetIter getIter) { - return getIter.execute(null, inliningTarget, object); - } + @CApiBuiltin(ret = PyObjectRawPointer, args = {PyObjectRawPointer}, call = Ignored) + static long GraalPyPrivate_Object_GetIter(long objectPtr) { + Object object = NativeToPythonNode.executeRawUncached(objectPtr); + Object result = PyObjectGetIter.executeUncached(object); + return PythonToNativeNewRefNode.executeLongUncached(result); } + /* + * Moving this to pure C is much faster (100x) for true native tp_hash, but hashing managed + * objects (e.g. Strings) regresses (also by ~100x). + */ @CApiBuiltin(ret = Py_hash_t, args = {PyObject}, call = Direct) abstract static class PyObject_Hash extends CApiUnaryBuiltinNode { @Specialization @@ -698,16 +701,6 @@ static long hash(Object object, } } - @CApiBuiltin(ret = Int, args = {PyObject}, call = Direct) - abstract static class PyCallable_Check extends CApiUnaryBuiltinNode { - @Specialization - static int doGeneric(Object object, - @Bind Node inliningTarget, - @Cached PyCallableCheckNode callableCheck) { - return intValue(callableCheck.execute(inliningTarget, object)); - } - } - @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct) abstract static class PyObject_Dir extends CApiUnaryBuiltinNode { @Specialization diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSetBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSetBuiltins.java index f72dbdd14e..6331637ce2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSetBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSetBuiltins.java @@ -287,6 +287,10 @@ static int add(Object self, @SuppressWarnings("unused") Object o, } } + /* + * A pure-C implementation regressed a mixed managed/native set/frozenset workload by about + * 1.16x. + */ @CApiBuiltin(ret = Py_ssize_t, args = {PyObject}, call = Direct) abstract static class PySet_Size extends CApiUnaryBuiltinNode { @Specialization diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTupleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTupleBuiltins.java index fc3bbebe05..05fdb0097c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTupleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTupleBuiltins.java @@ -172,6 +172,9 @@ private static int checkIndex(Node inliningTarget, long key, SequenceStorage seq } } + /* + * The best attempt at moving this to pure C regressed by about 1.09x by median time. + */ @CApiBuiltin(ret = Py_ssize_t, args = {PyObject}, call = Direct) abstract static class PyTuple_Size extends CApiUnaryBuiltinNode { @Specialization 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 2d124e3dca..b1442d8123 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 @@ -130,6 +130,7 @@ 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; +import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectReturn; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PySendResult; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PySliceObject; @@ -234,6 +235,7 @@ public final class CApiFunction { @CApiBuiltin(name = "PyCFunction_New", ret = PyObject, args = {PyMethodDef, PyObject}, call = CImpl) @CApiBuiltin(name = "PyCFunction_NewEx", ret = PyObject, args = {PyMethodDef, PyObject, PyObject}, call = CImpl) @CApiBuiltin(name = "PyCMethod_New", ret = PyObject, args = {PyMethodDef, PyObject, PyObject, PyTypeObject}, call = CImpl) + @CApiBuiltin(name = "PyCallable_Check", ret = PrimitiveResult32, args = {PyObjectReturn}, call = CImpl) @CApiBuiltin(name = "PyUnstable_Code_New", ret = PyCodeObject, args = {Int, Int, Int, Int, Int, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, Int, PyObject, PyObject}, call = CImpl) @CApiBuiltin(name = "PyCodec_StrictErrors", ret = PyObject, args = {PyObject}, call = CImpl) @@ -248,6 +250,7 @@ public final class CApiFunction { @CApiBuiltin(name = "PyDict_DelItemString", ret = Int, args = {PyObject, ConstCharPtrAsTruffleString}, call = CImpl) @CApiBuiltin(name = "PyDict_GetItemString", ret = PyObject, args = {PyObject, ConstCharPtrAsTruffleString}, call = CImpl) @CApiBuiltin(name = "PyDict_Next", ret = Int, args = {PyObject, PY_SSIZE_T_PTR, PyObjectPtr, PyObjectPtr}, call = CImpl) + @CApiBuiltin(name = "PyDict_Size", ret = Py_ssize_t, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyDict_SetItemString", ret = Int, args = {PyObject, ConstCharPtrAsTruffleString, PyObject}, call = CImpl) @CApiBuiltin(name = "PyErr_BadArgument", ret = Int, args = {}, call = CImpl) @CApiBuiltin(name = "PyErr_BadInternalCall", ret = Void, args = {}, call = CImpl) @@ -319,6 +322,7 @@ public final class CApiFunction { @CApiBuiltin(name = "PyInterpreterState_GetDict", ret = PyObject, args = {PyInterpreterState}, call = CImpl) @CApiBuiltin(name = "PyInterpreterState_GetID", ret = INT64_T, args = {PyInterpreterState}, call = CImpl) @CApiBuiltin(name = "PyInterpreterState_Main", ret = PyInterpreterState, args = {}, call = CImpl) + @CApiBuiltin(name = "PyIter_Check", ret = Int, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyIter_Send", ret = PySendResult, args = {PyObject, PyObject, PyObjectPtr}, call = CImpl) @CApiBuiltin(name = "PyList_SetItem", ret = Int, args = {PyObject, Py_ssize_t, PyObjectTransfer}, call = CImpl) @CApiBuiltin(name = "PyLong_AsDouble", ret = Double, args = {PyObject}, call = CImpl) @@ -328,14 +332,22 @@ public final class CApiFunction { @CApiBuiltin(name = "PyLong_AsLongLongAndOverflow", ret = LONG_LONG, args = {PyObject, INT_LIST}, call = CImpl) @CApiBuiltin(name = "PyLong_AsSize_t", ret = SIZE_T, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyLong_AsSsize_t", ret = Py_ssize_t, args = {PyObject}, call = CImpl) + @CApiBuiltin(name = "PyLong_AsVoidPtr", ret = Pointer, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyLong_AsUnsignedLong", ret = UNSIGNED_LONG, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyLong_AsUnsignedLongLong", ret = UNSIGNED_LONG_LONG, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyLong_AsUnsignedLongLongMask", ret = UNSIGNED_LONG_LONG, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyLong_AsUnsignedLongMask", ret = UNSIGNED_LONG, args = {PyObject}, call = CImpl) + @CApiBuiltin(name = "PyUnstable_Long_IsCompact", ret = Int, args = {ConstPyLongObject}, call = CImpl) + @CApiBuiltin(name = "_PyLong_NumBits", ret = SIZE_T, args = {PyObject}, call = CImpl) + @CApiBuiltin(name = "_PyLong_Sign", ret = Int, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyLong_FromString", ret = PyObject, args = {ConstCharPtrAsTruffleString, CHAR_PTR_LIST, Int}, call = CImpl) + @CApiBuiltin(name = "PyLong_FromDouble", ret = PyObjectTransfer, args = {ArgDescriptor.Double}, call = CImpl) @CApiBuiltin(name = "PyLong_FromLong", ret = PyObjectTransfer, args = {ArgDescriptor.Long}, call = CImpl) @CApiBuiltin(name = "PyLong_FromLongLong", ret = PyObjectTransfer, args = {LONG_LONG}, call = CImpl) + @CApiBuiltin(name = "PyLong_FromSize_t", ret = PyObjectTransfer, args = {SIZE_T}, call = CImpl) @CApiBuiltin(name = "PyLong_FromSsize_t", ret = PyObjectTransfer, args = {Py_ssize_t}, call = CImpl) + @CApiBuiltin(name = "PyLong_FromUnsignedLong", ret = PyObjectTransfer, args = {UNSIGNED_LONG}, call = CImpl) + @CApiBuiltin(name = "PyLong_FromUnsignedLongLong", ret = PyObjectTransfer, args = {UNSIGNED_LONG_LONG}, call = CImpl) @CApiBuiltin(name = "PyLong_FromVoidPtr", ret = PyObject, args = {Pointer}, call = CImpl) @CApiBuiltin(name = "PyMapping_Check", ret = Int, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyMapping_GetItemString", ret = PyObject, args = {PyObject, ConstCharPtrAsTruffleString}, call = CImpl) @@ -377,6 +389,8 @@ public final class CApiFunction { @CApiBuiltin(name = "PyNumber_Divmod", ret = PyObject, args = {PyObject, PyObject}, call = CImpl) @CApiBuiltin(name = "PyNumber_Float", ret = PyObject, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyNumber_Long", ret = PyObject, args = {PyObject}, call = CImpl) + @CApiBuiltin(name = "_PyNumber_Index", ret = PyObject, args = {PyObject}, call = CImpl) + @CApiBuiltin(name = "PyNumber_Index", ret = PyObject, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyNumber_FloorDivide", ret = PyObject, args = {PyObject, PyObject}, call = CImpl) @CApiBuiltin(name = "PyNumber_InPlaceAdd", ret = PyObject, args = {PyObject, PyObject}, call = CImpl) @CApiBuiltin(name = "PyNumber_InPlaceAnd", ret = PyObject, args = {PyObject, PyObject}, call = CImpl) @@ -440,9 +454,11 @@ public final class CApiFunction { @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) + @CApiBuiltin(name = "PyObject_GetIter", ret = PyObject, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyObject_Init", ret = PyObject, args = {PyObject, PyTypeObject}, call = CImpl) @CApiBuiltin(name = "PyObject_InitVar", ret = PyVarObject, args = {PyVarObject, PyTypeObject, Py_ssize_t}, call = CImpl) @CApiBuiltin(name = "PyObject_IS_GC", ret = Int, args = {PyObject}, call = CImpl) + @CApiBuiltin(name = "PyObject_IsTrue", ret = Int, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyObject_Malloc", ret = Pointer, args = {SIZE_T}, call = CImpl) @CApiBuiltin(name = "PyObject_Not", ret = Int, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PyObject_Print", ret = Int, args = {PyObject, FILE_PTR, Int}, call = CImpl)