Skip to content

Commit a300bc0

Browse files
committed
Fix storing promoted values in _PyType_Lookup
1 parent 21075be commit a300bc0

File tree

2 files changed

+85
-7
lines changed

2 files changed

+85
-7
lines changed

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
import array
4141
import sys
4242

43-
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, unhandled_error_compare, IS_MANAGED_LAUNCHER
43+
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, unhandled_error_compare, IS_MANAGED_LAUNCHER, CPyExtHeapType
4444

4545
__dir__ = __file__.rpartition("/")[0]
4646

@@ -74,6 +74,24 @@ def identCallResult(arg):
7474
return ident(arg)
7575

7676

77+
class TypeWithAttr:
78+
attr = "str"
79+
80+
81+
class SubtypeWithAttr(TypeWithAttr):
82+
pass
83+
84+
85+
class TypeWithAttrInDict:
86+
attr = "str"
87+
88+
89+
TypeWithAttrInDict.__dict__
90+
91+
NativeTypeWithAttr = CPyExtHeapType("NativeTypeWithAttr")
92+
NativeTypeWithAttr.attr = "str"
93+
94+
7795
class TestPyObject(CPyExtTestCase):
7896

7997
test_Py_TYPE = CPyExtFunction(
@@ -388,6 +406,22 @@ def __getattr__(self, item):
388406
argspec="Os",
389407
)
390408

409+
test__PyType_Lookup = CPyExtFunction(
410+
lambda args: "str",
411+
lambda: (
412+
(TypeWithAttr, "attr"),
413+
(TypeWithAttr, "attr"),
414+
(SubtypeWithAttr, "attr"),
415+
(SubtypeWithAttr, "attr"),
416+
(TypeWithAttrInDict, "attr"),
417+
(TypeWithAttrInDict, "attr"),
418+
(NativeTypeWithAttr, "attr"),
419+
(NativeTypeWithAttr, "attr"),
420+
),
421+
arguments=["PyTypeObject* type", "PyObject* name"],
422+
argspec="OO",
423+
)
424+
391425
def setattrstring(args):
392426
setattr(*args)
393427
return 0

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.PyObjectSetAttrNode;
6969
import com.oracle.graal.python.builtins.objects.PNone;
7070
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
71+
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
7172
import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
7273
import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext;
7374
import com.oracle.graal.python.builtins.objects.cext.capi.CApiMemberAccessNodes.ReadMemberNode;
@@ -79,6 +80,8 @@
7980
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.SetterRoot;
8081
import com.oracle.graal.python.builtins.objects.cext.common.CArrayWrappers.CArrayWrapper;
8182
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
83+
import com.oracle.graal.python.builtins.objects.cext.structs.CFields;
84+
import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess;
8285
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
8386
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetItem;
8487
import com.oracle.graal.python.builtins.objects.dict.PDict;
@@ -88,15 +91,18 @@
8891
import com.oracle.graal.python.builtins.objects.object.PythonObject;
8992
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
9093
import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass;
94+
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
9195
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
9296
import com.oracle.graal.python.builtins.objects.type.TpSlots;
9397
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
98+
import com.oracle.graal.python.lib.PyDictGetItem;
9499
import com.oracle.graal.python.lib.PyDictSetDefault;
100+
import com.oracle.graal.python.lib.PyDictSetItem;
95101
import com.oracle.graal.python.nodes.HiddenAttr;
96102
import com.oracle.graal.python.nodes.SpecialAttributeNames;
97-
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
98103
import com.oracle.graal.python.nodes.attributes.WriteAttributeToPythonObjectNode;
99104
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
105+
import com.oracle.graal.python.nodes.object.GetDictIfExistsNode;
100106
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
101107
import com.oracle.graal.python.runtime.PythonContext;
102108
import com.oracle.graal.python.runtime.PythonOptions;
@@ -122,6 +128,7 @@
122128
import com.oracle.truffle.api.nodes.Node;
123129
import com.oracle.truffle.api.nodes.RootNode;
124130
import com.oracle.truffle.api.object.DynamicObject;
131+
import com.oracle.truffle.api.object.DynamicObjectLibrary;
125132
import com.oracle.truffle.api.object.Shape;
126133
import com.oracle.truffle.api.profiles.InlinedExactClassProfile;
127134
import com.oracle.truffle.api.strings.TruffleString;
@@ -135,13 +142,50 @@ abstract static class _PyType_Lookup extends CApiBinaryBuiltinNode {
135142
Object doGeneric(Object type, Object name,
136143
@Bind("this") Node inliningTarget,
137144
@Cached CastToTruffleStringNode castToTruffleStringNode,
138-
@Cached LookupAttributeInMRONode.Dynamic lookupAttributeInMRONode) {
145+
@Cached TypeNodes.GetMroStorageNode getMroStorageNode,
146+
@Cached PythonCextBuiltins.PromoteBorrowedValue promoteBorrowedValue,
147+
@Cached CStructAccess.ReadObjectNode getNativeDict,
148+
@Cached GetDictIfExistsNode getDictIfExistsNode,
149+
@CachedLibrary(limit = "3") DynamicObjectLibrary dylib,
150+
@Cached PyDictGetItem getItem,
151+
@Cached PyDictSetItem setItem) {
139152
TruffleString key = castToTruffleStringNode.castKnownString(inliningTarget, name);
140-
Object result = lookupAttributeInMRONode.execute(type, key);
141-
if (result == PNone.NO_VALUE) {
142-
return getNativeNull();
153+
MroSequenceStorage mro = getMroStorageNode.execute(inliningTarget, type);
154+
for (int i = 0; i < mro.length(); i++) {
155+
PythonAbstractClass cls = mro.getPythonClassItemNormalized(i);
156+
PDict dict;
157+
if (cls instanceof PythonAbstractNativeObject nativeCls) {
158+
Object dictObj = getNativeDict.readFromObj(nativeCls, CFields.PyTypeObject__tp_dict);
159+
if (dictObj instanceof PDict d) {
160+
dict = d;
161+
} else {
162+
continue;
163+
}
164+
} else if (cls instanceof PythonManagedClass managedCls) {
165+
dict = getDictIfExistsNode.execute(managedCls);
166+
} else {
167+
throw CompilerDirectives.shouldNotReachHere();
168+
}
169+
Object value;
170+
if (dict == null) {
171+
value = dylib.getOrDefault((DynamicObject) cls, key, null);
172+
} else {
173+
value = getItem.execute(null, inliningTarget, dict, key);
174+
}
175+
if (value != null && value != PNone.NO_VALUE) {
176+
Object promoted = promoteBorrowedValue.execute(inliningTarget, value);
177+
if (promoted != null) {
178+
if (dict == null) {
179+
dylib.put((DynamicObject) cls, key, promoted);
180+
} else {
181+
setItem.execute(null, inliningTarget, dict, key, promoted);
182+
}
183+
return promoted;
184+
}
185+
return value;
186+
}
143187
}
144-
return result;
188+
return getNativeNull();
145189
}
146190
}
147191

0 commit comments

Comments
 (0)