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 ;
59
+ import com .oracle .truffle .api .CompilerDirectives ;
56
60
import com .oracle .truffle .api .dsl .Cached ;
57
61
import com .oracle .truffle .api .dsl .Cached .Shared ;
58
62
import com .oracle .truffle .api .dsl .ImportStatic ;
73
77
**/
74
78
public abstract class MaterializeFrameNode extends Node {
75
79
80
+ private final boolean adoptible ;
81
+
82
+ public MaterializeFrameNode () {
83
+ this .adoptible = true ;
84
+ }
85
+
86
+ public MaterializeFrameNode (boolean adoptible ) {
87
+ this .adoptible = adoptible ;
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,17 @@ protected static boolean inModuleRoot(Node location) {
220
234
return location .getRootNode () instanceof ModuleRootNode ;
221
235
}
222
236
237
+ protected SyncFrameValuesNode createSyncNode () {
238
+ return SyncFrameValuesNodeGen .create (adoptible );
239
+ }
240
+
241
+ protected PythonObjectFactory createFactory () {
242
+ if (adoptible ) {
243
+ return PythonObjectFactory .create ();
244
+ }
245
+ return PythonObjectFactory .getUncached ();
246
+ }
247
+
223
248
/**
224
249
* When refreshing the frame values in the locals dict, there are 4 cases:
225
250
* <ol>
@@ -241,6 +266,12 @@ protected static boolean inModuleRoot(Node location) {
241
266
@ ImportStatic (SpecialMethodNames .class )
242
267
public abstract static class SyncFrameValuesNode extends Node {
243
268
269
+ private final boolean adoptable ;
270
+
271
+ public SyncFrameValuesNode (boolean adoptable ) {
272
+ this .adoptable = adoptable ;
273
+ }
274
+
244
275
public abstract void execute (VirtualFrame frame , PFrame pyframe , Frame frameToSync );
245
276
246
277
@ Specialization (guards = {"hasLocalsStorage(pyFrame, frameToSync)" , "frameToSync.getFrameDescriptor() == cachedFd" }, //
@@ -315,11 +346,11 @@ static void doLocalsStorageUncached(PFrame pyFrame, Frame frameToSync) {
315
346
}
316
347
}
317
348
318
- @ Specialization (guards = {"isDictWithCustomStorage(pyFrame)" , "frameToSync.getFrameDescriptor() == cachedFd" }, //
349
+ @ Specialization (guards = {"isDictWithCustomStorage(pyFrame)" , "frameToSync.getFrameDescriptor() == cachedFd" , "isAdoptable()" }, //
319
350
assumptions = "cachedFd.getVersion()" , //
320
351
limit = "1" )
321
352
@ ExplodeLoop
322
- static void doGenericDictCached (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
353
+ static void doGenericDictAdoptableCached (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
323
354
@ Cached ("frameToSync.getFrameDescriptor()" ) @ SuppressWarnings ("unused" ) FrameDescriptor cachedFd ,
324
355
@ Cached (value = "getSlots(cachedFd)" , dimensions = 1 ) FrameSlot [] cachedSlots ,
325
356
@ Cached (value = "getProfiles(cachedSlots.length)" , dimensions = 1 ) ConditionProfile [] profiles ,
@@ -346,8 +377,8 @@ static void doGenericDictCached(VirtualFrame frame, PFrame pyFrame, Frame frameT
346
377
}
347
378
}
348
379
349
- @ Specialization (guards = "isDictWithCustomStorage(pyFrame)" , replaces = "doGenericDictCached " )
350
- static void doGenericDict (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
380
+ @ Specialization (guards = { "isDictWithCustomStorage(pyFrame)" , "isAdoptable()" }, replaces = "doGenericDictAdoptableCached " )
381
+ static void doGenericDictAdoptable (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ,
351
382
@ Cached HashingCollectionNodes .SetItemNode setItemNode ,
352
383
@ Cached HashingStorageNodes .DelItemNode deleteItemNode ) {
353
384
// This can happen if someone received the locals dict using 'locals()' or similar and
@@ -373,6 +404,34 @@ static void doGenericDict(VirtualFrame frame, PFrame pyFrame, Frame frameToSync,
373
404
}
374
405
}
375
406
407
+ @ Specialization (guards = {"isDictWithCustomStorage(pyFrame)" , "!isAdoptable()" })
408
+ static void doGenericDict (VirtualFrame frame , PFrame pyFrame , Frame frameToSync ) {
409
+ // Same as 'doGenericDictAdoptable' but uses a full call node to call '__setitem__' and
410
+ // '__delitem__' since this node is not adoptable.
411
+
412
+ FrameDescriptor fd = frameToSync .getFrameDescriptor ();
413
+ FrameSlot [] slots = getSlots (fd );
414
+ // The cast is guaranteed by the guard.
415
+ PDict localsDict = (PDict ) pyFrame .getLocalsDict ();
416
+
417
+ // we need to use nodes where we are sure that they may not be adopted
418
+ Object setItemMethod = LookupInheritedAttributeNode .Dynamic .getUncached ().execute (localsDict , SpecialMethodNames .__SETITEM__ );
419
+ Object deleteItemMethod = LookupInheritedAttributeNode .Dynamic .getUncached ().execute (localsDict , SpecialMethodNames .__DELITEM__ );
420
+
421
+ for (int i = 0 ; i < slots .length ; i ++) {
422
+ FrameSlot slot = slots [i ];
423
+ if (FrameSlotIDs .isUserFrameSlot (slot .getIdentifier ())) {
424
+ Object value = frameToSync .getValue (slot );
425
+ if (value != null ) {
426
+ CallNode .getUncached ().execute (frame , setItemMethod , localsDict , slot .getIdentifier (), resolveCellValue (ConditionProfile .getUncached (), value ));
427
+ } else {
428
+ // delete variable
429
+ CallNode .getUncached ().execute (frame , deleteItemMethod , localsDict , slot .getIdentifier ());
430
+ }
431
+ }
432
+ }
433
+ }
434
+
376
435
@ Specialization (guards = "isCustomLocalsObject(pyFrame, frameToSync)" )
377
436
@ SuppressWarnings ("unused" )
378
437
static void doCustomLocalsObject (PFrame pyFrame , Frame frameToSync ) {
@@ -428,5 +487,60 @@ private static Object resolveCellValue(ConditionProfile profile, Object value) {
428
487
}
429
488
return value ;
430
489
}
490
+
491
+ @ Override
492
+ public boolean isAdoptable () {
493
+ return adoptable ;
494
+ }
495
+ }
496
+
497
+ public static final class MaterializeFrameUnadoptibleNode extends Node {
498
+
499
+ private static final MaterializeFrameUnadoptibleNode INSTANCE = new MaterializeFrameUnadoptibleNode ();
500
+
501
+ // deliberately not annotated with '@Child'
502
+ private MaterializeFrameNode materializeFrameNode ;
503
+
504
+ public final PFrame execute (VirtualFrame frame , boolean markAsEscaped , Frame frameToMaterialize ) {
505
+ return execute (frame , markAsEscaped , false , frameToMaterialize );
506
+ }
507
+
508
+ public final PFrame execute (VirtualFrame frame , boolean markAsEscaped , boolean forceSync , Frame frameToMaterialize ) {
509
+ PFrame .Reference info = PArguments .getCurrentFrameInfo (frameToMaterialize );
510
+ assert info != null && info .getCallNode () != null : "cannot materialize a frame without location information" ;
511
+ Node callNode = info .getCallNode ();
512
+ return execute (frame , callNode , markAsEscaped , forceSync , frameToMaterialize );
513
+ }
514
+
515
+ public final PFrame execute (VirtualFrame frame , boolean markAsEscaped ) {
516
+ return execute (frame , markAsEscaped , frame );
517
+ }
518
+
519
+ public final PFrame execute (VirtualFrame frame , Node location , boolean markAsEscaped , boolean forceSync ) {
520
+ return execute (frame , location , markAsEscaped , forceSync , frame );
521
+ }
522
+
523
+ public PFrame execute (VirtualFrame frame , Node location , boolean markAsEscaped , boolean forceSync , Frame frameToMaterialize ) {
524
+ return ensureMaterializeFrameNode ().execute (frame , location , markAsEscaped , forceSync , frameToMaterialize );
525
+ }
526
+
527
+ public static MaterializeFrameUnadoptibleNode getUncached () {
528
+ return INSTANCE ;
529
+ }
530
+
531
+ private MaterializeFrameNode ensureMaterializeFrameNode () {
532
+ if (materializeFrameNode == null ) {
533
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
534
+ materializeFrameNode = insert (MaterializeFrameNodeGen .create (false ));
535
+ }
536
+ return materializeFrameNode ;
537
+ }
538
+
539
+ @ Override
540
+ public boolean isAdoptable () {
541
+ return false ;
542
+ }
543
+
431
544
}
545
+
432
546
}
0 commit comments