Skip to content

Commit f3a317e

Browse files
author
Adam Hrbac
committed
WIP: blocked by GR-50221
1 parent ba3adb4 commit f3a317e

File tree

3 files changed

+182
-35
lines changed

3 files changed

+182
-35
lines changed

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

Lines changed: 164 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.ArrayDeque;
4444
import java.util.ArrayList;
4545
import java.util.Arrays;
46+
import java.util.Collections;
4647
import java.util.HashMap;
4748
import java.util.List;
4849
import java.util.Objects;
@@ -421,6 +422,7 @@ public String toString(byte[] bytecode) {
421422
case JUMP_IF_TRUE_OR_POP:
422423
case MATCH_EXC_OR_JUMP:
423424
case SEND:
425+
case THROW:
424426
lines.computeIfAbsent(bcBCI + oparg, k -> new String[DISASSEMBLY_NUM_COLUMNS])[1] = ">>";
425427
line[5] = String.format("to %d", bcBCI + oparg);
426428
break;
@@ -557,41 +559,182 @@ public int lineToBci(int line) {
557559
return afterFirst ? bestBci : -2;
558560
}
559561

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");
562+
public enum StackItem {
563+
With("the body of a with statement"),
564+
Iterable("the body of a for loop"),
565+
Except("an 'except' block as there's no exception"),
566+
Object("Incompatible stack");
566567

567-
public final int i;
568568
public final String error;
569-
public static final long BITS = 3;
570569

571-
JumpBlock(int i, String error) {
570+
StackItem(String error) {
572571
this.error = error;
573-
this.i = i;
574572
}
575573

576-
private static final JumpBlock[] VALUES = JumpBlock.values();
574+
ArrayList<StackItem> push(ArrayList<StackItem> v) {
575+
ArrayList<StackItem> ret = v == null ? new ArrayList<>() : new ArrayList<>(v);
576+
ret.add(this);
577+
return ret;
578+
}
579+
}
580+
581+
private void setNextStack(ArrayDeque<Integer> todo, List<ArrayList<StackItem>> stacks, int target, ArrayList<StackItem> value) {
582+
ArrayList<StackItem> blocksAtTarget = stacks.get(target);
583+
if (blocksAtTarget == null) {
584+
stacks.set(target, value);
585+
todo.addLast(target);
586+
} else {
587+
assert value.equals(blocksAtTarget) : "found conflicting stacks depending on code path: " + this.name;
588+
}
589+
}
577590

578-
public long push(long stack) {
579-
return stack << BITS | this.i;
591+
private static ArrayList<StackItem> popStack(ArrayList<StackItem> blocks) {
592+
assert blocks != null : "Pop from null stack";
593+
assert blocks.size() >= 1 : "Pop from empty stack";
594+
return new ArrayList<>(blocks.subList(0, blocks.size() - 1));
595+
}
596+
597+
// returns null if the jump is fine
598+
public String checkJump(int from, int to) {
599+
List<ArrayList<StackItem>> blocks = computeStackElems();
600+
ArrayList<StackItem> blkFrom = blocks.get(from);
601+
System.out.println(this);
602+
603+
iterateBytecode(code, (bci, op, oparg, following) -> {
604+
System.out.println(bci + "\t" +
605+
op.getNumberOfProducedStackItems(oparg, following, false) + "\t" +
606+
op.getNumberOfConsumedStackItems(oparg, following, false) + "\t" + op + "\t" +
607+
blocks.get(bci));
608+
});
609+
610+
// todo these should be exceptions
611+
assert blkFrom != null : "Unreachable origin";
612+
ArrayList<StackItem> blkTo = blocks.get(to);
613+
assert blkTo != null : "Unreachable target";
614+
if (blkTo.size() > blkFrom.size()) {
615+
return blkTo.get(blkTo.size() - 1).error;
580616
}
617+
for (int i = blkTo.size() - 1; i >= 0; --i) {
618+
if (blkTo.get(i) != blkFrom.get(i)) {
619+
return blkTo.get(i).error;
620+
}
621+
}
622+
return null;
623+
}
624+
625+
private List<ArrayList<StackItem>> computeStackElems() {
626+
List<ArrayList<StackItem>> blocks = new ArrayList<>(Collections.nCopies(code.length + 1, null));
627+
blocks.set(0, new ArrayList<>());
628+
ArrayDeque<Integer> todo = new ArrayDeque<>();
629+
todo.addFirst(0);
630+
while (!todo.isEmpty()) {
631+
int i = todo.removeLast();
632+
assert blocks.get(i) != null : "TODO message here";
633+
opCodeAt(code, i, (bci, op, oparg, followingArgs) -> {
634+
ArrayList<StackItem> next = blocks.get(bci);
635+
for (int j = 0; j < exceptionHandlerRanges.length; j += 4) {
636+
int start = exceptionHandlerRanges[j];
637+
int handler = exceptionHandlerRanges[j + 2];
638+
int stack = exceptionHandlerRanges[j + 3];
639+
if (start == bci) {
640+
ArrayList<StackItem> handlerStack = StackItem.Except.push(new ArrayList<>(blocks.get(bci).subList(0, stack)));
641+
// an exception handler is like a jump
642+
// the except block is added in the lines below
643+
setNextStack(todo, blocks, handler, handlerStack);
644+
}
645+
}
646+
switch (op) {
647+
case GET_ITER:
648+
case GET_AITER:
649+
next = StackItem.Iterable.push(popStack(blocks.get(bci)));
650+
setNextStack(todo, blocks, bci + 1, next);
651+
break;
652+
case PUSH_EXC_INFO:
653+
next = StackItem.Except.push(blocks.get(bci));
654+
setNextStack(todo, blocks, bci + 1, next);
655+
break;
656+
case MATCH_EXC_OR_JUMP:
657+
next = popStack(next);
658+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, false), next);
659+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, true), next);
660+
break;
661+
case SETUP_WITH:
662+
case SETUP_AWITH:
663+
next = StackItem.Object.push(StackItem.With.push(blocks.get(bci)));
664+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, false), next);
665+
break;
666+
case GET_AEXIT_CORO:
667+
next = StackItem.Object.push(StackItem.Except.push(popStack(popStack(popStack(blocks.get(bci))))));
668+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, false), next);
669+
break;
670+
case DUP_TOP:
671+
next = next.get(next.size() - 1).push(next);
672+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, false), next);
673+
break;
674+
case ROT_TWO: {
675+
StackItem top = next.get(next.size() - 1);
676+
StackItem belowTop = next.get(next.size() - 2);
677+
next = belowTop.push(top.push(popStack(popStack(next))));
678+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, false), next);
679+
break;
680+
}
681+
case ROT_THREE: {
682+
StackItem top = next.get(next.size() - 1);
683+
StackItem second = next.get(next.size() - 2);
684+
StackItem third = next.get(next.size() - 3);
685+
next = second.push(third.push(top.push(top.push(popStack(popStack(popStack(next)))))));
686+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, false), next);
687+
break;
688+
}
689+
case LOAD_NONE:
690+
opCodeAt(code, op.getNextBci(bci, oparg, false), (ignored, nextOp, ignored2, ignored3) -> {
691+
// used instead of exceptions in non-error paths for these opcodes
692+
// the handler code will push the Except StackItem
693+
if (nextOp != OpCodes.GET_AEXIT_CORO && nextOp != OpCodes.EXIT_WITH) {
694+
setNextStack(todo, blocks, op.getNextBci(bci, oparg, false), StackItem.Object.push(blocks.get(bci)));
695+
}
696+
});
697+
break;
581698

