42
42
43
43
import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
44
44
import com .oracle .graal .python .builtins .objects .common .HashingCollectionNodes .SetItemNode ;
45
+ import com .oracle .graal .python .builtins .objects .common .HashingStorage ;
45
46
import com .oracle .graal .python .builtins .objects .common .LocalsStorage ;
46
47
import com .oracle .graal .python .builtins .objects .dict .PDict ;
47
48
import com .oracle .graal .python .builtins .objects .frame .PFrame ;
@@ -128,7 +129,7 @@ static PFrame freshPFrameInClassBody(VirtualFrame frame, Node location, boolean
128
129
static PFrame incompleteFrame (VirtualFrame frame , Node location , boolean markAsEscaped , @ SuppressWarnings ("unused" ) boolean forceSync , Frame frameToMaterialize ,
129
130
@ Shared ("factory" ) @ Cached PythonObjectFactory factory ,
130
131
@ Shared ("syncValuesNode" ) @ Cached SyncFrameValuesNode syncValuesNode ) {
131
- PDict locals = factory . createDictLocals (frameToMaterialize . getFrameDescriptor () );
132
+ Object locals = getPFrame (frameToMaterialize ). getLocalsDict ( );
132
133
PFrame escapedFrame = factory .createPFrame (PArguments .getCurrentFrameInfo (frameToMaterialize ), location , locals , inClassBody (frameToMaterialize ));
133
134
return doEscapeFrame (frame , frameToMaterialize , escapedFrame , markAsEscaped , forceSync , syncValuesNode );
134
135
}
@@ -206,12 +207,30 @@ protected static PFrame getPFrame(Frame frame) {
206
207
return PArguments .getCurrentFrameInfo (frame ).getPyFrame ();
207
208
}
208
209
210
+ /**
211
+ * When refreshing the frame values in the locals dict, there are 4 cases:
212
+ * <ol>
213
+ * <li>The locals object is a {@code dict} with a {@code LocalsStorage} having the same frame
214
+ * descriptor as the frame to synchronize. This then represents the unmodified set of frame
215
+ * variables and need to be refreshed.</li>
216
+ * <li>The locals object is a {@code dict} with a storage <b>different</b> to
217
+ * {@code LocalsStorage}. This may happen if someone retrieves the locals and manually assigns
218
+ * to the dict. Then the storage changes. In this case we must also refresh the frame
219
+ * values.</li>
220
+ * <li>The locals object is some arbitrary custom mapping object (excluding the above 2 cases).
221
+ * In this case, all code was already working on the custom object and we don't need to do
222
+ * anything.</li>
223
+ * <li>The locals object is a {@code dict} with a {@code LocalsStorage} having a different frame
224
+ * descriptor as the frame to synchronize. This is common when {@code exec} / {@code eval} and
225
+ * inheriting the locals of the caller. In this case, we don't need to do anything.</li>
226
+ * </ol>
227
+ */
209
228
@ ImportStatic (SpecialMethodNames .class )
210
229
public abstract static class SyncFrameValuesNode extends Node {
211
230
212
231
public abstract void execute (VirtualFrame frame , PFrame pyframe , Frame frameToSync );
213
232
214
- @ Specialization (guards = {"hasLocalsStorage(pyFrame)" , "frameToSync.getFrameDescriptor() == cachedFd" }, //
233
+ @ Specialization (guards = {"hasLocalsStorage(pyFrame, frameToSync )" , "frameToSync.getFrameDescriptor() == cachedFd" }, //
215
234
assumptions = "cachedFd.getVersion()" , //
216
235
limit = "1" )
217
236
@ ExplodeLoop
@@ -247,7 +266,7 @@ static void doLocalsStorageCached(PFrame pyFrame, Frame frameToSync,
247
266
}
248
267
}
249
268
250
- @ Specialization (guards = "hasLocalsStorage(pyFrame)" , replaces = "doLocalsStorageCached" )
269
+ @ Specialization (guards = "hasLocalsStorage(pyFrame, frameToSync )" , replaces = "doLocalsStorageCached" )
251
270
static void doLocalsStorageUncached (PFrame pyFrame , Frame frameToSync ) {
252
271
FrameDescriptor fd = frameToSync .getFrameDescriptor ();
253
272
FrameSlot [] cachedSlots = getSlots (fd );
@@ -324,7 +343,7 @@ static void doGenericDict(VirtualFrame frame, PFrame pyFrame, Frame frameToSync,
324
343
}
325
344
}
326
345
327
- @ Specialization (guards = "isCustomLocalsObject(pyFrame)" )
346
+ @ Specialization (guards = "isCustomLocalsObject(pyFrame, frameToSync )" )
328
347
@ SuppressWarnings ("unused" )
329
348
static void doCustomLocalsObject (PFrame pyFrame , Frame frameToSync ) {
330
349
// nothing to do; we already worked on the custom object
@@ -334,9 +353,14 @@ protected static FrameSlot[] getSlots(FrameDescriptor fd) {
334
353
return fd .getSlots ().toArray (new FrameSlot [0 ]);
335
354
}
336
355
337
- protected static boolean hasLocalsStorage (PFrame pyFrame ) {
356
+ /**
357
+ * Guard that tests if the locals object is a dict having a {@link LocalsStorage} using the
358
+ * same frame descriptor as the frame to synchronize. That means, the dict represents
359
+ * unmodified set of frame values of the frame to sync.
360
+ */
361
+ protected static boolean hasLocalsStorage (PFrame pyFrame , Frame frameToSync ) {
338
362
Object localsObject = pyFrame .getLocalsDict ();
339
- return localsObject instanceof PDict && (( PDict ) localsObject ).getDictStorage () instanceof LocalsStorage ;
363
+ return localsObject instanceof PDict && getFd ((( PDict ) localsObject ).getDictStorage ()) == frameToSync . getFrameDescriptor () ;
340
364
}
341
365
342
366
protected static boolean isDictWithCustomStorage (PFrame pyFrame ) {
@@ -345,12 +369,19 @@ protected static boolean isDictWithCustomStorage(PFrame pyFrame) {
345
369
return localsObject instanceof PDict && ((PDict ) localsObject ).getLazyPythonClass () == PythonBuiltinClassType .PDict ;
346
370
}
347
371
348
- protected static boolean isCustomLocalsObject (PFrame pyFrame ) {
349
- return !(pyFrame . getLocalsDict () instanceof PDict );
372
+ protected static boolean isCustomLocalsObject (PFrame pyFrame , Frame frameToSync ) {
373
+ return !hasLocalsStorage (pyFrame , frameToSync );
350
374
}
351
375
352
376
protected static LocalsStorage getLocalsStorage (PFrame pyFrame ) {
353
377
return (LocalsStorage ) ((PDict ) pyFrame .getLocalsDict ()).getDictStorage ();
354
378
}
379
+
380
+ private static FrameDescriptor getFd (HashingStorage storage ) {
381
+ if (storage instanceof LocalsStorage ) {
382
+ return ((LocalsStorage ) storage ).getFrame ().getFrameDescriptor ();
383
+ }
384
+ return null ;
385
+ }
355
386
}
356
387
}
0 commit comments