Skip to content

Commit 7e5c352

Browse files
committed
Make gi_yieldfrom and gi_frame work in bytecode
1 parent e29d69a commit 7e5c352

File tree

3 files changed

+60
-27
lines changed

3 files changed

+60
-27
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import com.oracle.graal.python.nodes.PGuards;
6262
import com.oracle.graal.python.nodes.PRaiseNode;
6363
import com.oracle.graal.python.nodes.SpecialMethodNames;
64+
import com.oracle.graal.python.nodes.bytecode.PBytecodeRootNode;
6465
import com.oracle.graal.python.nodes.call.CallTargetInvokeNode;
6566
import com.oracle.graal.python.nodes.call.GenericInvokeNode;
6667
import com.oracle.graal.python.nodes.call.special.LookupAndCallVarargsNode;
@@ -70,8 +71,6 @@
7071
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
7172
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
7273
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
73-
import com.oracle.graal.python.nodes.generator.AbstractYieldNode;
74-
import com.oracle.graal.python.nodes.generator.YieldFromNode;
7574
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
7675
import com.oracle.graal.python.runtime.PythonOptions;
7776
import com.oracle.graal.python.runtime.exception.PException;
@@ -556,10 +555,18 @@ static Object getFrame(PGenerator self,
556555
PArguments.setClosure(arguments, PArguments.getClosure(self.getArguments()));
557556
PArguments.setGeneratorFrame(arguments, generatorFrame);
558557
frame.setArguments(arguments);
559-
if (self.isStarted()) {
560-
// Hack: Fake bytecode to make inspect.getgeneratorstate distinguish suspended
561-
// and unstarted generators
562-
frame.setLasti(10000);
558+
if (!self.usesBytecode()) {
559+
if (self.isStarted()) {
560+
/*
561+
* Hack: Fake bytecode to make inspect.getgeneratorstate distinguish
562+
* suspended and unstarted generators
563+
*/
564+
frame.setLasti(10000);
565+
}
566+
} else {
567+
PBytecodeRootNode.FrameInfo info = (PBytecodeRootNode.FrameInfo) generatorFrame.getFrameDescriptor().getInfo();
568+
frame.setLasti(info.getBci(generatorFrame));
569+
frame.setLine(info.getLineno(generatorFrame));
563570
}
564571
return frame;
565572
}
@@ -571,13 +578,8 @@ static Object getFrame(PGenerator self,
571578
public abstract static class GetYieldFromNode extends PythonUnaryBuiltinNode {
572579
@Specialization
573580
static Object getYieldFrom(PGenerator self) {
574-
AbstractYieldNode currentYield = self.getCurrentYieldNode();
575-
if (currentYield instanceof YieldFromNode) {
576-
int iteratorSlot = ((YieldFromNode) currentYield).getIteratorSlot();
577-
return PArguments.getControlDataFromGeneratorArguments(self.getArguments()).getIteratorAt(iteratorSlot);
578-
} else {
579-
return PNone.NONE;
580-
}
581+
Object yieldFrom = self.getYieldFrom();
582+
return yieldFrom != null ? yieldFrom : PNone.NONE;
581583
}
582584
}
583585

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
3737
import com.oracle.graal.python.nodes.bytecode.PBytecodeRootNode;
3838
import com.oracle.graal.python.nodes.generator.AbstractYieldNode;
39+
import com.oracle.graal.python.nodes.generator.YieldFromNode;
3940
import com.oracle.graal.python.parser.ExecutionCellSlots;
4041
import com.oracle.graal.python.parser.GeneratorInfo;
4142
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
@@ -53,7 +54,7 @@ public final class PGenerator extends PythonBuiltinObject {
5354

5455
private String name;
5556
private String qualname;
56-
private boolean usesBytecode;
57+
private final boolean usesBytecode;
5758
/**
5859
* Call targets with copies of the generator's AST. Each call target corresponds to one possible
5960
* entry point into the generator: the first call, and continuation for each yield. Each AST can
@@ -161,7 +162,6 @@ public RootCallTarget getCurrentCallTarget() {
161162
}
162163

163164
public AbstractYieldNode getCurrentYieldNode() {
164-
// TODO bytecode
165165
if (currentCallTarget == 0 || running || finished) {
166166
// Not stopped on a yield
167167
return null;
@@ -170,6 +170,25 @@ public AbstractYieldNode getCurrentYieldNode() {
170170
return generatorInfo.getYieldNodes()[currentCallTarget - 1];
171171
}
172172

173+
public boolean usesBytecode() {
174+
return usesBytecode;
175+
}
176+
177+
public Object getYieldFrom() {
178+
if (!usesBytecode) {
179+
AbstractYieldNode currentYield = getCurrentYieldNode();
180+
if (currentYield instanceof YieldFromNode) {
181+
int iteratorSlot = ((YieldFromNode) currentYield).getIteratorSlot();
182+
return PArguments.getControlDataFromGeneratorArguments(arguments).getIteratorAt(iteratorSlot);
183+
}
184+
return null;
185+
} else {
186+
MaterializedFrame generatorFrame = PArguments.getGeneratorFrame(arguments);
187+
PBytecodeRootNode.FrameInfo info = (PBytecodeRootNode.FrameInfo) generatorFrame.getFrameDescriptor().getInfo();
188+
return info.getYieldFrom(generatorFrame);
189+
}
190+
}
191+
173192
public boolean isStarted() {
174193
return (currentCallTarget != 0 || usesBytecode && getBci() > 0) && !running;
175194
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import com.oracle.graal.python.builtins.objects.function.PArguments;
6666
import com.oracle.graal.python.builtins.objects.function.PKeyword;
6767
import com.oracle.graal.python.builtins.objects.function.Signature;
68+
import com.oracle.graal.python.builtins.objects.generator.GeneratorControlData;
6869
import com.oracle.graal.python.builtins.objects.generator.ThrowData;
6970
import com.oracle.graal.python.builtins.objects.list.ListBuiltins;
7071
import com.oracle.graal.python.builtins.objects.list.PList;
@@ -127,6 +128,7 @@
127128
import com.oracle.graal.python.nodes.subscript.DeleteItemNode;
128129
import com.oracle.graal.python.nodes.subscript.GetItemNode;
129130
import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode;
131+
import com.oracle.graal.python.parser.GeneratorInfo;
130132
import com.oracle.graal.python.runtime.ExecutionContext.CalleeContext;
131133
import com.oracle.graal.python.runtime.PythonContext;
132134
import com.oracle.graal.python.runtime.PythonOptions;
@@ -343,6 +345,12 @@ public final class PBytecodeRootNode extends PRootNode implements BytecodeOSRNod
343345
}
344346
};
345347

348+
/*
349+
* Create fake GeneratorControlData just to maintain the same generator frame layout as AST
350+
* interpreter. TODO remove
351+
*/
352+
public static final GeneratorControlData GENERATOR_CONTROL_DATA = new GeneratorControlData(new GeneratorInfo(new GeneratorInfo.Mutable()));
353+
346354
private final Signature signature;
347355
private final String name;
348356
private boolean pythonInternal;
@@ -398,19 +406,21 @@ public int bciToLine(int bci) {
398406
}
399407

400408
public int getBci(Frame frame) {
401-
/*
402-
* Integer values throw FrameSlotTypeException when accessed before being set. The bci
403-
* value is set upon exception or in generators, but not on normal return, which is the
404-
* most common case, so we use getValue to avoid the exception.
405-
*
406-
* TODO when the static slot API is merged, we should use that, the static slots should
407-
* be initialized to 0
408-
*/
409-
Integer bci = (Integer) frame.getValue(rootNode.bcioffset);
410-
if (bci == null) {
411-
return -1;
409+
if (frame.isInt(rootNode.bcioffset)) {
410+
return frame.getInt(rootNode.bcioffset);
411+
}
412+
return -1;
413+
}
414+
415+
public Object getYieldFrom(Frame generatorFrame) {
416+
int bci = getBci(generatorFrame);
417+
/* Match the `yield from` bytecode pattern and get the object from stack */
418+
if (bci > 3 && rootNode.bytecode[bci - 3] == OpCodesConstants.SEND && rootNode.bytecode[bci - 1] == OpCodesConstants.YIELD_VALUE &&
419+
rootNode.bytecode[bci] == OpCodesConstants.RESUME_YIELD) {
420+
int stackTop = generatorFrame.getInt(rootNode.generatorStackTopOffset);
421+
return generatorFrame.getObject(stackTop);
412422
}
413-
return bci;
423+
return null;
414424
}
415425

416426
public Object getGeneratorReturnValue(Frame frame) {
@@ -746,6 +756,8 @@ public void createGeneratorFrame(Object[] arguments) {
746756
// it, otherwise they stay at the initial value, which we must set to null here
747757
PArguments.setException(arguments, null);
748758
PArguments.setCallerFrameInfo(arguments, null);
759+
PArguments.setControlData(arguments, GENERATOR_CONTROL_DATA);
760+
PArguments.setGeneratorFrameLocals(generatorFrameArguments, factory.createDictLocals(generatorFrame));
749761
generatorFrame.setInt(bcioffset, 0);
750762
generatorFrame.setInt(generatorStackTopOffset, stackoffset - 1);
751763
copyArgsAndCells(generatorFrame, arguments);

0 commit comments

Comments
 (0)