582-
public static long pop(long stack) {
583-
return stack >> BITS;
699+
default: {
700+
int nextWJump = op.getNextBci(bci, oparg, true);
701+
int nextWOJump = op.getNextBci(bci, oparg, false);
702+
int stackLostWJump = op.getNumberOfConsumedStackItems(oparg, followingArgs, true);
703+
int stackLostWOJump = op.getNumberOfConsumedStackItems(oparg, followingArgs, false);
704+
int stackGainWJump = op.getNumberOfProducedStackItems(oparg, followingArgs, true);
705+
int stackGainWOJump = op.getNumberOfProducedStackItems(oparg, followingArgs, false);
706+
handleGeneralOp(blocks, todo, bci, nextWJump, stackLostWJump, stackGainWJump);
707+
if (nextWJump != nextWOJump) {
708+
handleGeneralOp(blocks, todo, bci, nextWOJump, stackLostWOJump, stackGainWOJump);
709+
}
710+
break;
711+
}
712+
}
713+
});
584714
}
715+
return blocks;
716+
}
585717

586-
public static JumpBlock peek(long stack) {
587-
return VALUES[(int) (stack & ((1 << BITS) - 1))];
718+
private void handleGeneralOp(List<ArrayList<StackItem>> blocks, ArrayDeque<Integer> todo, int bci, int next, int stackLost, int stackGain) {
719+
if (next >= 0) {
720+
ArrayList<StackItem> blocksHere = new ArrayList<>(blocks.get(bci));
721+
// System.out.println("Before: " + stackLost + "\t" + stackGain + "\t" + bci + "\t" +
722+
// blocksHere);
723+
for (int k = 0; k < stackLost; ++k) {
724+
blocksHere.remove(blocksHere.size() - 1);
725+
}
726+
for (int k = 0; k < stackGain; ++k) {
727+
blocksHere.add(StackItem.Object);
728+
}
729+
// System.out.println("Before stack: " + blocks.get(next));
730+
// System.out.println("After: " + blocksHere);
731+
setNextStack(todo, blocks, next, blocksHere);
588732
}
589733
}
590734

591735
@CompilerDirectives.TruffleBoundary
592-
public void computeStackLevels(long[] blocks, int[] stackLevels) {
593-
assert code.length + 1 == blocks.length;
594-
assert stackLevels.length == code.length;
736+
public int[] computeStackLevels() {
737+
int[] stackLevels = new int[code.length];
595738
Arrays.fill(stackLevels, -1);
596739
// stackLevels has the stack depth before the corresponding opcode executes
597740
stackLevels[0] = 0;
@@ -622,9 +765,6 @@ public void computeStackLevels(long[] blocks, int[] stackLevels) {
622765
}
623766
if (stackLevels[bciWJump] < 0) {
624767
stackLevels[bciWJump] = stackHere + stackWJump;
625-
if (op == OpCodes.GET_ITER) {
626-
System.out.println(stackLevels[bciWJump]);
627-
}
628768
todo.addFirst(bciWJump);
629769
} else {
630770
assert stackLevels[bciWJump] == stackHere + stackWJump;
@@ -639,6 +779,7 @@ public void computeStackLevels(long[] blocks, int[] stackLevels) {
639779
}
640780
});
641781
}
782+
return stackLevels;
642783
}
643784

