5050import com .oracle .graal .python .builtins .objects .dict .PDict ;
5151import com .oracle .graal .python .builtins .objects .object .PythonObject ;
5252import 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 ;
5355import com .oracle .graal .python .builtins .objects .type .PythonManagedClass ;
5456import com .oracle .graal .python .builtins .objects .type .SpecialMethodSlot ;
5557import com .oracle .graal .python .builtins .objects .type .TypeNodes .IsTypeNode ;
7072import com .oracle .truffle .api .dsl .ImportStatic ;
7173import com .oracle .truffle .api .dsl .Specialization ;
7274import com .oracle .truffle .api .library .CachedLibrary ;
73- import com .oracle .truffle .api .nodes . Node ;
75+ import com .oracle .truffle .api .object . HiddenKey ;
7476import com .oracle .truffle .api .profiles .BranchProfile ;
7577
7678@ ImportStatic (PythonOptions .class )
7779public 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