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 0686ab33cb..3c3ad95443 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 @@ -38,7 +38,7 @@ # SOFTWARE. import struct -from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare +from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, CPyExtType, unhandled_error_compare int_bits = struct.calcsize('i') * 8 max_int = 2 ** (int_bits - 1) - 1 @@ -195,6 +195,28 @@ def _int_examples(): class TestPyLong(CPyExtTestCase): + def test_native_long_subtype_has_native_layout(self): + NativeLongWithMember = CPyExtType( + "NativeLongWithMember", + """ + static void NativeLongWithMember_dealloc(NativeLongWithMemberObject *self) { + Py_XDECREF(self->member); + Py_TYPE(self)->tp_free((PyObject *)self); + } + """, + ready_code="NativeLongWithMemberType.tp_new = PyLong_Type.tp_new;", + tp_base="&PyLong_Type", + struct_base="PyLongObject base;", + cmembers="PyObject *member;", + tp_dealloc="(destructor)NativeLongWithMember_dealloc", + tp_members='{"member", T_OBJECT_EX, offsetof(NativeLongWithMemberObject, member), 0, NULL}', + ) + + obj = NativeLongWithMember(10) + assert obj == 10 + obj.member = "foo" + assert obj.member == "foo" + test_PyLong_AsLong = CPyExtFunction( _reference_as_long, _int_examples, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java index 3dc09002aa..e7ec3e511b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java @@ -115,7 +115,6 @@ import com.oracle.graal.python.builtins.objects.cext.structs.CStructs; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.complex.PComplex; -import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.floats.PFloat; import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; @@ -271,33 +270,25 @@ static Object doGeneric(Node inliningTarget, Object object, Object arg, } } - @GenerateInline(true) - @GenerateCached(false) - @GenerateUncached(false) - public abstract static class DictSubtypeNew extends Node { - public abstract PDict execute(Node node, Object cls, PDict managedSide); - - @Specialization - static PDict allocateNativePart(Object cls, PDict managedSide, - @Bind Node inliningTarget, - @Cached PythonToNativeNode toNative) { - assert !managedSide.isNative(); - assert EnsurePythonObjectNode.doesNotNeedPromotion(cls); - long clsPointer = toNative.executeLong(cls); - long nativeObject; - try { - nativeObject = ExternalFunctionInvoker.invokePY_TYPE_GENERIC_NEW_RAW(CApiContext.getNativeSymbol(inliningTarget, NativeCAPISymbol.FUN_PY_TYPE_GENERIC_NEW_RAW).getAddress(), - clsPointer, 0L, 0L); - } catch (Throwable t) { - throw CompilerDirectives.shouldNotReachHere(t); - } finally { - Reference.reachabilityFence(cls); - } - CApiTransitions.writeNativeRefCount(nativeObject, MANAGED_REFCNT); - CApiTransitions.createReference(managedSide, nativeObject); - assert managedSide.isNative(); - return managedSide; - } + public static T allocateNativePart(Node inliningTarget, Object cls, T managedSide) { + assert !managedSide.isNative(); + assert EnsurePythonObjectNode.doesNotNeedPromotion(cls); + long nativeObject; + try { + nativeObject = ExternalFunctionInvoker.invokePY_TYPE_GENERIC_NEW_RAW(CApiContext.getNativeSymbol(inliningTarget, NativeCAPISymbol.FUN_PY_TYPE_GENERIC_NEW_RAW).getAddress(), + PythonToNativeNode.executeLongUncached(cls), 0L, 0L); + } catch (Throwable t) { + throw CompilerDirectives.shouldNotReachHere(t); + } finally { + Reference.reachabilityFence(cls); + } + PythonContext context = PythonContext.get(inliningTarget); + TransformExceptionFromNativeNode.executeUncached(context.getThreadState(context.getLanguage()), NativeCAPISymbol.FUN_PY_TYPE_GENERIC_NEW_RAW.getTsName(), nativeObject == NULLPTR, + true); + CApiTransitions.writeNativeRefCount(nativeObject, MANAGED_REFCNT); + CApiTransitions.createReference(managedSide, nativeObject); + assert managedSide.isNative(); + return managedSide; } // ----------------------------------------------------------------------------------------------------------------- diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java index 6a0c3b1dbd..20172f498f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -157,7 +157,6 @@ static Object dict(Object cls, Object[] args, PKeyword[] keywordArgs, @Bind Node inliningTarget, @Cached InlinedConditionProfile orderedProfile, @Cached TypeNodes.NeedsNativeAllocationNode needsNativeAllocationNode, - @Cached CExtNodes.DictSubtypeNew subtypeNew, @Cached IsSubtypeNode isSubtypeNode, @Cached TypeNodes.GetInstanceShape getInstanceShape) { Shape shape = getInstanceShape.execute(cls); @@ -166,7 +165,7 @@ static Object dict(Object cls, Object[] args, PKeyword[] keywordArgs, } PDict newDict = PFactory.createDict(cls, shape, EmptyStorage.INSTANCE); if (needsNativeAllocationNode.execute(inliningTarget, cls)) { - return subtypeNew.execute(inliningTarget, cls, newDict); + return CExtNodes.allocateNativePart(inliningTarget, cls, newDict); } else { return newDict; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java index 2c81fcea3d..477dfe3e70 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java @@ -81,6 +81,7 @@ import com.oracle.graal.python.builtins.objects.bytes.BytesNodes.BytesFromObject; import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; +import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.FromNativeSubclassNode; import com.oracle.graal.python.builtins.objects.common.FormatNodeBase; import com.oracle.graal.python.builtins.objects.floats.PFloat; @@ -167,6 +168,7 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.UnexpectedResultException; +import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedIntValueProfile; @@ -207,42 +209,47 @@ static Object doGeneric(VirtualFrame frame, Object cls, Object x, Object baseObj @Bind Node inliningTarget, @Cached IntNodeInnerNode innerNode, @Cached IsBuiltinClassExactProfile isPrimitiveIntProfile, + @Cached TypeNodes.NeedsNativeAllocationNode needsNativeAllocationNode, + @Cached TypeNodes.GetInstanceShape getInstanceShape, @Cached CreateIntSubclassNode createIntSubclassNode) { Object result = innerNode.execute(frame, inliningTarget, x, baseObj); if (isPrimitiveIntProfile.profileClass(inliningTarget, cls, PythonBuiltinClassType.PInt)) { return result; } else { - return createIntSubclassNode.execute(inliningTarget, cls, result); + assert IsSubtypeNode.getUncached().execute(cls, PythonBuiltinClassType.PInt); + PInt managedInt = createIntSubclassNode.execute(inliningTarget, cls, result, getInstanceShape.execute(cls)); + if (needsNativeAllocationNode.execute(inliningTarget, cls)) { + // needsNativeAllocationNode acts as branch profile + return CExtNodes.allocateNativePart(inliningTarget, cls, managedInt); + } else { + return managedInt; + } } } @GenerateInline @GenerateCached(false) abstract static class CreateIntSubclassNode extends Node { - public abstract Object execute(Node inliningTarget, Object cls, Object intObj); + public abstract PInt execute(Node inliningTarget, Object cls, Object intObj, Shape shape); @Specialization - static Object doSubclass(Object cls, int value, - @Shared @Cached TypeNodes.GetInstanceShape getInstanceShape) { - return PFactory.createInt(cls, getInstanceShape.execute(cls), value); + static PInt doManagedSubclass(Object cls, int value, Shape shape) { + return PFactory.createInt(cls, shape, value); } @Specialization - static Object doSubclass(Object cls, long value, - @Shared @Cached TypeNodes.GetInstanceShape getInstanceShape) { - return PFactory.createInt(cls, getInstanceShape.execute(cls), value); + static PInt doManagedSubclass(Object cls, long value, Shape shape) { + return PFactory.createInt(cls, shape, value); } @Specialization - static Object doSubclass(Object cls, boolean value, - @Shared @Cached TypeNodes.GetInstanceShape getInstanceShape) { - return PFactory.createInt(cls, getInstanceShape.execute(cls), PInt.intValue(value)); + static PInt doManagedSubclass(Object cls, boolean value, Shape shape) { + return PFactory.createInt(cls, shape, PInt.intValue(value)); } @Specialization - static Object doSubclass(Object cls, PInt value, - @Shared @Cached TypeNodes.GetInstanceShape getInstanceShape) { - return PFactory.createInt(cls, getInstanceShape.execute(cls), value.getValue()); + static PInt doManagedSubclass(Object cls, PInt value, Shape shape) { + return PFactory.createInt(cls, shape, value.getValue()); } }