Skip to content

Commit f890648

Browse files
committed
[GR-45462] Use generic allocation for managed classes in the native side
PullRequest: graalpython/2729
2 parents 7acc918 + 288d7fd commit f890648

File tree

2 files changed

+73
-8
lines changed
  • graalpython
    • com.oracle.graal.python.test/src/tests/cpyext
    • com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi

2 files changed

+73
-8
lines changed

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,31 @@ def test_int(self):
109109
tester = TestInt()
110110
assert int(tester) == 42
111111

112+
def test_inherit_slots_with_managed_class(self):
113+
TestTpAllocWithManaged = CPyExtType("TestTpAllocWithManaged",
114+
"""
115+
static PyObject *test_alloc(PyTypeObject *type, Py_ssize_t nitems) {
116+
PyErr_SetString(PyExc_RuntimeError, "Should not call this tp_alloc");
117+
return NULL;
118+
}
119+
""",
120+
tp_alloc="test_alloc"
121+
)
122+
TestTpAllocCall = CPyExtType("TestTpAllocCall",
123+
'''
124+
static PyObject* testslots_tp_alloc(PyObject* self, PyObject *cls) {
125+
return ((PyTypeObject *)cls)->tp_alloc((PyTypeObject *) cls, 0);
126+
}
127+
''',
128+
tp_methods='{"createObj", (PyCFunction)testslots_tp_alloc, METH_O, ""}'
129+
)
130+
class managed(TestTpAllocWithManaged):
131+
pass
132+
t = TestTpAllocCall()
133+
134+
assert t.createObj(managed) != None
135+
136+
112137
def test_float_binops(self):
113138
TestFloatBinop = CPyExtType("TestFloatBinop",
114139
"""

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@
130130
import com.oracle.graal.python.builtins.objects.str.StringNodes.StringMaterializeNode;
131131
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
132132
import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass;
133+
import com.oracle.graal.python.builtins.objects.type.PythonClass;
133134
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
135+
import com.oracle.graal.python.builtins.objects.type.TypeBuiltins;
134136
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
135137
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetMroStorageNode;
136138
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
@@ -203,6 +205,7 @@
203205
import com.oracle.truffle.api.nodes.EncapsulatingNodeReference;
204206
import com.oracle.truffle.api.nodes.ExplodeLoop;
205207
import com.oracle.truffle.api.nodes.Node;
208+
import com.oracle.truffle.api.object.HiddenKey;
206209
import com.oracle.truffle.api.profiles.BranchProfile;
207210
import com.oracle.truffle.api.profiles.ConditionProfile;
208211
import com.oracle.truffle.api.source.Source;
@@ -1718,22 +1721,31 @@ public static GetTypeMemberNode getUncached() {
17181721
* Use this node to lookup a native type member like {@code tp_alloc}.<br>
17191722
* <p>
17201723
* This node basically implements the native member inheritance that is done by
1721-
* {@code inherit_special} or other code in {@code PyType_Ready}.
1724+
* {@code inherit_special} or other code in {@code PyType_Ready}. In addition, we do a special
1725+
* case for special slots assignment that happens within {@Code type_new_alloc} for heap types.
17221726
* </p>
17231727
* <p>
17241728
* Since it may be that a managed types needs to emulate such members but there is no
1725-
* corresponding Python attribute (e.g. {@code tp_alloc}), such members are stored as hidden
1726-
* keys on the managed type. However, the MRO may contain native types and in this case, we need
1727-
* to access the native member.
1729+
* corresponding Python attribute (e.g. {@code tp_vectorcall_offset}), such members are stored
1730+
* as hidden keys on the managed type. However, the MRO may contain native types and in this
1731+
* case, we need to access the native member.
17281732
* </p>
17291733
*/
17301734
@GenerateUncached
17311735
public abstract static class LookupNativeMemberInMRONode extends Node {
17321736

1733-
public abstract Object execute(Object cls, NativeMember nativeMemberName, Object managedMemberName);
1737+
public abstract Object execute(Object cls, NativeMember nativeMemberName, HiddenKey managedMemberName);
17341738

1735-
@Specialization
1736-
static Object doSingleContext(Object cls, NativeMember nativeMemberName, Object managedMemberName,
1739+
static boolean isSpecialHeapSlot(Object cls, HiddenKey key) {
1740+
return cls instanceof PythonClass && (key == TypeBuiltins.TYPE_ALLOC || key == TypeBuiltins.TYPE_DEL);
1741+
// mq: not supported yet
1742+
// key == TypeBuiltins.TYPE_DEALLOC (subtype_dealloc)
1743+
// key == TypeBuiltins.TYPE_TRAVERSE (subtype_traverse)
1744+
// key == TypeBuiltins.TYPE_CLEAR (subtype_clear)
1745+
}
1746+
1747+
@Specialization(guards = "!isSpecialHeapSlot(cls, managedMemberName)")
1748+
static Object doSingleContext(Object cls, NativeMember nativeMemberName, HiddenKey managedMemberName,
17371749
@Cached GetMroStorageNode getMroNode,
17381750
@Cached SequenceStorageNodes.GetItemDynamicNode getItemNode,
17391751
@Cached("createForceType()") ReadAttributeFromObjectNode readAttrNode,
@@ -1744,6 +1756,7 @@ static Object doSingleContext(Object cls, NativeMember nativeMemberName, Object
17441756

17451757
for (int i = 0; i < n; i++) {
17461758
PythonAbstractClass mroCls = (PythonAbstractClass) getItemNode.execute(mroStorage, i);
1759+
17471760
Object result;
17481761
if (PGuards.isManagedClass(mroCls)) {
17491762
result = readAttrNode.execute(mroCls, managedMemberName);
@@ -1756,7 +1769,34 @@ static Object doSingleContext(Object cls, NativeMember nativeMemberName, Object
17561769
}
17571770
}
17581771

1759-
return PNone.NO_VALUE;
1772+
return readAttrNode.execute(PythonContext.get(readAttrNode).lookupType(PythonBuiltinClassType.PythonObject), managedMemberName);
1773+
}
1774+
1775+
@TruffleBoundary
1776+
static Object createSpecialHeapSlot(Object cls, HiddenKey managedMemberName, Node node) {
1777+
Object func;
1778+
if (managedMemberName == TypeBuiltins.TYPE_ALLOC || managedMemberName == TypeBuiltins.TYPE_DEL) {
1779+
PythonObject object = PythonContext.get(null).lookupType(PythonBuiltinClassType.PythonObject);
1780+
// We need to point to PyType_GenericAlloc or PyObject_GC_Del
1781+
func = ReadAttributeFromObjectNode.getUncachedForceType().execute(object, managedMemberName);
1782+
WriteAttributeToObjectNode.getUncached().execute(cls, managedMemberName, func);
1783+
} else {
1784+
// managedMemberName == TypeBuiltins.TYPE_DEALLOC
1785+
// managedMemberName == TypeBuiltins.TYPE_CLEAR
1786+
// managedMemberName == TypeBuiltins.TYPE_TRAVERSE
1787+
throw PRaiseNode.raiseUncached(node, SystemError, tsLiteral("not supported yet!"));
1788+
}
1789+
return func;
1790+
}
1791+
1792+
@Specialization(guards = "isSpecialHeapSlot(cls, managedMemberName)")
1793+
static Object doToAllocOrDelManaged(Object cls, @SuppressWarnings("unused") NativeMember nativeMemberName, HiddenKey managedMemberName,
1794+
@Cached("createForceType()") ReadAttributeFromObjectNode readAttrNode) {
1795+
Object func = readAttrNode.execute(cls, managedMemberName);
1796+
if (func == PNone.NO_VALUE) {
1797+
func = createSpecialHeapSlot(cls, managedMemberName, readAttrNode);
1798+
}
1799+
return func;
17601800
}
17611801
}
17621802

0 commit comments

Comments
 (0)