Skip to content

Commit fbe3af9

Browse files
committed
Fix multiple inheritance scenario with managed dict
1 parent c2cd948 commit fbe3af9

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@
4545

4646
NativeTypeWithDict = CPyExtType(
4747
name='NativeTypeWithDict',
48-
cmembers='PyObject* dict;',
48+
cmembers='int some_field; PyObject* dict;',
4949
tp_dictoffset='offsetof(NativeTypeWithDictObject, dict)',
5050
tp_getset='{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}',
5151
)
5252

5353
NativeHeapTypeWithoutDict = CPyExtHeapType(
54+
cmembers='int some_field;',
5455
name='NativeTypeWithManagedDict',
5556
)
5657

@@ -75,7 +76,7 @@
7576

7677

7778
# TODO it would be great if we could test creating heap types with Py_TPFLAGS_MANAGED_DICT, because pybind11 does that,
78-
# but there's no way to do that without abusing abusing implementations details
79+
# but there's no way to do that without abusing implementations details
7980

8081

8182
class NativeSubtypeWithDict(NativeTypeWithDict):
@@ -107,3 +108,15 @@ def test_dict(self):
107108
self.assert_has_working_dict(NativeHeapTypeWithDict())
108109
self.assert_has_working_dict(NativeSubtypeWithDict())
109110
self.assert_has_working_dict(NativeSubtypeWithAddedDict())
111+
112+
def test_multiple_inheritance(self):
113+
class Base1(NativeTypeWithoutDict):
114+
pass
115+
116+
class Base2(NativeTypeWithoutDict):
117+
pass
118+
119+
class Derived(Base1, Base2):
120+
pass
121+
122+
self.assert_has_working_dict(Derived())

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,18 +2356,24 @@ private static void addNativeSlots(TypeNewContext ctx, PythonManagedClass python
23562356
long dictOffset = GetDictOffsetNode.executeUncached(base);
23572357
long weakListOffset = GetWeakListOffsetNode.executeUncached(base);
23582358
long itemSize = GetItemSizeNode.executeUncached(base);
2359-
if (ctx.addDict) {
2360-
if (itemSize != 0) {
2361-
dictOffset = -SIZEOF_PY_OBJECT_PTR;
2362-
} else {
2363-
dictOffset = slotOffset;
2364-
}
2359+
if (ctx.addDict && itemSize != 0) {
2360+
dictOffset = -SIZEOF_PY_OBJECT_PTR;
23652361
slotOffset += SIZEOF_PY_OBJECT_PTR;
23662362
}
23672363
if (ctx.addWeak) {
23682364
weakListOffset = slotOffset;
23692365
slotOffset += SIZEOF_PY_OBJECT_PTR;
23702366
}
2367+
if (ctx.addDict && itemSize == 0) {
2368+
long flags = GetTypeFlagsNode.executeUncached(pythonClass) | MANAGED_DICT;
2369+
SetTypeFlagsNode.executeUncached(pythonClass, flags);
2370+
/*
2371+
* Negative offsets are computed from the end of the structure. Our managed dict is
2372+
* right before the start of the object. CPython has 3 fields there, so our formula
2373+
* differs.
2374+
*/
2375+
dictOffset = -slotOffset - SIZEOF_PY_OBJECT_PTR;
2376+
}
23712377
SetDictOffsetNode.executeUncached(pythonClass, dictOffset);
23722378
SetBasicSizeNode.executeUncached(pythonClass, slotOffset);
23732379
SetItemSizeNode.executeUncached(pythonClass, itemSize);

0 commit comments

Comments
 (0)