Skip to content

Commit 68904ef

Browse files
committed
Provide a single point to notify PythonManagedClass about attribute updates
Additionally, provide a simple fast-path PE friendly check whether the TruffleBoundary attribute update notification need to be called. Used those new methods in WriteAttributeToObjectNode.
1 parent bc7b176 commit 68904ef

File tree

3 files changed

+46
-24
lines changed

3 files changed

+46
-24
lines changed

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,15 +209,32 @@ private boolean computeNeedsNativeAllocation() {
209209
@Override
210210
@TruffleBoundary
211211
public void setAttribute(Object key, Object value) {
212-
invalidateFinalAttribute(key);
213212
super.setAttribute(key, value);
213+
onAttributeUpdate(key, value);
214214
}
215215

216-
@TruffleBoundary
217-
public final void invalidateFinalAttribute(Object key) {
216+
/**
217+
* Fast-path check designed for PE code.
218+
*/
219+
public final boolean canSkipOnAttributeUpdate(String key, Object value) {
220+
return !methodResolutionOrder.hasAttributeInMROFinalAssumptions() &&
221+
!SpecialMethodSlot.canBeSpecial(key);
222+
}
223+
224+
public final void onAttributeUpdate(Object key, Object value) {
225+
// In compilation: use a profile and call the String key overload
218226
CompilerAsserts.neverPartOfCompilation();
219227
if (key instanceof String) {
220-
methodResolutionOrder.invalidateAttributeInMROFinalAssumptions((String) key);
228+
onAttributeUpdate((String) key, value);
229+
}
230+
}
231+
232+
@TruffleBoundary
233+
public final void onAttributeUpdate(String key, Object value) {
234+
methodResolutionOrder.invalidateAttributeInMROFinalAssumptions(key);
235+
SpecialMethodSlot slot = SpecialMethodSlot.findSpecialSlot(key);
236+
if (slot != null) {
237+
SpecialMethodSlot.fixupSpecialMethodSlot(this, slot, value);
221238
}
222239
}
223240

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

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,6 @@ protected static boolean isAttrWritable(PythonObject self, Object key) {
101101
return (self.getShape().getFlags() & PythonObject.HAS_SLOTS_BUT_NO_DICT_FLAG) == 0;
102102
}
103103

104-
private static void fixupSpecialMethodSlots(BranchProfile isSpecialKey, PythonManagedClass object, String key, Object value) {
105-
if (SpecialMethodSlot.canBeSpecial(key)) {
106-
isSpecialKey.enter();
107-
SpecialMethodSlot slot = SpecialMethodSlot.findSpecialSlot(key);
108-
if (slot != null) {
109-
SpecialMethodSlot.fixupSpecialMethodSlot(object, slot, value);
110-
}
111-
}
112-
}
113-
114104
private static String castKey(CastToJavaStringNode castNode, Object value) {
115105
try {
116106
return castNode.execute(value);
@@ -138,30 +128,37 @@ static boolean writeToDynamicStorageNoType(PythonObject object, Object key, Obje
138128
static boolean writeToDynamicStorageBuiltinType(PythonBuiltinClass klass, Object key, Object value,
139129
@CachedLibrary("klass") @SuppressWarnings("unused") PythonObjectLibrary lib,
140130
@Cached CastToJavaStringNode castToStrNode,
141-
@Cached BranchProfile isSpecialKey,
142-
@Cached BranchProfile changedShape,
131+
@Cached BranchProfile callAttrUpdate,
143132
@Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode) {
144133
String strKey = castKey(castToStrNode, key);
145134
try {
146135
return writeAttributeToDynamicObjectNode.execute(klass, strKey, value);
147136
} finally {
148-
klass.invalidateFinalAttribute(strKey);
149-
fixupSpecialMethodSlots(isSpecialKey, klass, strKey, value);
137+
if (!klass.canSkipOnAttributeUpdate(strKey, value)) {
138+
callAttrUpdate.enter();
139+
klass.onAttributeUpdate(strKey, value);
140+
}
150141
}
151142
}
152143

144+
static boolean[] createFlag() {
145+
return new boolean[1];
146+
}
147+
153148
@Specialization(guards = {"!isHiddenKey(key)", "!lib.hasDict(klass)", "isAttrWritable(klass, key)"}, limit = "1")
154149
static boolean writeToDynamicStoragePythonClass(PythonClass klass, Object key, Object value,
155150
@CachedLibrary("klass") @SuppressWarnings("unused") PythonObjectLibrary lib,
156151
@Cached CastToJavaStringNode castToStrNode,
157-
@Cached BranchProfile isSpecialKey,
152+
@Cached BranchProfile callAttrUpdate,
158153
@Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode) {
159154
String strKey = castKey(castToStrNode, key);
160155
try {
161156
return writeAttributeToDynamicObjectNode.execute(klass, strKey, value);
162157
} finally {
163-
klass.invalidateFinalAttribute(strKey);
164-
fixupSpecialMethodSlots(isSpecialKey, klass, strKey, value);
158+
if (!klass.canSkipOnAttributeUpdate(strKey, value)) {
159+
callAttrUpdate.enter();
160+
klass.onAttributeUpdate(strKey, value);
161+
}
165162
}
166163
}
167164

@@ -177,16 +174,18 @@ static boolean writeToDictNoType(PythonObject object, Object key, Object value,
177174
@Specialization(guards = {"!isHiddenKey(key)", "lib.hasDict(klass)"}, limit = "1")
178175
static boolean writeToDictBuiltinType(PythonManagedClass klass, Object key, Object value,
179176
@Cached CastToJavaStringNode castToStrNode,
180-
@Cached BranchProfile isSpecialKey,
177+
@Cached BranchProfile callAttrUpdate,
181178
@CachedLibrary("klass") PythonObjectLibrary lib,
182179
@Cached BranchProfile updateStorage,
183180
@CachedLibrary(limit = "1") HashingStorageLibrary hlib) {
184181
String strKey = castKey(castToStrNode, key);
185182
try {
186183
return writeToDict(lib.getDict(klass), strKey, value, updateStorage, hlib);
187184
} finally {
188-
klass.invalidateFinalAttribute(strKey);
189-
fixupSpecialMethodSlots(isSpecialKey, klass, strKey, value);
185+
if (!klass.canSkipOnAttributeUpdate(strKey, value)) {
186+
callAttrUpdate.enter();
187+
klass.onAttributeUpdate(strKey, value);
188+
}
190189
}
191190
}
192191

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/MroSequenceStorage.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public final class MroSequenceStorage extends TypedSequenceStorage {
7171
* assumptions will be invalidated if the mro changes.
7272
*/
7373
private final Map<String, List<Assumption>> attributesInMROFinalAssumptions;
74+
private boolean hasAttributesInMROFinalAssumptions;
7475

7576
@CompilationFinal(dimensions = 1) private final PythonAbstractClass[] values;
7677

@@ -228,6 +229,7 @@ public Assumption createAttributeInMROFinalAssumption(String name) {
228229
List<Assumption> attrAssumptions = attributesInMROFinalAssumptions.getOrDefault(name, null);
229230
if (attrAssumptions == null) {
230231
attrAssumptions = new ArrayList<>();
232+
hasAttributesInMROFinalAssumptions = true;
231233
attributesInMROFinalAssumptions.put(name, attrAssumptions);
232234
}
233235

@@ -241,6 +243,7 @@ public void addAttributeInMROFinalAssumption(String name, Assumption assumption)
241243
List<Assumption> attrAssumptions = attributesInMROFinalAssumptions.getOrDefault(name, null);
242244
if (attrAssumptions == null) {
243245
attrAssumptions = new ArrayList<>();
246+
hasAttributesInMROFinalAssumptions = true;
244247
attributesInMROFinalAssumptions.put(name, attrAssumptions);
245248
}
246249

@@ -301,4 +304,7 @@ public Object[] getCopyOfInternalArray() {
301304
return getInternalArray();
302305
}
303306

307+
public final boolean hasAttributeInMROFinalAssumptions() {
308+
return hasAttributesInMROFinalAssumptions;
309+
}
304310
}

0 commit comments

Comments
 (0)