43
43
import com .oracle .graal .python .PythonLanguage ;
44
44
import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
45
45
import com .oracle .graal .python .builtins .objects .PNone ;
46
+ import com .oracle .graal .python .builtins .objects .object .PythonObjectLibrary ;
46
47
import com .oracle .graal .python .builtins .objects .type .PythonClass ;
47
48
import com .oracle .graal .python .builtins .objects .type .TypeNodes ;
48
49
import com .oracle .graal .python .builtins .objects .type .TypeNodes .GetMroStorageNode ;
63
64
import com .oracle .truffle .api .dsl .ImportStatic ;
64
65
import com .oracle .truffle .api .dsl .ReportPolymorphism ;
65
66
import com .oracle .truffle .api .dsl .Specialization ;
67
+ import com .oracle .truffle .api .library .CachedLibrary ;
66
68
import com .oracle .truffle .api .nodes .ExplodeLoop ;
67
69
68
70
@ ImportStatic (PythonOptions .class )
@@ -190,17 +192,17 @@ protected Object lookupPBCTGeneric(PythonBuiltinClassType klass,
190
192
return findAttr (getCore (), klass , key , readAttrNode );
191
193
}
192
194
193
- static final class PythonClassAssumptionPair {
195
+ static final class AttributeAssumptionPair {
194
196
public final Assumption assumption ;
195
197
public final Object value ;
196
198
197
- PythonClassAssumptionPair (Assumption assumption , Object value ) {
199
+ AttributeAssumptionPair (Assumption assumption , Object value ) {
198
200
this .assumption = assumption ;
199
201
this .value = value ;
200
202
}
201
203
}
202
204
203
- protected PythonClassAssumptionPair findAttrClassAndAssumptionInMRO (Object klass ) {
205
+ protected AttributeAssumptionPair findAttrAndAssumptionInMRO (Object klass ) {
204
206
CompilerAsserts .neverPartOfCompilation ();
205
207
MroSequenceStorage mro = getMro (klass );
206
208
Assumption attrAssumption = mro .createAttributeInMROFinalAssumption (key );
@@ -215,19 +217,24 @@ protected PythonClassAssumptionPair findAttrClassAndAssumptionInMRO(Object klass
215
217
}
216
218
Object value = ReadAttributeFromObjectNode .getUncachedForceType ().execute (clsObj , key );
217
219
if (value != PNone .NO_VALUE ) {
218
- return new PythonClassAssumptionPair (attrAssumption , value );
220
+ return new AttributeAssumptionPair (attrAssumption , value );
219
221
}
220
222
}
221
- return new PythonClassAssumptionPair (attrAssumption , PNone .NO_VALUE );
223
+ return new AttributeAssumptionPair (attrAssumption , PNone .NO_VALUE );
222
224
}
223
225
224
- @ Specialization (guards = {"isSameType(cachedKlass, klass)" , "cachedClassInMROInfo != null" }, //
226
+ /**
227
+ * NOTE: Guard for case when attributes stored in a dict. Calling __eq__ or __hash__ on such
228
+ * could have mro related sideeffects.
229
+ */
230
+ @ Specialization (guards = {"!lib.hasDict(klass)" , "isSameType(cachedKlass, klass)" , "cachedAttrInMROInfo != null" }, //
225
231
limit = "getAttributeAccessInlineCacheMaxDepth()" , //
226
- assumptions = {"cachedClassInMROInfo .assumption" , "singleContextAssumption()" })
232
+ assumptions = {"cachedAttrInMROInfo .assumption" , "singleContextAssumption()" })
227
233
protected static Object lookupConstantMROCached (@ SuppressWarnings ("unused" ) Object klass ,
228
234
@ Cached ("klass" ) @ SuppressWarnings ("unused" ) Object cachedKlass ,
229
- @ Cached ("findAttrClassAndAssumptionInMRO(cachedKlass)" ) PythonClassAssumptionPair cachedClassInMROInfo ) {
230
- return cachedClassInMROInfo .value ;
235
+ @ CachedLibrary ("klass" ) @ SuppressWarnings ("unused" ) PythonObjectLibrary lib ,
236
+ @ Cached ("findAttrAndAssumptionInMRO(cachedKlass)" ) AttributeAssumptionPair cachedAttrInMROInfo ) {
237
+ return cachedAttrInMROInfo .value ;
231
238
}
232
239
233
240
protected static ReadAttributeFromObjectNode [] create (int size ) {
@@ -248,8 +255,14 @@ protected Object lookupConstantMRO(@SuppressWarnings("unused") Object klass,
248
255
@ Cached ("mro.getLookupStableAssumption()" ) @ SuppressWarnings ("unused" ) Assumption lookupStable ,
249
256
@ Cached ("mro.length()" ) int mroLength ,
250
257
@ Cached ("create(mroLength)" ) ReadAttributeFromObjectNode [] readAttrNodes ) {
251
- for (int i = 0 ; i < mroLength ; i ++) {
252
- Object kls = mro .getItemNormalized (i );
258
+ // create snapshot, mro storage can change during lookup
259
+ Object [] mroArray = new Object [mroLength ];
260
+ for (int i = 0 ; i < mroArray .length ; i ++) {
261
+ mroArray [i ] = mro .getItemNormalized (i );
262
+ }
263
+
264
+ for (int i = 0 ; i < mroArray .length ; i ++) {
265
+ Object kls = mroArray [i ];
253
266
if (skipPythonClasses && kls instanceof PythonClass ) {
254
267
continue ;
255
268
}
@@ -281,16 +294,21 @@ protected MroSequenceStorage getMro(Object clazz) {
281
294
282
295
public static Object lookupSlow (Object klass , Object key , GetMroStorageNode getMroNode , ReadAttributeFromObjectNode readAttrNode , boolean skipPythonClasses ) {
283
296
MroSequenceStorage mro = getMroNode .execute (klass );
284
- for (int i = 0 ; i < mro .length (); i ++) {
285
- Object kls = mro .getItemNormalized (i );
286
- if (skipPythonClasses && kls instanceof PythonClass ) {
287
- continue ;
288
- }
289
- Object value = readAttrNode .execute (kls , key );
290
- if (value != PNone .NO_VALUE ) {
291
- return value ;
292
- }
293
- }
297
+ // create snapshot, mro storage could change during lookup
298
+ Object [] mroArray = new Object [mro .length ()];
299
+ for (int i = 0 ; i < mroArray .length ; i ++) {
300
+ mroArray [i ] = mro .getItemNormalized (i );
301
+ }
302
+ for (int i = 0 ; i < mroArray .length ; i ++) {
303
+ Object kls = mroArray [i ];
304
+ if (skipPythonClasses && kls instanceof PythonClass ) {
305
+ continue ;
306
+ }
307
+ Object value = readAttrNode .execute (kls , key );
308
+ if (value != PNone .NO_VALUE ) {
309
+ return value ;
310
+ }
311
+ }
294
312
return PNone .NO_VALUE ;
295
313
}
296
314
0 commit comments