Skip to content

Commit 76ec107

Browse files
committed
use an assumption to signal the stability of a __dict__'s storage
- if the storage is still backed by the DynamicObject read directly from the DynamicObject location, else switch to reading the __dict__
1 parent edbf8ab commit 76ec107

File tree

8 files changed

+47
-25
lines changed

8 files changed

+47
-25
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage.PythonObjectDictStorage;
4646
import com.oracle.graal.python.builtins.objects.str.PString;
4747
import com.oracle.graal.python.builtins.objects.type.PythonClass;
48+
import com.oracle.truffle.api.Assumption;
4849
import com.oracle.truffle.api.CompilerAsserts;
4950
import com.oracle.truffle.api.interop.ForeignAccess;
5051
import com.oracle.truffle.api.interop.TruffleObject;
@@ -112,9 +113,9 @@ public DynamicObjectNativeWrapper(Object delegate) {
112113
super(delegate);
113114
}
114115

115-
public PythonObjectDictStorage createNativeMemberStore() {
116+
public PythonObjectDictStorage createNativeMemberStore(Assumption dictStableAssumption) {
116117
if (nativeMemberStore == null) {
117-
nativeMemberStore = new PythonObjectDictStorage(SHAPE.newInstance());
118+
nativeMemberStore = new PythonObjectDictStorage(SHAPE.newInstance(), dictStableAssumption);
118119
}
119120
return nativeMemberStore;
120121
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ Object doTpSubclasses(PythonClass object, @SuppressWarnings("unused") String key
680680
Object doMdDef(PythonObject object, @SuppressWarnings("unused") String key, Object value) {
681681
DynamicObjectNativeWrapper nativeWrapper = ((PythonAbstractObject) object).getNativeWrapper();
682682
assert nativeWrapper != null;
683-
getSetItemNode().execute(nativeWrapper.createNativeMemberStore(), NativeMemberNames.MD_DEF, value);
683+
getSetItemNode().execute(nativeWrapper.createNativeMemberStore(object.getDictStableAssumption()), NativeMemberNames.MD_DEF, value);
684684
return value;
685685
}
686686

@@ -701,7 +701,7 @@ Object doTpDict(PythonClass object, @SuppressWarnings("unused") String key, Obje
701701
if (existing != null) {
702702
d.setDictStorage(existing.getDictStorage());
703703
} else {
704-
d.setDictStorage(new DynamicObjectStorage.PythonObjectDictStorage(object.getStorage()));
704+
d.setDictStorage(new DynamicObjectStorage.PythonObjectDictStorage(object.getStorage(), object.getDictStableAssumption()));
705705
}
706706
object.setDict(d);
707707
} else {
@@ -735,7 +735,7 @@ Object doGeneric(Object object, String key, Object value) {
735735
DynamicObjectNativeWrapper nativeWrapper = ((PythonAbstractObject) object).getNativeWrapper();
736736
assert nativeWrapper != null;
737737
logGeneric(key);
738-
getSetItemNode().execute(nativeWrapper.createNativeMemberStore(), key, value);
738+
getSetItemNode().execute(nativeWrapper.createNativeMemberStore(null), key, value);
739739
return value;
740740
}
741741
throw UnknownIdentifierException.raise(key);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import java.util.ArrayList;
4444

45+
import com.oracle.truffle.api.Assumption;
4546
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4647
import com.oracle.truffle.api.object.DynamicObject;
4748
import com.oracle.truffle.api.object.Layout;
@@ -159,15 +160,22 @@ public HashingStorage copy(Equivalence eq) {
159160
}
160161

161162
public static class PythonObjectDictStorage extends DynamicObjectStorage {
162-
public PythonObjectDictStorage(DynamicObject store) {
163+
private final Assumption dictStableAssumption;
164+
165+
public PythonObjectDictStorage(DynamicObject store, Assumption dictStableAssumption) {
163166
super(store);
167+
this.dictStableAssumption = dictStableAssumption;
168+
}
169+
170+
public Assumption getDictStableAssumption() {
171+
return dictStableAssumption;
164172
}
165173

166174
@Override
167175
@TruffleBoundary
168176
public HashingStorage copy(Equivalence eq) {
169177
assert eq == HashingStorage.DEFAULT_EQIVALENCE;
170-
return new PythonObjectDictStorage(getStore().copy(getStore().getShape()));
178+
return new PythonObjectDictStorage(getStore().copy(getStore().getShape()), getDictStableAssumption());
171179
}
172180
}
173181

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
import com.oracle.graal.python.runtime.exception.PException;
9191
import com.oracle.graal.python.runtime.exception.PythonErrorType;
9292
import com.oracle.graal.python.runtime.sequence.PSequence;
93+
import com.oracle.truffle.api.Assumption;
9394
import com.oracle.truffle.api.CompilerAsserts;
9495
import com.oracle.truffle.api.CompilerDirectives;
9596
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -240,6 +241,10 @@ protected static DynamicObjectStorage switchToFastDictStorage(HashingStorage sto
240241
}
241242

242243
protected static PythonObjectHybridDictStorage switchToHybridDictStorage(PythonObjectDictStorage dictStorage) {
244+
Assumption dictStableAssumption = dictStorage.getDictStableAssumption();
245+
if (dictStableAssumption != null) {
246+
dictStableAssumption.invalidate();
247+
}
243248
return new PythonObjectHybridDictStorage(dictStorage);
244249
}
245250

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectBuiltins.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ Object dict(PythonObject self, @SuppressWarnings("unused") PNone none) {
504504

505505
@Specialization(guards = {"!isBuiltinObject(self)", "!isClass(self)", "!isExactObjectInstance(self)"})
506506
Object dict(PythonObject self, PDict dict) {
507+
self.getDictStableAssumption().invalidate();
507508
self.setDict(dict);
508509
return PNone.NONE;
509510
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/PythonObject.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
import com.oracle.truffle.api.Assumption;
4040
import com.oracle.truffle.api.CompilerAsserts;
4141
import com.oracle.truffle.api.CompilerDirectives;
42-
import com.oracle.truffle.api.Truffle;
4342
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
4443
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
44+
import com.oracle.truffle.api.Truffle;
4545
import com.oracle.truffle.api.object.DynamicObject;
4646
import com.oracle.truffle.api.object.Location;
4747
import com.oracle.truffle.api.object.Property;
@@ -50,6 +50,7 @@
5050
public class PythonObject extends PythonAbstractObject {
5151
@CompilationFinal private LazyPythonClass pythonClass;
5252
private final Assumption classStable = Truffle.getRuntime().createAssumption("class unchanged");
53+
private final Assumption dictStable = Truffle.getRuntime().createAssumption("dict unchanged from instance attributes");
5354
private final DynamicObject storage;
5455
private PHashingCollection dict;
5556

@@ -103,6 +104,10 @@ public final Assumption getClassStableAssumption() {
103104
return classStable;
104105
}
105106

107+
public final Assumption getDictStableAssumption() {
108+
return dictStable;
109+
}
110+
106111
public final DynamicObject getStorage() {
107112
return storage;
108113
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromObjectNode.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import com.oracle.graal.python.builtins.objects.PNone;
4444
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes;
45-
import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
4645
import com.oracle.graal.python.builtins.objects.object.PythonObject;
4746
import com.oracle.graal.python.builtins.objects.str.PString;
4847
import com.oracle.graal.python.nodes.PGuards;
@@ -104,25 +103,25 @@ protected Object attrKey(Object key) {
104103
@Specialization(limit = "1", //
105104
guards = {
106105
"object == cachedObject",
107-
"cachedDict == null",
108106
"checkShape(object, cachedObject, cachedShape)",
109107
"key == cachedKey",
110108
"!isNull(loc)",
111109
"loc.isAssumedFinal()",
112110
}, //
113111
assumptions = {
114112
"layoutAssumption",
115-
"finalAssumption"
113+
"finalAssumption",
114+
"dictStableAssumption"
116115
})
117116
protected Object readDirectFinal(PythonObject object, Object key,
118117
@Cached("object") PythonObject cachedObject,
119118
@Cached("key") Object cachedKey,
120119
@Cached("attrKey(key)") Object attrKey,
121120
@Cached("object.getStorage().getShape()") Shape cachedShape,
122-
@Cached("object.getDict()") PHashingCollection cachedDict,
123121
@Cached("cachedShape.getValidAssumption()") Assumption layoutAssumption,
124122
@Cached("getLocationOrNull(cachedShape.getProperty(attrKey))") Location loc,
125123
@Cached("loc.getFinalAssumption()") Assumption finalAssumption,
124+
@SuppressWarnings("unused") @Cached("object.getDictStableAssumption()") Assumption dictStableAssumption,
126125
@Cached("readFinalValue(object, loc)") Object cachedValue) {
127126
assert assertFinal(object, attrKey, cachedValue);
128127
return cachedValue;
@@ -137,17 +136,19 @@ private static boolean assertFinal(PythonObject object, Object key, Object cache
137136
@Specialization(limit = "getIntOption(getContext(), AttributeAccessInlineCacheMaxDepth)", //
138137
guards = {
139138
"object.getStorage().getShape() == cachedShape",
140-
"cachedDict == null",
141139
"key == cachedKey",
142140
"isNull(loc) || !loc.isAssumedFinal()",
143141
}, //
144-
assumptions = "layoutAssumption")
142+
assumptions = {
143+
"layoutAssumption",
144+
"dictStableAssumption"
145+
})
145146
protected Object readDirect(PythonObject object, Object key,
146147
@Cached("key") Object cachedKey,
147148
@Cached("attrKey(cachedKey)") Object attrKey,
148149
@Cached("object.getStorage().getShape()") Shape cachedShape,
149-
@Cached("object.getDict()") PHashingCollection cachedDict,
150150
@Cached("cachedShape.getValidAssumption()") Assumption layoutAssumption,
151+
@SuppressWarnings("unused") @Cached("object.getDictStableAssumption()") Assumption dictStableAssumption,
151152
@Cached("getLocationOrNull(cachedShape.getProperty(attrKey))") Location loc) {
152153
if (loc == null) {
153154
return PNone.NO_VALUE;
@@ -159,21 +160,21 @@ protected Object readDirect(PythonObject object, Object key,
159160
@SuppressWarnings("unused")
160161
@Specialization(guards = {
161162
"object.getStorage().getShape() == cachedShape",
162-
"cachedDict == null",
163163
"!layoutAssumption.isValid()"
164-
})
164+
}, assumptions = "dictStableAssumption")
165165
protected Object updateShapeAndRead(PythonObject object, Object key,
166166
@Cached("object.getStorage().getShape()") Shape cachedShape,
167-
@Cached("object.getDict()") PHashingCollection cachedDict,
168167
@Cached("cachedShape.getValidAssumption()") Assumption layoutAssumption,
168+
@SuppressWarnings("unused") @Cached("object.getDictStableAssumption()") Assumption dictStableAssumption,
169169
@Cached("create()") ReadAttributeFromObjectNode nextNode) {
170170
CompilerDirectives.transferToInterpreter();
171171
object.getStorage().updateShape();
172172
return nextNode.execute(object, key);
173173
}
174174

175-
@Specialization(guards = "object.getDict() == null", replaces = "readDirect")
176-
protected Object readIndirect(PythonObject object, Object key) {
175+
@Specialization(replaces = "readDirect", assumptions = "dictStableAssumption")
176+
protected Object readIndirect(PythonObject object, Object key,
177+
@SuppressWarnings("unused") @Cached("object.getDictStableAssumption()") Assumption dictStableAssumption) {
177178
Object value = object.getStorage().get(attrKey(key));
178179
if (value == null) {
179180
return PNone.NO_VALUE;
@@ -182,9 +183,10 @@ protected Object readIndirect(PythonObject object, Object key) {
182183
}
183184
}
184185

185-
@Specialization(guards = "object.getDict() != null")
186+
@Specialization(guards = "!dictStableAssumption.isValid()")
186187
protected Object readFromDict(PythonObject object, Object key,
187-
@Cached("create()") HashingStorageNodes.GetItemNode getItemNode) {
188+
@Cached("create()") HashingStorageNodes.GetItemNode getItemNode,
189+
@SuppressWarnings("unused") @Cached("object.getDictStableAssumption()") Assumption dictStableAssumption) {
188190
Object value = getItemNode.execute(object.getDict().getDictStorage(), key);
189191
if (value == null) {
190192
return PNone.NO_VALUE;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PythonObjectFactory.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ public PDict createDict(DynamicObject dynamicObject) {
476476
}
477477

478478
public PDict createDictFixedStorage(PythonObject pythonObject) {
479-
return createDict(new PythonObjectDictStorage(pythonObject.getStorage()));
479+
return createDict(new PythonObjectDictStorage(pythonObject.getStorage(), pythonObject.getDictStableAssumption()));
480480
}
481481

482482
public PDict createDict(HashingStorage storage) {
@@ -510,15 +510,15 @@ public PGeneratorFunction createGeneratorFunction(String name, String enclosingC
510510
}
511511

512512
public PMappingproxy createMappingproxy(PythonObject object) {
513-
return trace(new PMappingproxy(PythonBuiltinClassType.PMappingproxy, new PythonObjectDictStorage(object.getStorage())));
513+
return trace(new PMappingproxy(PythonBuiltinClassType.PMappingproxy, new PythonObjectDictStorage(object.getStorage(), object.getDictStableAssumption())));
514514
}
515515

516516
public PMappingproxy createMappingproxy(HashingStorage storage) {
517517
return trace(new PMappingproxy(PythonBuiltinClassType.PMappingproxy, storage));
518518
}
519519

520520
public PMappingproxy createMappingproxy(PythonClass cls, PythonObject object) {
521-
return trace(new PMappingproxy(cls, new PythonObjectDictStorage(object.getStorage())));
521+
return trace(new PMappingproxy(cls, new PythonObjectDictStorage(object.getStorage(), object.getDictStableAssumption())));
522522
}
523523

524524
public PMappingproxy createMappingproxy(LazyPythonClass cls, HashingStorage storage) {

0 commit comments

Comments
 (0)