51
51
import com .oracle .graal .python .builtins .objects .function .PArguments ;
52
52
import com .oracle .graal .python .nodes .ModuleRootNode ;
53
53
import com .oracle .graal .python .nodes .SpecialMethodNames ;
54
+ import com .oracle .graal .python .nodes .attributes .LookupInheritedAttributeNode ;
55
+ import com .oracle .graal .python .nodes .call .CallNode ;
56
+ import com .oracle .graal .python .nodes .frame .MaterializeFrameNodeGen .SyncFrameValuesNodeGen ;
54
57
import com .oracle .graal .python .nodes .function .ClassBodyRootNode ;
55
58
import com .oracle .graal .python .runtime .object .PythonObjectFactory ;
56
59
import com .oracle .truffle .api .dsl .Cached ;
73
76
**/
74
77
public abstract class MaterializeFrameNode extends Node {
75
78
79
+ private final boolean adoptable ;
80
+ private static final MaterializeFrameNode INSTANCE = MaterializeFrameNodeGen .create (false );
81
+
82
+ public MaterializeFrameNode () {
83
+ this .adoptable = true ;
84
+ }
85
+
86
+ protected MaterializeFrameNode (boolean adoptable ) {
87
+ this .adoptable = adoptable ;
88
+ }
89
+
76
90
public final PFrame execute (VirtualFrame frame , boolean markAsEscaped , Frame frameToMaterialize ) {
77
91
return execute (frame , markAsEscaped , false , frameToMaterialize );
78
92
}
@@ -96,7 +110,7 @@ public final PFrame execute(VirtualFrame frame, Node location, boolean markAsEsc
96
110
97
111
@ Specialization (guards = {"getPFrame(frameToMaterialize) == null" , "isGeneratorFrame(frameToMaterialize)" })
98
112
static PFrame freshPFrameForGenerator (Node location , @ SuppressWarnings ("unused" ) boolean markAsEscaped , @ SuppressWarnings ("unused" ) boolean forceSync , Frame frameToMaterialize ,
99
- @ Shared ("factory" ) @ Cached PythonObjectFactory factory ) {
113
+ @ Shared ("factory" ) @ Cached ( "createFactory()" ) PythonObjectFactory factory ) {
100
114
PFrame escapedFrame = factory .createPFrame (PArguments .getCurrentFrameInfo (frameToMaterialize ), location , PArguments .getGeneratorFrameLocals (frameToMaterialize ), false );
101
115
syncArgs (frameToMaterialize , escapedFrame );
102
116
PFrame .Reference topFrameRef = PArguments .getCurrentFrameInfo (frameToMaterialize );
@@ -106,17 +120,17 @@ static PFrame freshPFrameForGenerator(Node location, @SuppressWarnings("unused")
106
120
107
121
@ Specialization (guards = {"getPFrame(frameToMaterialize) == null" , "!inClassBody(frameToMaterialize)" , "!isGeneratorFrame(frameToMaterialize)" })
108
122
static PFrame freshPFrame (VirtualFrame frame , Node location , boolean markAsEscaped , @ SuppressWarnings ("unused" ) boolean forceSync , Frame frameToMaterialize ,
109
- @ Shared ("factory" ) @ Cached PythonObjectFactory factory ,
110
- @ Shared ("syncValuesNode" ) @ Cached SyncFrameValuesNode syncValuesNode ) {
123
+ @ Shared ("factory" ) @ Cached ( "createFactory()" ) PythonObjectFactory factory ,
124
+ @ Shared ("syncValuesNode" ) @ Cached ( "createSyncNode()" ) SyncFrameValuesNode syncValuesNode ) {
111
125
PDict locals = factory .createDictLocals (frameToMaterialize .getFrameDescriptor ());
112
126
PFrame escapedFrame = factory .createPFrame (PArguments .getCurrentFrameInfo (frameToMaterialize ), location , locals , false );
113
127
return doEscapeFrame (frame , frameToMaterialize , escapedFrame , markAsEscaped , forceSync && !inModuleRoot (location ), syncValuesNode );
114
128
}
115
129
116
130
@ Specialization (guards = {"getPFrame(frameToMaterialize) == null" , "inClassBody(frameToMaterialize)" })
117
131
static PFrame freshPFrameInClassBody (VirtualFrame frame , Node location , boolean markAsEscaped , @ SuppressWarnings ("unused" ) boolean forceSync , Frame frameToMaterialize ,
118
- @ Shared ("factory" ) @ Cached PythonObjectFactory factory ,
119
- @ Shared ("syncValuesNode" ) @ Cached SyncFrameValuesNode syncValuesNode ) {
132
+ @ Shared ("factory" ) @ Cached ( "createFactory()" ) PythonObjectFactory factory ,
133
+ @ Shared ("syncValuesNode" ) @ Cached ( "createSyncNode()" ) SyncFrameValuesNode syncValuesNode ) {
120
134
// the namespace argument stores the locals
121
135
PFrame escapedFrame = factory .createPFrame (PArguments .getCurrentFrameInfo (frameToMaterialize ), location , PArguments .getArgument (frameToMaterialize , 0 ), true );
122
136
// The locals dict in a class body is always custom; we must not write the values from the
@@ -133,16 +147,16 @@ static PFrame freshPFrameInClassBody(VirtualFrame frame, Node location, boolean
133
147
**/
134
148
@ Specialization (guards = {"getPFrame(frameToMaterialize) != null" , "!getPFrame(frameToMaterialize).hasFrame()" })
135
149
static PFrame incompleteFrame (VirtualFrame frame , Node location , boolean markAsEscaped , boolean forceSync , Frame frameToMaterialize ,
136
- @ Shared ("factory" ) @ Cached PythonObjectFactory factory ,
137
- @ Shared ("syncValuesNode" ) @ Cached SyncFrameValuesNode syncValuesNode ) {
150
+ @ Shared ("factory" ) @ Cached ( "createFactory()" ) PythonObjectFactory factory ,
151
+ @ Shared ("syncValuesNode" ) @ Cached ( "createSyncNode()" ) SyncFrameValuesNode syncValuesNode ) {
138
152
Object locals = getPFrame (frameToMaterialize ).getLocalsDict ();
139
153
PFrame escapedFrame = factory .createPFrame (PArguments .getCurrentFrameInfo (frameToMaterialize ), location , locals , inClassBody (frameToMaterialize ));
140
154
return doEscapeFrame (frame , frameToMaterialize , escapedFrame , markAsEscaped , forceSync && !inModuleRoot (location ), syncValuesNode );
141
155
}
142
156
143
157
@ Specialization (guards = {"getPFrame(frameToMaterialize) != null" , "getPFrame(frameToMaterialize).hasFrame()" }, replaces = "freshPFrame" )
144
158
static PFrame alreadyEscapedFrame (VirtualFrame frame , Node location , boolean markAsEscaped , boolean forceSync , Frame frameToMaterialize ,
145
- @ Shared ("syncValuesNode" ) @ Cached SyncFrameValuesNode syncValuesNode ,
159
+ @ Shared ("syncValuesNode" ) @ Cached ( "createSyncNode()" ) SyncFrameValuesNode syncValuesNode ,
146
160
@ Cached ("createBinaryProfile()" ) ConditionProfile syncProfile ) {
147
161
PFrame pyFrame = getPFrame (frameToMaterialize );
148
162
if (syncProfile .profile (forceSync && !inClassBody (frameToMaterialize ) && !inModuleRoot (location ))) {
@@ -158,8 +172,8 @@ static PFrame alreadyEscapedFrame(VirtualFrame frame, Node location, boolean mar
158
172
159
173
@ Specialization (replaces = {"freshPFrame" , "alreadyEscapedFrame" })
160
174
static PFrame notInClassBody (VirtualFrame frame , Node location , boolean markAsEscaped , boolean forceSync , Frame frameToMaterialize ,
161
- @ Shared ("factory" ) @ Cached PythonObjectFactory factory ,
162
- @ Shared ("syncValuesNode" ) @ Cached SyncFrameValuesNode syncValuesNode ,
175
+ @ Shared ("factory" ) @ Cached ( "createFactory()" ) PythonObjectFactory factory ,
176
+ @ Shared ("syncValuesNode" ) @ Cached ( "createSyncNode()" ) SyncFrameValuesNode syncValuesNode ,
163
177
@ Cached ("createBinaryProfile()" ) ConditionProfile syncProfile ) {
164
178
if (getPFrame (frameToMaterialize ) != null ) {
165
179
return alreadyEscapedFrame (frame , location , markAsEscaped , forceSync , frameToMaterialize , syncValuesNode , syncProfile );
@@ -220,6 +234,26 @@ protected static boolean inModuleRoot(Node location) {
220
234
return location .getRootNode () instanceof ModuleRootNode ;
221
235
}
222
236
237
+ protected final SyncFrameValuesNode createSyncNode () {
238
+ return SyncFrameValuesNodeGen .create (isAdoptable ());
239
+ }
240
+
241
+ protected final PythonObjectFactory createFactory () {
242
+ if (isAdoptable ()) {
243
+ return PythonObjectFactory .create ();
244
+ }
245
+ return PythonObjectFactory .getUncached ();
246
+ }
247
+
248
+ @ Override
249
+ public boolean isAdoptable () {
250
+ return adoptable ;
251
+ }
252
+
253
+ public static MaterializeFrameNode getUnadoptable () {
254
+ return INSTANCE ;
255
+ }
256
+
223
257
/**
224
258
* When refreshing the frame values in the locals dict, there are 4 cases:
225
259
* <ol>
@@ -241,6 +275,12 @@ protected static boolean inModuleRoot(Node location) {
241
275
@ ImportStatic (SpecialMethodNames .class )
242
276
public abstract static class SyncFrameValuesNode extends Node {
243
277
278
+ private final boolean adoptable ;
279
+
280
+ public SyncFrameValuesNode (boolean adoptable ) {
281
+ this .adoptable = adoptable ;
282
+ }
283
+
244
284
public abstract void execute (VirtualFrame frame , PFrame pyframe , Frame frameToSync );
245
285
246
286
@ Specialization (guards = {"hasLocalsStorage(pyFrame, frameToSync)" , "frameToSync.getFrameDescriptor() == cachedFd" }, //
@@ -315,11 +355,11 @@ static void doLocalsStorageUncached(PFrame pyFrame, Frame frameToSync) {
315
355
}
316
356
}
317
357
318
- @ Specialization (guards = {"isDictWithCustomStorage(pyFrame)" , "frameToSync.getFrameDescriptor() == cachedFd" }, //
358
+ @ Specialization (guards = {"isDictWithCustomStorage(pyFrame)" , "frameToSync.getFrameDescriptor() == cachedFd" , "isAdoptable()" }, //
319
359
assumptions = "cachedFd.getVersion()" , //
320
360
limit = "1" )
321
361
@ ExplodeLoop
322
- static void doGenericDictCached (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
362
+ static void doGenericDictAdoptableCached (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
323
363
@ Cached ("frameToSync.getFrameDescriptor()" ) @ SuppressWarnings ("unused" ) FrameDescriptor cachedFd ,
324
364
@ Cached (value = "getSlots(cachedFd)" , dimensions = 1 ) FrameSlot [] cachedSlots ,
325
365
@ Cached (value = "getProfiles(cachedSlots.length)" , dimensions = 1 ) ConditionProfile [] profiles ,
@@ -346,8 +386,8 @@ static void doGenericDictCached(VirtualFrame frame, PFrame pyFrame, Frame frameT
346
386
}
347
387
}
348
388
349
- @ Specialization (guards = "isDictWithCustomStorage(pyFrame)" , replaces = "doGenericDictCached " )
350
- static void doGenericDict (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
389
+ @ Specialization (guards = { "isDictWithCustomStorage(pyFrame)" , "isAdoptable()" }, replaces = "doGenericDictAdoptableCached " )
390
+ static void doGenericDictAdoptable (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
351
391
@ Cached HashingCollectionNodes .SetItemNode setItemNode ,
352
392
@ Cached HashingStorageNodes .DelItemNode deleteItemNode ) {
353
393
// This can happen if someone received the locals dict using 'locals()' or similar and
@@ -373,6 +413,34 @@ static void doGenericDict(VirtualFrame frame, PFrame pyFrame, Frame frameToSync,
373
413
}
374
414
}
375
415
416
+ @ Specialization (guards = {"isDictWithCustomStorage(pyFrame)" , "!isAdoptable()" })
417
+ static void doGenericDict (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ) {
418
+ // Same as 'doGenericDictAdoptable' but uses a full call node to call '__setitem__' and
419
+ // '__delitem__' since this node is not adoptable.
420
+
421
+ FrameDescriptor fd = frameToSync .getFrameDescriptor ();
422
+ FrameSlot [] slots = getSlots (fd );
423
+ // The cast is guaranteed by the guard.
424
+ PDict localsDict = (PDict ) pyFrame .getLocalsDict ();
425
+
426
+ // we need to use nodes where we are sure that they may not be adopted
427
+ Object setItemMethod = LookupInheritedAttributeNode .Dynamic .getUncached ().execute (localsDict , SpecialMethodNames .__SETITEM__ );
428
+ Object deleteItemMethod = LookupInheritedAttributeNode .Dynamic .getUncached ().execute (localsDict , SpecialMethodNames .__DELITEM__ );
429
+
430
+ for (int i = 0 ; i < slots .length ; i ++) {
431
+ FrameSlot slot = slots [i ];
432
+ if (FrameSlotIDs .isUserFrameSlot (slot .getIdentifier ())) {
433
+ Object value = frameToSync .getValue (slot );
434
+ if (value != null ) {
435
+ CallNode .getUncached ().execute (frame , setItemMethod , localsDict , slot .getIdentifier (), resolveCellValue (ConditionProfile .getUncached (), value ));
436
+ } else {
437
+ // delete variable
438
+ CallNode .getUncached ().execute (frame , deleteItemMethod , localsDict , slot .getIdentifier ());
439
+ }
440
+ }
441
+ }
442
+ }
443
+
376
444
@ Specialization (guards = "isCustomLocalsObject(pyFrame, frameToSync)" )
377
445
@ SuppressWarnings ("unused" )
378
446
static void doCustomLocalsObject (PFrame pyFrame , Frame frameToSync ) {
@@ -428,5 +496,11 @@ private static Object resolveCellValue(ConditionProfile profile, Object value) {
428
496
}
429
497
return value ;
430
498
}
499
+
500
+ @ Override
501
+ public boolean isAdoptable () {
502
+ return adoptable ;
503
+ }
431
504
}
505
+
432
506
}
0 commit comments