Skip to content

Commit ba3adb4

Browse files
author
Adam Hrbac
committed
Implement stack level computation
1 parent 6b4c956 commit ba3adb4

File tree

3 files changed

+141
-22
lines changed

3 files changed

+141
-22
lines changed

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

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.compiler;
4242

43+
import java.util.ArrayDeque;
4344
import java.util.ArrayList;
4445
import java.util.Arrays;
4546
import java.util.HashMap;
@@ -556,31 +557,120 @@ public int lineToBci(int line) {
556557
return afterFirst ? bestBci : -2;
557558
}
558559

560+
public enum JumpBlock {
561+
None(0, null),
562+
With(1, "the body of a with statement"),
563+
Loop(2, "the body of a for loop"),
564+
Try(3, "the body of a try statement"),
565+
Except(4, "an 'except' block as there's no exception");
566+
567+
public final int i;
568+
public final String error;
569+
public static final long BITS = 3;
570+
571+
JumpBlock(int i, String error) {
572+
this.error = error;
573+
this.i = i;
574+
}
575+
576+
private static final JumpBlock[] VALUES = JumpBlock.values();
577+
578+
public long push(long stack) {
579+
return stack << BITS | this.i;
580+
}
581+
582+
public static long pop(long stack) {
583+
return stack >> BITS;
584+
}
585+
586+
public static JumpBlock peek(long stack) {
587+
return VALUES[(int) (stack & ((1 << BITS) - 1))];
588+
}
589+
}
590+
591+
@CompilerDirectives.TruffleBoundary
592+
public void computeStackLevels(long[] blocks, int[] stackLevels) {
593+
assert code.length + 1 == blocks.length;
594+
assert stackLevels.length == code.length;
595+
Arrays.fill(stackLevels, -1);
596+
// stackLevels has the stack depth before the corresponding opcode executes
597+
stackLevels[0] = 0;
598+
// deque of bci
599+
ArrayDeque<Integer> todo = new ArrayDeque<>();
600+
todo.addFirst(0);
601+
for (int i = 0; i < exceptionHandlerRanges.length; i += 4) {
602+
int handler = exceptionHandlerRanges[i + 2];
603+
int stackAtHandler = exceptionHandlerRanges[i + 3];
604+
// stack at handler + the exception
605+
stackLevels[handler] = stackAtHandler + 1;
606+
todo.addFirst(handler);
607+
}
608+
while (!todo.isEmpty()) {
609+
int bci = todo.removeLast();
610+
int stackHere = stackLevels[bci];
611+
assert stackHere >= 0;
612+
opCodeAt(code, bci, (ignored, op, oparg, followingArgs) -> {
613+
assert stackHere >= op.getNumberOfConsumedStackItems(oparg, followingArgs, true) : "failed at:" + op + ":" + bci;
614+
assert stackHere >= op.getNumberOfConsumedStackItems(oparg, followingArgs, false) : "failed at:" + op + ":" + bci;
615+
int stackWJump = op.getStackEffect(oparg, followingArgs, true);
616+
int stackWOJump = op.getStackEffect(oparg, followingArgs, false);
617+
int bciWJump = op.getNextBci(bci, oparg, true);
618+
int bciWOJump = op.getNextBci(bci, oparg, false);
619+
if (bciWJump == -1) {
620+
assert bciWOJump == bciWJump;
621+
return;
622+
}
623+
if (stackLevels[bciWJump] < 0) {
624+
stackLevels[bciWJump] = stackHere + stackWJump;
625+
if (op == OpCodes.GET_ITER) {
626+
System.out.println(stackLevels[bciWJump]);
627+
}
628+
todo.addFirst(bciWJump);
629+
} else {
630+
assert stackLevels[bciWJump] == stackHere + stackWJump;
631+
}
632+
if (bciWJump != bciWOJump) {
633+
if (stackLevels[bciWOJump] < 0) {
634+
stackLevels[bciWOJump] = stackHere + stackWOJump;
635+
todo.addFirst(bciWOJump);
636+
} else {
637+
assert stackLevels[bciWOJump] == stackHere + stackWOJump;
638+
}
639+
}
640+
});
641+
}
642+
}
643+
559644
@FunctionalInterface
560645
public interface BytecodeAction {
561646
void run(int bci, OpCodes op, int oparg, byte[] followingArgs);
562647
}
563648

