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 .DynamicObjectLibrary ;
76+ import com .oracle .truffle .api .object .HiddenKey ;
7477import com .oracle .truffle .api .profiles .BranchProfile ;
7578
7679@ ImportStatic (PythonOptions .class )
7780public abstract class WriteAttributeToObjectNode extends ObjectAttributeNode {
7881
7982 public abstract boolean execute (Object primary , Object key , Object value );
8083
84+ public abstract boolean execute (Object primary , HiddenKey key , Object value );
85+
8186 public static WriteAttributeToObjectNode create () {
8287 return WriteAttributeToObjectNotTypeNodeGen .create ();
8388 }
@@ -97,61 +102,97 @@ protected static boolean isAttrWritable(PythonObject self, Object key) {
97102 return (self .getShape ().getFlags () & PythonObject .HAS_SLOTS_BUT_NO_DICT_FLAG ) == 0 ;
98103 }
99104
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 );
105+ private static String castKey (CastToJavaStringNode castNode , Object value ) {
106+ try {
107+ return castNode .execute (value );
108+ } catch (CannotCastException ex ) {
109+ throw CompilerDirectives .shouldNotReachHere (ex );
104110 }
105111 }
106112
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)
116- if (SpecialMethodSlot .canBeSpecial (key )) {
117- profiles .isSpecialKey .enter ();
118- SpecialMethodSlot slot = SpecialMethodSlot .findSpecialSlot (key );
119- if (slot != null ) {
120- SpecialMethodSlot .fixupSpecialMethodSlot (object , slot , value );
113+ @ Specialization (guards = "isAttrWritable(object, key)" , limit = "getAttributeAccessInlineCacheMaxDepth()" )
114+ static boolean writeHiddenKeyToDynamicStorage (PythonObject object , HiddenKey key , Object value ,
115+ @ CachedLibrary ("object.getStorage()" ) DynamicObjectLibrary dylib ) {
116+ // HiddenKeys are always written to the storage and do not have any other special handling
117+ dylib .put (object .getStorage (), key , value );
118+ return true ;
119+ }
120+
121+ @ Specialization (guards = {"!isHiddenKey(key)" , "!lib.hasDict(object)" , "isAttrWritable(object, key)" , "!isManagedClass(object)" }, limit = "1" )
122+ static boolean writeToDynamicStorageNoType (PythonObject object , Object key , Object value ,
123+ @ Cached CastToJavaStringNode castToStrNode ,
124+ @ CachedLibrary ("object" ) @ SuppressWarnings ("unused" ) PythonObjectLibrary lib ,
125+ @ CachedLibrary (limit = "getAttributeAccessInlineCacheMaxDepth()" ) DynamicObjectLibrary dylib ) {
126+ // Objects w/o dict that are not classes do not have any special handling
127+ String strKey = castKey (castToStrNode , key );
128+ dylib .put (object .getStorage (), strKey , value );
129+ return true ;
130+ }
131+
132+ @ Specialization (guards = {"!isHiddenKey(key)" , "!lib.hasDict(klass)" , "isAttrWritable(klass, key)" }, limit = "1" )
133+ static boolean writeToDynamicStorageBuiltinType (PythonBuiltinClass klass , Object key , Object value ,
134+ @ CachedLibrary ("klass" ) @ SuppressWarnings ("unused" ) PythonObjectLibrary lib ,
135+ @ Cached CastToJavaStringNode castToStrNode ,
136+ @ Cached BranchProfile callAttrUpdate ,
137+ @ CachedLibrary (limit = "getAttributeAccessInlineCacheMaxDepth()" ) DynamicObjectLibrary dylib ) {
138+ String strKey = castKey (castToStrNode , key );
139+ try {
140+ dylib .put (klass , strKey , value );
141+ return true ;
142+ } finally {
143+ if (!klass .canSkipOnAttributeUpdate (strKey , value )) {
144+ callAttrUpdate .enter ();
145+ klass .onAttributeUpdate (strKey , value );
121146 }
122147 }
123148 }
124149
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 ,
131- @ CachedLibrary ("object" ) @ SuppressWarnings ("unused" ) PythonObjectLibrary lib ,
132- @ Cached WriteAttributeToDynamicObjectNode writeAttributeToDynamicObjectNode ,
133- @ Exclusive @ Cached HandlePythonClassProfiles handlePythonClassProfiles ) {
150+ static boolean [] createFlag () {
151+ return new boolean [1 ];
152+ }
153+
154+ @ Specialization (guards = {"!isHiddenKey(key)" , "!lib.hasDict(klass)" , "isAttrWritable(klass, key)" }, limit = "1" )
155+ static boolean writeToDynamicStoragePythonClass (PythonClass klass , Object key , Object value ,
156+ @ CachedLibrary ("klass" ) @ SuppressWarnings ("unused" ) PythonObjectLibrary lib ,
157+ @ Cached CastToJavaStringNode castToStrNode ,
158+ @ Cached BranchProfile callAttrUpdate ,
159+ @ CachedLibrary (limit = "getAttributeAccessInlineCacheMaxDepth()" ) DynamicObjectLibrary dylib ) {
160+ String strKey = castKey (castToStrNode , key );
134161 try {
135- return writeAttributeToDynamicObjectNode .execute (object .getStorage (), key , value );
162+ dylib .put (klass , strKey , value );
163+ return true ;
136164 } finally {
137- handlePossiblePythonClass (handlePythonClassProfiles , object , key , value );
165+ if (!klass .canSkipOnAttributeUpdate (strKey , value )) {
166+ callAttrUpdate .enter ();
167+ klass .onAttributeUpdate (strKey , value );
168+ }
138169 }
139170 }
140171
141172 // 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 ,
173+ @ Specialization (guards = {"!isHiddenKey(key)" , "lib.hasDict(object)" , "!isManagedClass(object)" }, limit = "1" )
174+ static boolean writeToDictNoType (PythonObject object , Object key , Object value ,
147175 @ CachedLibrary ("object" ) PythonObjectLibrary lib ,
148176 @ Cached BranchProfile updateStorage ,
149- @ CachedLibrary (limit = "1" ) HashingStorageLibrary hlib ,
150- @ Exclusive @ Cached HandlePythonClassProfiles handlePythonClassProfiles ) {
177+ @ CachedLibrary (limit = "1" ) HashingStorageLibrary hlib ) {
178+ return writeToDict (lib .getDict (object ), key , value , updateStorage , hlib );
179+ }
180+
181+ @ Specialization (guards = {"!isHiddenKey(key)" , "lib.hasDict(klass)" }, limit = "1" )
182+ static boolean writeToDictBuiltinType (PythonManagedClass klass , Object key , Object value ,
183+ @ Cached CastToJavaStringNode castToStrNode ,
184+ @ Cached BranchProfile callAttrUpdate ,
185+ @ CachedLibrary ("klass" ) PythonObjectLibrary lib ,
186+ @ Cached BranchProfile updateStorage ,
187+ @ CachedLibrary (limit = "1" ) HashingStorageLibrary hlib ) {
188+ String strKey = castKey (castToStrNode , key );
151189 try {
152- return writeToDict (lib .getDict (object ), key , value , updateStorage , hlib );
190+ return writeToDict (lib .getDict (klass ), strKey , value , updateStorage , hlib );
153191 } finally {
154- handlePossiblePythonClass (handlePythonClassProfiles , object , key , value );
192+ if (!klass .canSkipOnAttributeUpdate (strKey , value )) {
193+ callAttrUpdate .enter ();
194+ klass .onAttributeUpdate (strKey , value );
195+ }
155196 }
156197 }
157198
@@ -277,46 +318,4 @@ private String castKey(Object keyObj) {
277318 return castKeyNode .execute (keyObj );
278319 }
279320 }
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- }
322321}
0 commit comments