Skip to content

Commit 6b4c956

Browse files
author
Adam Hrbac
committed
Implement basic jumps
1 parent 4a276bd commit 6b4c956

File tree

4 files changed

+126
-5
lines changed

4 files changed

+126
-5
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameBuiltins.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ public static GetBuiltinsNode create() {
140140
}
141141
}
142142

143-
@Builtin(name = "f_lineno", minNumOfPositionalArgs = 1, isGetter = true)
144143
@GenerateNodeFactory
145144
public abstract static class GetLinenoNode extends PythonBuiltinNode {
146145
public abstract int executeInt(VirtualFrame frame, PFrame self);
@@ -167,6 +166,49 @@ public static GetLinenoNode create() {
167166
}
168167
}
169168

169+
@Builtin(name = "f_lineno", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)
170+
@GenerateNodeFactory
171+
public abstract static class SetLinenoNode extends PythonBuiltinNode {
172+
public abstract Object execute(VirtualFrame frame, PFrame self, Object newLineno);
173+
174+
@Specialization(guards = "isNoValue(newLineno)")
175+
int get(VirtualFrame frame, PFrame self, Object newLineno,
176+
@Bind("this") Node inliningTarget,
177+
@Cached InlinedConditionProfile isCurrentFrameProfile,
178+
@Cached MaterializeFrameNode materializeNode) {
179+
// Special case because this builtin can be called without going through an invoke node:
180+
// we need to sync the location of the frame if and only if 'self' represents the
181+
// current frame. If 'self' represents another frame on the stack, the location is
182+
// already set
183+
if (isCurrentFrameProfile.profile(inliningTarget, frame != null && PArguments.getCurrentFrameInfo(frame) == self.getRef())) {
184+
PFrame pyFrame = materializeNode.execute(frame, this, false, false);
185+
assert pyFrame == self;
186+
}
187+
return self.getLine();
188+
}
189+
190+
@Specialization(guards = "!isNoValue(newLineno)")
191+
PNone set(VirtualFrame frame, PFrame self, Object newLineno,
192+
@Bind("this") Node inliningTarget,
193+
@Cached InlinedConditionProfile isCurrentFrameProfile,
194+
@Cached MaterializeFrameNode materializeNode) {
195+
// Special case because this builtin can be called without going through an invoke node:
196+
// we need to sync the location of the frame if and only if 'self' represents the
197+
// current frame. If 'self' represents another frame on the stack, the location is
198+
// already set
199+
if (isCurrentFrameProfile.profile(inliningTarget, frame != null && PArguments.getCurrentFrameInfo(frame) == self.getRef())) {
200+
PFrame pyFrame = materializeNode.execute(frame, this, false, false);
201+
assert pyFrame == self;
202+
}
203+
if (self.isTraceArgument()) {
204+
self.setJumpDestLine((int) newLineno); // todo
205+
} else {
206+
throw raise(PythonBuiltinClassType.ValueError); // todo
207+
}
208+
return PNone.NONE;
209+
}
210+
}
211+
170212
@Builtin(name = "f_lasti", minNumOfPositionalArgs = 1, isGetter = true)
171213
@GenerateNodeFactory
172214
public abstract static class GetLastiNode extends PythonUnaryBuiltinNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ public final class PFrame extends PythonBuiltinObject {
7474
*/
7575
private boolean lockLine = false;
7676

77+
// -3 for jumps not allowed, -2 for no jump, otherwise the line to jump to - only should be set
78+
// in a trace function.
79+
private int jumpDestLine = -3;
7780
private Object localTraceFun = null;
7881

7982
private boolean traceLine = true;
@@ -96,6 +99,18 @@ public void setTraceLine(boolean traceLine) {
9699
this.traceLine = traceLine;
97100
}
98101

102+
public boolean isTraceArgument() {
103+
return jumpDestLine != -3;
104+
}
105+
106+
public int getJumpDestLine() {
107+
return jumpDestLine;
108+
}
109+
110+
public void setJumpDestLine(int jumpDestLine) {
111+
this.jumpDestLine = jumpDestLine;
112+
}
113+
99114
// TODO: frames: this is a large object, think about how to make this
100115
// smaller
101116
public static final class Reference {
@@ -228,6 +243,10 @@ public void lineUnlock() {
228243
this.lockLine = false;
229244
}
230245

246+
public boolean didJump() {
247+
return jumpDestLine > -2;
248+
}
249+
231250
@TruffleBoundary
232251
public int getLine() {
233252
if (line == -2) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/CodeUnit.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,34 @@ private static String collectionTypeToString(int oparg) {
528528
throw new IllegalStateException("Unknown type");
529529
}
530530

531+
// -1 for line after the code block, -2 for line before the code block, line number otherwise
532+
public int lineToBci(int line) {
533+
if (startLine == line) {
534+
return 0;
535+
}
536+
// todo look into instrumentation support
537+
int[] map = getSourceMap().startLineMap;
538+
int bestBci = -1;
539+
int lineDiff = Integer.MAX_VALUE;
540+
boolean afterFirst = false;
541+
for (int bci = 0; bci < map.length; ++bci) {
542+
if (map[bci] >= line) {
543+
int lineDiff2 = map[bci] - line;
544+
// the first bci found is the start of the line
545+
if (lineDiff2 < lineDiff) {
546+
bestBci = bci;
547+
lineDiff = lineDiff2;
548+
}
549+
}
550+
if (map[bci] > 0 && map[bci] <= line) {
551+
// the line is actually within the codeblock.
552+
afterFirst = true;
553+
}
554+
}
555+
// bestBci being -1 means the line is outside the code block
556+
return afterFirst ? bestBci : -2;
557+
}
558+
531559
@FunctionalInterface
532560
public interface BytecodeAction {
533561
void run(int bci, OpCodes op, int oparg, byte[] followingArgs);

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

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RecursionError;
4444
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
45+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
4546
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ZeroDivisionError;
4647
import static com.oracle.graal.python.builtins.objects.type.TypeFlags.MAPPING;
4748
import static com.oracle.graal.python.builtins.objects.type.TypeFlags.SEQUENCE;
@@ -1295,7 +1296,12 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
12951296
final int beginBci = bci;
12961297
tracingOrProfilingEnabled = checkTracingAndProfilingEnabled(noTraceOrProfile, mutableData);
12971298
if (isTracingEnabled(tracingOrProfilingEnabled)) {
1298-
traceLine(virtualFrame, mutableData, localBC, bci);
1299+
int newBci = traceLine(virtualFrame, mutableData, localBC, bci);
1300+
if (newBci != bci) {
1301+
setCurrentBci(virtualFrame, bciSlot, newBci);
1302+
bci = newBci;
1303+
continue; // todo make sure this doesn't break inlining
1304+
}
12991305
}
13001306

13011307
CompilerAsserts.partialEvaluationConstant(bc);
@@ -2880,8 +2886,9 @@ private void traceOrProfileCallCutoff(VirtualFrame virtualFrame, int initialBci,
28802886
}
28812887
}
28822888

2889+
// returns new bci
28832890
@InliningCutoff
2884-
private void traceLine(VirtualFrame virtualFrame, MutableLoopData mutableData, byte[] localBC, int bci) {
2891+
private int traceLine(VirtualFrame virtualFrame, MutableLoopData mutableData, byte[] localBC, int bci) {
28852892
int thisLine = bciToLine(bci);
28862893
boolean onANewLine = thisLine != mutableData.getPastLine();
28872894
mutableData.setPastLine(thisLine);
@@ -2911,14 +2918,34 @@ private void traceLine(VirtualFrame virtualFrame, MutableLoopData mutableData, b
29112918
bciToLine(bci - 1) != thisLine);
29122919
}
29132920
if (shouldTrace) {
2921+
// do not emit a line event on the line we just jumped to
29142922
mutableData.setReturnLine(mutableData.getPastLine());
29152923
mutableData.setPyFrame(ensurePyFrame(virtualFrame));
2916-
if (mutableData.getPyFrame().getTraceLine()) {
2924+
PFrame pyFrame = mutableData.getPyFrame();
2925+
if (pyFrame != null && pyFrame.didJump()) {
2926+
pyFrame.setJumpDestLine(-3);
2927+
mutableData.setPastBci(bci);
2928+
return bci;
2929+
}
2930+
if (pyFrame.getTraceLine()) {
2931+
pyFrame.setJumpDestLine(-2);
29172932
invokeTraceFunction(virtualFrame, null, mutableData.getThreadState(this), mutableData, PythonContext.TraceEvent.LINE,
29182933
mutableData.getPastLine(), true);
2934+
if (pyFrame.didJump()) {
2935+
mutableData.setPastBci(bci);
2936+
int newBci = lineToBci(pyFrame.getJumpDestLine());
2937+
if (newBci == -1) {
2938+
throw PRaiseNode.getUncached().raise(ValueError); // todo
2939+
} else if (newBci == -2) {
2940+
throw PRaiseNode.getUncached().raise(ValueError); // todo
2941+
} else {
2942+
bci = newBci;
2943+
}
2944+
}
29192945
}
29202946
}
29212947
mutableData.setPastBci(bci);
2948+
return bci;
29222949
}
29232950

29242951
private int bytecodeBinarySubscrAdaptive(VirtualFrame virtualFrame, int stackTop, int bci, Node[] localNodes, int bciSlot) {
@@ -3075,7 +3102,8 @@ private void invokeTraceFunction(VirtualFrame virtualFrame, Object arg, PythonCo
30753102
GetFrameLocalsNode.executeUncached(pyFrame);
30763103
Object result = CallTernaryMethodNode.getUncached().execute(null, traceFn, pyFrame, event.pythonName, nonNullArg);
30773104
syncLocalsBackToFrame(virtualFrame, pyFrame);
3078-
Object realResult = result == PNone.NONE ? null : result;
3105+
// https://github.com/python/cpython/issues/104232
3106+
Object realResult = result == PNone.NONE ? traceFn : result;
30793107
pyFrame.setLocalTraceFun(realResult);
30803108
} catch (Throwable e) {
30813109
threadState.setTraceFun(null, PythonLanguage.get(this));
@@ -5753,6 +5781,10 @@ public int bciToLine(int bci) {
57535781
return co.bciToLine(bci);
57545782
}
57555783

5784+
public int lineToBci(int line) {
5785+
return co.lineToBci(line);
5786+
}
5787+
57565788
public int getFirstLineno() {
57575789
return co.startLine;
57585790
}

0 commit comments

Comments
 (0)