564-
public static void iterateBytecode(byte[] bytecode, BytecodeAction action) {
649+
// returns the following bci
650+
private static int opCodeAt(byte[] bytecode, int bci, BytecodeAction action) {
565651
int oparg = 0;
566-
for (int bci = 0; bci < bytecode.length;) {
567-
OpCodes op = OpCodes.fromOpCode(bytecode[bci]);
568-
if (op == OpCodes.EXTENDED_ARG) {
569-
oparg |= Byte.toUnsignedInt(bytecode[bci + 1]);
570-
oparg <<= 8;
571-
} else {
572-
byte[] followingArgs = null;
573-
if (op.argLength > 0) {
574-
oparg |= Byte.toUnsignedInt(bytecode[bci + 1]);
575-
if (op.argLength > 1) {
576-
followingArgs = new byte[op.argLength - 1];
577-
System.arraycopy(bytecode, bci + 2, followingArgs, 0, followingArgs.length);
578-
}
579-
}
580-
action.run(bci, op, oparg, followingArgs);
581-
oparg = 0;
652+
OpCodes op = OpCodes.fromOpCode(bytecode[bci]);
653+
while (op == OpCodes.EXTENDED_ARG) {
654+
oparg |= Byte.toUnsignedInt(bytecode[bci + 1]);
655+
oparg <<= 8;
656+
bci += 2;
657+
op = OpCodes.fromOpCode(bytecode[bci]);
658+
}
659+
byte[] followingArgs = null;
660+
if (op.argLength > 0) {
661+
oparg |= Byte.toUnsignedInt(bytecode[bci + 1]);
662+
if (op.argLength > 1) {
663+
followingArgs = new byte[op.argLength - 1];
664+
System.arraycopy(bytecode, bci + 2, followingArgs, 0, followingArgs.length);
582665
}
583-
bci += op.length();
666+
}
667+
action.run(bci, op, oparg, followingArgs);
668+
return bci + op.length();
669+
}
670+
671+
public static void iterateBytecode(byte[] bytecode, BytecodeAction action) {
672+
for (int bci = 0; bci < bytecode.length;) {
673+
bci = opCodeAt(bytecode, bci, action);
584674
}
585675
}
586676

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@
4343
import java.math.BigInteger;
4444

4545
import com.oracle.graal.python.annotations.GenerateEnumConstants;
46+
import com.oracle.graal.python.builtins.objects.asyncio.PAsyncGenWrappedValue;
4647
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4748
import com.oracle.graal.python.builtins.objects.ints.PInt;
4849
import com.oracle.graal.python.runtime.exception.PException;
49-
import com.oracle.graal.python.builtins.objects.asyncio.PAsyncGenWrappedValue;
5050

5151
/**
5252
* Operation codes of our bytecode interpreter. They are similar to CPython's, but not the same. Our
@@ -675,7 +675,7 @@ public enum OpCodes {
675675
*
676676
* Pushes: the saved exception state, the exception
677677
*/
678-
PUSH_EXC_INFO(0, 0, 1),
678+
PUSH_EXC_INFO(0, 1, 2),
679679
/**
680680
* Sets the current exception state to the saved state (by {@link #PUSH_EXC_INFO}) on the stack
681681
* and pop it.
@@ -980,4 +980,29 @@ public int getNumberOfProducedStackItems(int oparg, byte[] followingArgs, boolea
980980
public int getStackEffect(int oparg, byte[] followingArgs, boolean withJump) {
981981
return getNumberOfProducedStackItems(oparg, followingArgs, withJump) - getNumberOfConsumedStackItems(oparg, followingArgs, withJump);
982982
}
983+
984+
public int getNextBci(int bci, int oparg, boolean withJump) {
985+
if (this.quickens != null) {
986+
return this.quickens.getNextBci(bci, oparg, withJump);
987+
}
988+
switch (this) {
989+
case JUMP_FORWARD:
990+
return bci + oparg;
991+
case JUMP_BACKWARD:
992+
return bci - oparg;
993+
case POP_AND_JUMP_IF_FALSE:
994+
case POP_AND_JUMP_IF_TRUE:
995+
case JUMP_IF_FALSE_OR_POP:
996+
case JUMP_IF_TRUE_OR_POP:
997+
case FOR_ITER:
998+
case MATCH_EXC_OR_JUMP:
999+
return withJump ? bci + oparg : bci + length();
1000+
case RETURN_VALUE:
1001+
case RAISE_VARARGS:
1002+
case END_EXC_HANDLER:
1003+
return -1;
1004+
default:
1005+
return bci + length();
1006+
}
1007+
}
9831008
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
13001300
if (newBci != bci) {
13011301
setCurrentBci(virtualFrame, bciSlot, newBci);
13021302
bci = newBci;
1303-
continue; // todo make sure this doesn't break inlining
1303+
continue; // todo code in big loop
13041304
}
13051305
}
13061306

@@ -2922,7 +2922,7 @@ private int traceLine(VirtualFrame virtualFrame, MutableLoopData mutableData, by
29222922
mutableData.setReturnLine(mutableData.getPastLine());
29232923
mutableData.setPyFrame(ensurePyFrame(virtualFrame));
29242924
PFrame pyFrame = mutableData.getPyFrame();
2925-
if (pyFrame != null && pyFrame.didJump()) {
2925+
if (pyFrame.didJump()) {
29262926
pyFrame.setJumpDestLine(-3);
29272927
mutableData.setPastBci(bci);
29282928
return bci;
@@ -2932,6 +2932,10 @@ private int traceLine(VirtualFrame virtualFrame, MutableLoopData mutableData, by
29322932
invokeTraceFunction(virtualFrame, null, mutableData.getThreadState(this), mutableData, PythonContext.TraceEvent.LINE,
29332933
mutableData.getPastLine(), true);
29342934
if (pyFrame.didJump()) {
2935+
long[] blocks = new long[getCodeUnit().code.length + 1];
2936+
int[] stacks = new int[getCodeUnit().code.length];
2937+
getCodeUnit().computeStackLevels(blocks, stacks);
2938+
System.out.println(getCodeUnit());
29352939
mutableData.setPastBci(bci);
29362940
int newBci = lineToBci(pyFrame.getJumpDestLine());
29372941
if (newBci == -1) {

0 commit comments

Comments
 (0)