644785
@FunctionalInterface

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,8 @@ public int getNextBci(int bci, int oparg, boolean withJump) {
996996
case JUMP_IF_TRUE_OR_POP:
997997
case FOR_ITER:
998998
case MATCH_EXC_OR_JUMP:
999+
case SEND:
1000+
case THROW:
9991001
return withJump ? bci + oparg : bci + length();
10001002
case RETURN_VALUE:
10011003
case RAISE_VARARGS:

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

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,10 +1296,11 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
12961296
final int beginBci = bci;
12971297
tracingOrProfilingEnabled = checkTracingAndProfilingEnabled(noTraceOrProfile, mutableData);
12981298
if (isTracingEnabled(tracingOrProfilingEnabled)) {
1299-
int newBci = traceLine(virtualFrame, mutableData, localBC, bci);
1300-
if (newBci != bci) {
1301-
setCurrentBci(virtualFrame, bciSlot, newBci);
1302-
bci = newBci;
1299+
int stackDiff = traceLine(virtualFrame, mutableData, localBC, bci);
1300+
if (stackDiff <= 0) {
1301+
// traceLine already set the correct bci
1302+
bci = virtualFrame.getInt(bciSlot);
1303+
stackTop += stackDiff;
13031304
continue; // todo code in big loop
13041305
}
13051306
}
@@ -2886,10 +2887,11 @@ private void traceOrProfileCallCutoff(VirtualFrame virtualFrame, int initialBci,
28862887
}
28872888
}
28882889

2889-
// returns new bci
2890+
// returns the change in stackTop after the jump, or 1 if no jump happened
28902891
@InliningCutoff
28912892
private int traceLine(VirtualFrame virtualFrame, MutableLoopData mutableData, byte[] localBC, int bci) {
28922893
int thisLine = bciToLine(bci);
2894+
int ret = 1;
28932895
boolean onANewLine = thisLine != mutableData.getPastLine();
28942896
mutableData.setPastLine(thisLine);
28952897
OpCodes c = OpCodes.fromOpCode(localBC[mutableData.getPastBci()]);
@@ -2932,24 +2934,26 @@ private int traceLine(VirtualFrame virtualFrame, MutableLoopData mutableData, by
29322934
invokeTraceFunction(virtualFrame, null, mutableData.getThreadState(this), mutableData, PythonContext.TraceEvent.LINE,
29332935
mutableData.getPastLine(), true);
29342936
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());
2939-
mutableData.setPastBci(bci);
29402937
int newBci = lineToBci(pyFrame.getJumpDestLine());
2938+
String error = co.checkJump(bci, newBci);
2939+
if (error != null) {
2940+
throw PRaiseNode.getUncached().raise(ValueError, ErrorMessages.CANT_JUMP_INTO_S, error);
2941+
}
2942+
mutableData.setPastBci(bci);
29412943
if (newBci == -1) {
29422944
throw PRaiseNode.getUncached().raise(ValueError); // todo
29432945
} else if (newBci == -2) {
29442946
throw PRaiseNode.getUncached().raise(ValueError); // todo
29452947
} else {
2946-
bci = newBci;
2948+
int[] stacks = co.computeStackLevels();
2949+
ret = stacks[newBci] - stacks[bci];
2950+
setCurrentBci(virtualFrame, bcioffset, newBci);
29472951
}
29482952
}
29492953
}
29502954
}
29512955
mutableData.setPastBci(bci);
2952-
return bci;
2956+
return ret;
29532957
}
29542958

29552959
private int bytecodeBinarySubscrAdaptive(VirtualFrame virtualFrame, int stackTop, int bci, Node[] localNodes, int bciSlot) {

0 commit comments

Comments
 (0)