Skip to content

Commit bc7b176

Browse files
committed
Restructure WriteAttributeToObjectNode to avoid doing key casts twice and to improve footprint
1 parent b9d24b1 commit bc7b176

File tree

2 files changed

+76
-83
lines changed

2 files changed

+76
-83
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@
5555
@GenerateUncached
5656
public abstract class WriteAttributeToDynamicObjectNode extends ObjectAttributeNode {
5757

58-
public abstract boolean execute(Object primary, Object key, Object value);
59-
6058
public abstract boolean execute(Object primary, HiddenKey key, Object value);
6159

6260
public abstract boolean execute(Object primary, String key, Object value);
6361

62+
public abstract boolean execute(Object primary, Object key, Object value);
63+
6464
public static WriteAttributeToDynamicObjectNode create() {
6565
return WriteAttributeToDynamicObjectNodeGen.create();
6666
}
@@ -76,8 +76,8 @@ static boolean writeDirect(DynamicObject dynamicObject, String key, Object value
7676
return true;
7777
}
7878

79-
@Specialization(guards = "isHiddenKey(key)", limit = "getAttributeAccessInlineCacheMaxDepth()")
80-
static boolean writeDirectHidden(DynamicObject dynamicObject, Object key, Object value,
79+
@Specialization(limit = "getAttributeAccessInlineCacheMaxDepth()")
80+
static boolean writeDirectHidden(DynamicObject dynamicObject, HiddenKey key, Object value,
8181
@CachedLibrary("dynamicObject") DynamicObjectLibrary dylib) {
8282
dylib.put(dynamicObject, key, value);
8383
return true;

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

Lines changed: 72 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
import com.oracle.graal.python.builtins.objects.dict.PDict;
5151
import com.oracle.graal.python.builtins.objects.object.PythonObject;
5252
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
53+
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
54+
import com.oracle.graal.python.builtins.objects.type.PythonClass;
5355
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
5456
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
5557
import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode;
@@ -70,14 +72,16 @@
7072
import com.oracle.truffle.api.dsl.ImportStatic;
7173
import com.oracle.truffle.api.dsl.Specialization;
7274
import com.oracle.truffle.api.library.CachedLibrary;
73-
import com.oracle.truffle.api.nodes.Node;
75+
import com.oracle.truffle.api.object.HiddenKey;
7476
import com.oracle.truffle.api.profiles.BranchProfile;
7577

7678
@ImportStatic(PythonOptions.class)
7779
public abstract class WriteAttributeToObjectNode extends ObjectAttributeNode {
7880

7981
public abstract boolean execute(Object primary, Object key, Object value);
8082

83+
public abstract boolean execute(Object primary, HiddenKey key, Object value);
84+
8185
public static WriteAttributeToObjectNode create() {
8286
return WriteAttributeToObjectNotTypeNodeGen.create();
8387
}
@@ -97,61 +101,92 @@ protected static boolean isAttrWritable(PythonObject self, Object key) {
97101
return (self.getShape().getFlags() & PythonObject.HAS_SLOTS_BUT_NO_DICT_FLAG) == 0;
98102
}
99103

100-
private static void handlePossiblePythonClass(HandlePythonClassProfiles profiles, PythonObject object, Object keyObj, Object value) {
101-
if (PythonManagedClass.isInstance(object)) {
102-
profiles.isManagedClass.enter();
103-
handlePythonClass(profiles, PythonManagedClass.cast(object), keyObj, value);
104-
}
105-
}
106-
107-
private static void handlePythonClass(HandlePythonClassProfiles profiles, PythonManagedClass object, Object keyObj, Object value) {
108-
String key = profiles.castKey(keyObj);
109-
if (key == null) {
110-
return;
111-
}
112-
object.invalidateFinalAttribute(key);
113-
// Note: we need to handle builtin classes here, because during initialization we are
114-
// setting attributes of some builtin types to Python functions (when given builtin method
115-
// is not intrinsified in Java)
104+
private static void fixupSpecialMethodSlots(BranchProfile isSpecialKey, PythonManagedClass object, String key, Object value) {
116105
if (SpecialMethodSlot.canBeSpecial(key)) {
117-
profiles.isSpecialKey.enter();
106+
isSpecialKey.enter();
118107
SpecialMethodSlot slot = SpecialMethodSlot.findSpecialSlot(key);
119108
if (slot != null) {
120109
SpecialMethodSlot.fixupSpecialMethodSlot(object, slot, value);
121110
}
122111
}
123112
}
124113

125-
// write to the DynamicObject
126-
@Specialization(guards = {
127-
"isAttrWritable(object, key)",
128-
"isHiddenKey(key) || !lib.hasDict(object)"
129-
}, limit = "1")
130-
static boolean writeToDynamicStorage(PythonObject object, Object key, Object value,
114+
private static String castKey(CastToJavaStringNode castNode, Object value) {
115+
try {
116+
return castNode.execute(value);
117+
} catch (CannotCastException ex) {
118+
throw CompilerDirectives.shouldNotReachHere(ex);
119+
}
120+
}
121+
122+
@Specialization(guards = "isAttrWritable(object, key)")
123+
static boolean writeHiddenKeyToDynamicStorage(PythonObject object, HiddenKey key, Object value,
124+
@Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode) {
125+
// HiddenKeys are always written to the storage and do not have any other special handling
126+
return writeAttributeToDynamicObjectNode.execute(object.getStorage(), key, value);
127+
}
128+
129+
@Specialization(guards = {"!isHiddenKey(key)", "!lib.hasDict(object)", "isAttrWritable(object, key)", "!isManagedClass(object)"}, limit = "1")
130+
static boolean writeToDynamicStorageNoType(PythonObject object, Object key, Object value,
131131
@CachedLibrary("object") @SuppressWarnings("unused") PythonObjectLibrary lib,
132-
@Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode,
133-
@Exclusive @Cached HandlePythonClassProfiles handlePythonClassProfiles) {
132+
@Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode) {
133+
// Objects w/o dict that are not classes do not have any special handling
134+
return writeAttributeToDynamicObjectNode.execute(object.getStorage(), key, value);
135+
}
136+
137+
@Specialization(guards = {"!isHiddenKey(key)", "!lib.hasDict(klass)", "isAttrWritable(klass, key)"}, limit = "1")
138+
static boolean writeToDynamicStorageBuiltinType(PythonBuiltinClass klass, Object key, Object value,
139+
@CachedLibrary("klass") @SuppressWarnings("unused") PythonObjectLibrary lib,
140+
@Cached CastToJavaStringNode castToStrNode,
141+
@Cached BranchProfile isSpecialKey,
142+
@Cached BranchProfile changedShape,
143+
@Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode) {
144+
String strKey = castKey(castToStrNode, key);
134145
try {
135-
return writeAttributeToDynamicObjectNode.execute(object.getStorage(), key, value);
146+
return writeAttributeToDynamicObjectNode.execute(klass, strKey, value);
136147
} finally {
137-
handlePossiblePythonClass(handlePythonClassProfiles, object, key, value);
148+
klass.invalidateFinalAttribute(strKey);
149+
fixupSpecialMethodSlots(isSpecialKey, klass, strKey, value);
150+
}
151+
}
152+
153+
@Specialization(guards = {"!isHiddenKey(key)", "!lib.hasDict(klass)", "isAttrWritable(klass, key)"}, limit = "1")
154+
static boolean writeToDynamicStoragePythonClass(PythonClass klass, Object key, Object value,
155+
@CachedLibrary("klass") @SuppressWarnings("unused") PythonObjectLibrary lib,
156+
@Cached CastToJavaStringNode castToStrNode,
157+
@Cached BranchProfile isSpecialKey,
158+
@Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode) {
159+
String strKey = castKey(castToStrNode, key);
160+
try {
161+
return writeAttributeToDynamicObjectNode.execute(klass, strKey, value);
162+
} finally {
163+
klass.invalidateFinalAttribute(strKey);
164+
fixupSpecialMethodSlots(isSpecialKey, klass, strKey, value);
138165
}
139166
}
140167

141168
// write to the dict
142-
@Specialization(guards = {
143-
"!isHiddenKey(key)",
144-
"lib.hasDict(object)"
145-
}, limit = "1")
146-
static boolean writeToDict(PythonObject object, Object key, Object value,
169+
@Specialization(guards = {"!isHiddenKey(key)", "lib.hasDict(object)", "!isManagedClass(object)"}, limit = "1")
170+
static boolean writeToDictNoType(PythonObject object, Object key, Object value,
147171
@CachedLibrary("object") PythonObjectLibrary lib,
148172
@Cached BranchProfile updateStorage,
149-
@CachedLibrary(limit = "1") HashingStorageLibrary hlib,
150-
@Exclusive @Cached HandlePythonClassProfiles handlePythonClassProfiles) {
173+
@CachedLibrary(limit = "1") HashingStorageLibrary hlib) {
174+
return writeToDict(lib.getDict(object), key, value, updateStorage, hlib);
175+
}
176+
177+
@Specialization(guards = {"!isHiddenKey(key)", "lib.hasDict(klass)"}, limit = "1")
178+
static boolean writeToDictBuiltinType(PythonManagedClass klass, Object key, Object value,
179+
@Cached CastToJavaStringNode castToStrNode,
180+
@Cached BranchProfile isSpecialKey,
181+
@CachedLibrary("klass") PythonObjectLibrary lib,
182+
@Cached BranchProfile updateStorage,
183+
@CachedLibrary(limit = "1") HashingStorageLibrary hlib) {
184+
String strKey = castKey(castToStrNode, key);
151185
try {
152-
return writeToDict(lib.getDict(object), key, value, updateStorage, hlib);
186+
return writeToDict(lib.getDict(klass), strKey, value, updateStorage, hlib);
153187
} finally {
154-
handlePossiblePythonClass(handlePythonClassProfiles, object, key, value);
188+
klass.invalidateFinalAttribute(strKey);
189+
fixupSpecialMethodSlots(isSpecialKey, klass, strKey, value);
155190
}
156191
}
157192

@@ -277,46 +312,4 @@ private String castKey(Object keyObj) {
277312
return castKeyNode.execute(keyObj);
278313
}
279314
}
280-
281-
protected static final class HandlePythonClassProfiles extends Node {
282-
private static final HandlePythonClassProfiles UNCACHED = new HandlePythonClassProfiles(BranchProfile.getUncached(), BranchProfile.getUncached(), BranchProfile.getUncached(),
283-
CastToJavaStringNode.getUncached());
284-
final BranchProfile isManagedClass;
285-
final BranchProfile isUserClass;
286-
final BranchProfile isSpecialKey;
287-
@Child CastToJavaStringNode castKeyNode;
288-
289-
public HandlePythonClassProfiles(BranchProfile isManagedClass, BranchProfile isUserClass, BranchProfile isSpecialKey, CastToJavaStringNode castKeyNode) {
290-
this.isManagedClass = isManagedClass;
291-
this.isUserClass = isUserClass;
292-
this.isSpecialKey = isSpecialKey;
293-
this.castKeyNode = castKeyNode;
294-
}
295-
296-
public static HandlePythonClassProfiles create() {
297-
return new HandlePythonClassProfiles(BranchProfile.create(), BranchProfile.create(), BranchProfile.create(), null);
298-
}
299-
300-
public static HandlePythonClassProfiles getUncached() {
301-
return UNCACHED;
302-
}
303-
304-
String castKey(Object key) {
305-
if (castKeyNode == null) {
306-
// fast-path w/o node for two most common situations
307-
if (key instanceof String) {
308-
return (String) key;
309-
} else if (isHiddenKey(key)) {
310-
return null;
311-
}
312-
CompilerDirectives.transferToInterpreterAndInvalidate();
313-
castKeyNode = insert(CastToJavaStringNode.create());
314-
}
315-
try {
316-
return castKeyNode.execute(key);
317-
} catch (CannotCastException ex) {
318-
return null;
319-
}
320-
}
321-
}
322315
}

0 commit comments

Comments
 (0)