Skip to content

Commit 1368e4e

Browse files
committed
Allow 'MaterializeFrameNode' to be used unadopted.
1 parent 07eefac commit 1368e4e

File tree

3 files changed

+160
-23
lines changed

3 files changed

+160
-23
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/GenericInvokeNode.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCalleeContext;
4949
import com.oracle.graal.python.runtime.PythonContext;
5050
import com.oracle.truffle.api.RootCallTarget;
51-
import com.oracle.truffle.api.Truffle;
5251
import com.oracle.truffle.api.frame.VirtualFrame;
5352
import com.oracle.truffle.api.nodes.IndirectCallNode;
5453
import com.oracle.truffle.api.nodes.NodeCost;
@@ -57,8 +56,8 @@
5756
public abstract class GenericInvokeNode extends AbstractInvokeNode {
5857
private static final GenericInvokeUncachedNode UNCACHED = new GenericInvokeUncachedNode();
5958

60-
@Child private IndirectCallNode callNode = Truffle.getRuntime().createIndirectCallNode();
61-
@Child private CallContext callContext = CallContext.create();
59+
@Child private IndirectCallNode callNode;
60+
@Child private CallContext callContext;
6261

6362
private final ConditionProfile isNullFrameProfile;
6463

@@ -70,7 +69,9 @@ public static GenericInvokeNode getUncached() {
7069
return UNCACHED;
7170
}
7271

73-
public GenericInvokeNode(ConditionProfile isNullFrameProfile) {
72+
public GenericInvokeNode(IndirectCallNode callNode, CallContext callContext, ConditionProfile isNullFrameProfile) {
73+
this.callNode = callNode;
74+
this.callContext = callContext;
7475
this.isNullFrameProfile = isNullFrameProfile;
7576
}
7677

@@ -109,14 +110,14 @@ public Object execute(VirtualFrame frame, RootCallTarget callTarget, Object[] ar
109110
private static final class GenericInvokeCachedNode extends GenericInvokeNode {
110111

111112
public GenericInvokeCachedNode() {
112-
super(ConditionProfile.createBinaryProfile());
113+
super(IndirectCallNode.create(), CallContext.create(), ConditionProfile.createBinaryProfile());
113114
}
114115

115116
}
116117

117118
private static final class GenericInvokeUncachedNode extends GenericInvokeNode {
118119
public GenericInvokeUncachedNode() {
119-
super(ConditionProfile.getUncached());
120+
super(IndirectCallNode.getUncached(), CallContext.getUncached(), ConditionProfile.getUncached());
120121
}
121122

122123
@Override

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/MaterializeFrameNode.java

Lines changed: 128 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@
5151
import com.oracle.graal.python.builtins.objects.function.PArguments;
5252
import com.oracle.graal.python.nodes.ModuleRootNode;
5353
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;
5457
import com.oracle.graal.python.nodes.function.ClassBodyRootNode;
5558
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
59+
import com.oracle.truffle.api.CompilerDirectives;
5660
import com.oracle.truffle.api.dsl.Cached;
5761
import com.oracle.truffle.api.dsl.Cached.Shared;
5862
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -73,6 +77,16 @@
7377
**/
7478
public abstract class MaterializeFrameNode extends Node {
7579

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+
7690
public final PFrame execute(VirtualFrame frame, boolean markAsEscaped, Frame frameToMaterialize) {
7791
return execute(frame, markAsEscaped, false, frameToMaterialize);
7892
}
@@ -96,7 +110,7 @@ public final PFrame execute(VirtualFrame frame, Node location, boolean markAsEsc
96110

97111
@Specialization(guards = {"getPFrame(frameToMaterialize) == null", "isGeneratorFrame(frameToMaterialize)"})
98112
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) {
100114
PFrame escapedFrame = factory.createPFrame(PArguments.getCurrentFrameInfo(frameToMaterialize), location, PArguments.getGeneratorFrameLocals(frameToMaterialize), false);
101115
syncArgs(frameToMaterialize, escapedFrame);
102116
PFrame.Reference topFrameRef = PArguments.getCurrentFrameInfo(frameToMaterialize);
@@ -106,17 +120,17 @@ static PFrame freshPFrameForGenerator(Node location, @SuppressWarnings("unused")
106120

107121
@Specialization(guards = {"getPFrame(frameToMaterialize) == null", "!inClassBody(frameToMaterialize)", "!isGeneratorFrame(frameToMaterialize)"})
108122
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) {
111125
PDict locals = factory.createDictLocals(frameToMaterialize.getFrameDescriptor());
112126
PFrame escapedFrame = factory.createPFrame(PArguments.getCurrentFrameInfo(frameToMaterialize), location, locals, false);
113127
return doEscapeFrame(frame, frameToMaterialize, escapedFrame, markAsEscaped, forceSync && !inModuleRoot(location), syncValuesNode);
114128
}
115129

116130
@Specialization(guards = {"getPFrame(frameToMaterialize) == null", "inClassBody(frameToMaterialize)"})
117131
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) {
120134
// the namespace argument stores the locals
121135
PFrame escapedFrame = factory.createPFrame(PArguments.getCurrentFrameInfo(frameToMaterialize), location, PArguments.getArgument(frameToMaterialize, 0), true);
122136
// 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
133147
**/
134148
@Specialization(guards = {"getPFrame(frameToMaterialize) != null", "!getPFrame(frameToMaterialize).hasFrame()"})
135149
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) {
138152
Object locals = getPFrame(frameToMaterialize).getLocalsDict();
139153
PFrame escapedFrame = factory.createPFrame(PArguments.getCurrentFrameInfo(frameToMaterialize), location, locals, inClassBody(frameToMaterialize));
140154
return doEscapeFrame(frame, frameToMaterialize, escapedFrame, markAsEscaped, forceSync && !inModuleRoot(location), syncValuesNode);
141155
}
142156

143157
@Specialization(guards = {"getPFrame(frameToMaterialize) != null", "getPFrame(frameToMaterialize).hasFrame()"}, replaces = "freshPFrame")
144158
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,
146160
@Cached("createBinaryProfile()") ConditionProfile syncProfile) {
147161
PFrame pyFrame = getPFrame(frameToMaterialize);
148162
if (syncProfile.profile(forceSync && !inClassBody(frameToMaterialize) && !inModuleRoot(location))) {
@@ -158,8 +172,8 @@ static PFrame alreadyEscapedFrame(VirtualFrame frame, Node location, boolean mar
158172

159173
@Specialization(replaces = {"freshPFrame", "alreadyEscapedFrame"})
160174
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,
163177
@Cached("createBinaryProfile()") ConditionProfile syncProfile) {
164178
if (getPFrame(frameToMaterialize) != null) {
165179
return alreadyEscapedFrame(frame, location, markAsEscaped, forceSync, frameToMaterialize, syncValuesNode, syncProfile);
@@ -220,6 +234,17 @@ protected static boolean inModuleRoot(Node location) {
220234
return location.getRootNode() instanceof ModuleRootNode;
221235
}
222236

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+
223248
/**
224249
* When refreshing the frame values in the locals dict, there are 4 cases:
225250
* <ol>
@@ -241,6 +266,12 @@ protected static boolean inModuleRoot(Node location) {
241266
@ImportStatic(SpecialMethodNames.class)
242267
public abstract static class SyncFrameValuesNode extends Node {
243268

269+
private final boolean adoptable;
270+
271+
public SyncFrameValuesNode(boolean adoptable) {
272+
this.adoptable = adoptable;
273+
}
274+
244275
public abstract void execute(VirtualFrame frame, PFrame pyframe, Frame frameToSync);
245276

246277
@Specialization(guards = {"hasLocalsStorage(pyFrame, frameToSync)", "frameToSync.getFrameDescriptor() == cachedFd"}, //
@@ -315,11 +346,11 @@ static void doLocalsStorageUncached(PFrame pyFrame, Frame frameToSync) {
315346
}
316347
}
317348

318-
@Specialization(guards = {"isDictWithCustomStorage(pyFrame)", "frameToSync.getFrameDescriptor() == cachedFd"}, //
349+
@Specialization(guards = {"isDictWithCustomStorage(pyFrame)", "frameToSync.getFrameDescriptor() == cachedFd", "isAdoptable()"}, //
319350
assumptions = "cachedFd.getVersion()", //
320351
limit = "1")
321352
@ExplodeLoop
322-
static void doGenericDictCached(VirtualFrame frame, PFrame pyFrame, Frame frameToSync,
353+
static void doGenericDictAdoptableCached(VirtualFrame frame, PFrame pyFrame, Frame frameToSync,
323354
@Cached("frameToSync.getFrameDescriptor()") @SuppressWarnings("unused") FrameDescriptor cachedFd,
324355
@Cached(value = "getSlots(cachedFd)", dimensions = 1) FrameSlot[] cachedSlots,
325356
@Cached(value = "getProfiles(cachedSlots.length)", dimensions = 1) ConditionProfile[] profiles,
@@ -346,8 +377,8 @@ static void doGenericDictCached(VirtualFrame frame, PFrame pyFrame, Frame frameT
346377
}
347378
}
348379

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,
351382
@Cached HashingCollectionNodes.SetItemNode setItemNode,
352383
@Cached HashingStorageNodes.DelItemNode deleteItemNode) {
353384
// 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,
373404
}
374405
}
375406

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+
376435
@Specialization(guards = "isCustomLocalsObject(pyFrame, frameToSync)")
377436
@SuppressWarnings("unused")
378437
static void doCustomLocalsObject(PFrame pyFrame, Frame frameToSync) {
@@ -428,5 +487,60 @@ private static Object resolveCellValue(ConditionProfile profile, Object value) {
428487
}
429488
return value;
430489
}
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+
431544
}
545+
432546
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/ExecutionContext.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.oracle.graal.python.nodes.frame.MaterializeFrameNode;
4949
import com.oracle.graal.python.nodes.frame.MaterializeFrameNodeGen;
5050
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
51+
import com.oracle.graal.python.nodes.frame.MaterializeFrameNode.MaterializeFrameUnadoptibleNode;
5152
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.GetCaughtExceptionNode;
5253
import com.oracle.graal.python.runtime.exception.PException;
5354
import com.oracle.truffle.api.CompilerDirectives;
@@ -66,8 +67,17 @@
6667
public abstract class ExecutionContext {
6768

6869
public static final class CallContext extends Node {
70+
71+
private static final CallContext INSTANCE = new CallContext(false);
72+
6973
@Child private MaterializeFrameNode materializeNode;
7074

75+
private final boolean adoptable;
76+
77+
private CallContext(boolean adoptable) {
78+
this.adoptable = adoptable;
79+
}
80+
7181
/**
7282
* Prepare a call from a Python frame to a Python function.
7383
*/
@@ -87,7 +97,7 @@ public void prepareCall(VirtualFrame frame, Object[] callArguments, RootCallTarg
8797
// We are handing the PFrame of the current frame to the caller, i.e., it does not
8898
// 'escape' since it is still on the stack.
8999
// Also, force synchronization of values
90-
PFrame pyFrame = ensureMaterializeNode().execute(frame, callNode, false, true);
100+
PFrame pyFrame = materialize(frame, callNode, false, true);
91101
assert thisInfo.getPyFrame() == pyFrame;
92102
assert pyFrame.getRef() == thisInfo;
93103

@@ -111,16 +121,28 @@ public void prepareCall(VirtualFrame frame, Object[] callArguments, RootCallTarg
111121
}
112122
}
113123

124+
private PFrame materialize(VirtualFrame frame, Node callNode, boolean markAsEscaped, boolean forceSync) {
125+
if (adoptable) {
126+
return ensureMaterializeNode().execute(frame, callNode, markAsEscaped, forceSync);
127+
}
128+
return MaterializeFrameUnadoptibleNode.getUncached().execute(frame, callNode, markAsEscaped, forceSync);
129+
}
130+
114131
private MaterializeFrameNode ensureMaterializeNode() {
115132
if (materializeNode == null) {
116133
CompilerDirectives.transferToInterpreterAndInvalidate();
117-
materializeNode = insert(MaterializeFrameNodeGen.create());
134+
materializeNode = insert(MaterializeFrameNodeGen.create(adoptable));
118135
}
119136
return materializeNode;
137+
120138
}
121139

122140
public static CallContext create() {
123-
return new CallContext();
141+
return new CallContext(true);
142+
}
143+
144+
public static CallContext getUncached() {
145+
return INSTANCE;
124146
}
125147
}
126148

0 commit comments

Comments
 (0)