|
52 | 52 | import com.oracle.truffle.api.frame.FrameSlotKind; |
53 | 53 | import com.oracle.truffle.api.frame.FrameSlotTypeException; |
54 | 54 | import com.oracle.truffle.api.frame.VirtualFrame; |
55 | | -import com.oracle.truffle.api.impl.FrameWithoutBoxing; |
56 | 55 | import com.oracle.truffle.api.nodes.BytecodeOSRNode; |
57 | 56 | import com.oracle.truffle.api.nodes.ExplodeLoop; |
58 | 57 | import com.oracle.truffle.api.nodes.Node; |
@@ -138,6 +137,21 @@ public void testMultipleLoops() { |
138 | 137 | Assert.assertEquals(TwoFixedIterationLoops.NO_OSR, target.call(osrThreshold / 2)); |
139 | 138 | } |
140 | 139 |
|
| 140 | + /* |
| 141 | + * Test that OSR is triggered in the expected location when multiple loops are involved, and |
| 142 | + * makes sure that their cached frame states for transfers are independent. |
| 143 | + */ |
| 144 | + @Test |
| 145 | + public void testMultipleLoopsIncompatibleState() { |
| 146 | + // Each loop runs for osrThreshold + 1 iterations, so the first loop should trigger OSR. |
| 147 | + FrameDescriptor.Builder builder = FrameDescriptor.newBuilder(); |
| 148 | + TwoLoopsIncompatibleFrames osrNode = new TwoLoopsIncompatibleFrames(builder); |
| 149 | + RootNode rootNode = new Program(osrNode, builder.build()); |
| 150 | + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); |
| 151 | + Assert.assertEquals(TwoLoopsIncompatibleFrames.OSR_IN_FIRST_LOOP, target.call(osrThreshold + 1, true)); |
| 152 | + Assert.assertEquals(TwoLoopsIncompatibleFrames.OSR_IN_SECOND_LOOP, target.call(osrThreshold + 1, false)); |
| 153 | + } |
| 154 | + |
141 | 155 | /* |
142 | 156 | * Test that OSR fails if the code cannot be compiled. |
143 | 157 | */ |
@@ -576,7 +590,7 @@ public FixedIterationLoop(FrameDescriptor frameDescriptor) { |
576 | 590 | } |
577 | 591 |
|
578 | 592 | @Override |
579 | | - public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target) { |
| 593 | + public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target, Object targetMetadata) { |
580 | 594 | setInt(osrFrame, indexSlot, getInt(parentFrame, indexSlot)); |
581 | 595 | setInt(osrFrame, numIterationsSlot, getInt(parentFrame, numIterationsSlot)); |
582 | 596 | } |
@@ -657,6 +671,90 @@ protected Object executeLoop(VirtualFrame frame, int numIterations) { |
657 | 671 | } |
658 | 672 | } |
659 | 673 |
|
| 674 | + /** |
| 675 | + * Contains two loops whose entry's frame states differs. Makes sure that one's entry frame |
| 676 | + * state does not spill to the other |
| 677 | + */ |
| 678 | + public static class TwoLoopsIncompatibleFrames extends BytecodeOSRTestNode { |
| 679 | + static final String NO_OSR = "no osr"; |
| 680 | + static final String OSR_IN_FIRST_LOOP = "osr in first loop"; |
| 681 | + static final String OSR_IN_SECOND_LOOP = "osr in second loop"; |
| 682 | + |
| 683 | + static final int FIRST_LOOP_TARGET = 0; |
| 684 | + static final int SECOND_LOOP_TARGET = 1; |
| 685 | + |
| 686 | + @CompilationFinal int iterationsSlot; |
| 687 | + @CompilationFinal int indexSlot; |
| 688 | + @CompilationFinal int selectSlot; |
| 689 | + @CompilationFinal int localSlot; |
| 690 | + |
| 691 | + public TwoLoopsIncompatibleFrames(FrameDescriptor.Builder builder) { |
| 692 | + iterationsSlot = builder.addSlot(FrameSlotKind.Int, "iterations", null); |
| 693 | + indexSlot = builder.addSlot(FrameSlotKind.Int, "index", null); |
| 694 | + selectSlot = builder.addSlot(FrameSlotKind.Boolean, "select", null); |
| 695 | + localSlot = builder.addSlot(FrameSlotKind.Illegal, "local", null); |
| 696 | + } |
| 697 | + |
| 698 | + @Override |
| 699 | + Object execute(VirtualFrame frame) { |
| 700 | + int numIter = (int) frame.getArguments()[0]; |
| 701 | + boolean select = (boolean) frame.getArguments()[1]; |
| 702 | + frame.setInt(iterationsSlot, numIter); |
| 703 | + frame.setInt(indexSlot, 0); |
| 704 | + frame.setBoolean(selectSlot, select); |
| 705 | + if (select) { |
| 706 | + frame.setInt(localSlot, 0); |
| 707 | + return executeLoop(frame, numIter, select); |
| 708 | + } else { |
| 709 | + frame.setDouble(localSlot, 0d); |
| 710 | + return executeLoop(frame, numIter, select); |
| 711 | + } |
| 712 | + } |
| 713 | + |
| 714 | + @Override |
| 715 | + public Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterState) { |
| 716 | + return executeLoop(osrFrame, osrFrame.getInt(iterationsSlot), target == FIRST_LOOP_TARGET); |
| 717 | + } |
| 718 | + |
| 719 | + protected Object executeLoop(VirtualFrame frame, int numIterations, boolean select) { |
| 720 | + try { |
| 721 | + if (select) { |
| 722 | + for (int i = frame.getInt(indexSlot); i < numIterations; i++) { |
| 723 | + frame.setInt(indexSlot, i); |
| 724 | + int partial = frame.getInt(localSlot); |
| 725 | + frame.setInt(localSlot, i + partial); |
| 726 | + if (i + 1 < numIterations) { // back-edge will be taken |
| 727 | + if (BytecodeOSRNode.pollOSRBackEdge(this)) { |
| 728 | + Object result = BytecodeOSRNode.tryOSR(this, FIRST_LOOP_TARGET, null, null, frame); |
| 729 | + if (result != null) { |
| 730 | + return OSR_IN_FIRST_LOOP; |
| 731 | + } |
| 732 | + } |
| 733 | + } |
| 734 | + } |
| 735 | + } else { |
| 736 | + for (int i = frame.getInt(indexSlot); i < numIterations; i++) { |
| 737 | + frame.setInt(indexSlot, i); |
| 738 | + double partial = frame.getDouble(localSlot); |
| 739 | + frame.setDouble(localSlot, i + partial); |
| 740 | + if (i + 1 < numIterations) { // back-edge will be taken |
| 741 | + if (BytecodeOSRNode.pollOSRBackEdge(this)) { |
| 742 | + Object result = BytecodeOSRNode.tryOSR(this, SECOND_LOOP_TARGET, null, null, frame); |
| 743 | + if (result != null) { |
| 744 | + return OSR_IN_SECOND_LOOP; |
| 745 | + } |
| 746 | + } |
| 747 | + } |
| 748 | + } |
| 749 | + } |
| 750 | + return NO_OSR; |
| 751 | + } catch (FrameSlotTypeException e) { |
| 752 | + CompilerDirectives.transferToInterpreter(); |
| 753 | + throw new IllegalStateException("Error accessing index slot"); |
| 754 | + } |
| 755 | + } |
| 756 | + } |
| 757 | + |
660 | 758 | public static class UncompilableFixedIterationLoop extends FixedIterationLoop { |
661 | 759 | public UncompilableFixedIterationLoop(FrameDescriptor frameDescriptor) { |
662 | 760 | super(frameDescriptor); |
@@ -1013,8 +1111,8 @@ public Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterSt |
1013 | 1111 | } |
1014 | 1112 |
|
1015 | 1113 | @Override |
1016 | | - public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target) { |
1017 | | - super.copyIntoOSRFrame(osrFrame, parentFrame, target); |
| 1114 | + public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target, Object targetMetadata) { |
| 1115 | + super.copyIntoOSRFrame(osrFrame, parentFrame, target, targetMetadata); |
1018 | 1116 | // Copying should not trigger a deopt. |
1019 | 1117 | Assert.assertTrue(CompilerDirectives.inCompiledCode()); |
1020 | 1118 | } |
@@ -1128,10 +1226,9 @@ public void checkOSRState(VirtualFrame frame) { |
1128 | 1226 | public void restoreParentFrame(VirtualFrame osrFrame, VirtualFrame parentFrame) { |
1129 | 1227 | // The parent implementation asserts we are in compiled code, so we instead explicitly |
1130 | 1228 | // do the transfer here. |
1131 | | - ((BytecodeOSRMetadata) osrMetadata).transferFrame((FrameWithoutBoxing) osrFrame, (FrameWithoutBoxing) parentFrame); |
1132 | | - // Since the intSlot tag changed inside the compiled code, the tag speculation should |
1133 | | - // fail and cause a deopt. |
1134 | | - Assert.assertFalse(CompilerDirectives.inCompiledCode()); |
| 1229 | + super.restoreParentFrame(osrFrame, parentFrame); |
| 1230 | + // Parent frame restoration does not speculate on the state of the frame on return. |
| 1231 | + Assert.assertTrue(CompilerDirectives.inCompiledCode()); |
1135 | 1232 | } |
1136 | 1233 | } |
1137 | 1234 |
|
@@ -1204,9 +1301,9 @@ public FrameChangingNode(FrameDescriptor frameDescriptor) { |
1204 | 1301 | } |
1205 | 1302 |
|
1206 | 1303 | @Override |
1207 | | - public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target) { |
| 1304 | + public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target, Object targetMetadata) { |
1208 | 1305 | changeFrame(osrFrame.getFrameDescriptor()); // only changes the first time |
1209 | | - super.copyIntoOSRFrame(osrFrame, parentFrame, target); |
| 1306 | + super.copyIntoOSRFrame(osrFrame, parentFrame, target, targetMetadata); |
1210 | 1307 | } |
1211 | 1308 |
|
1212 | 1309 | @Override |
@@ -1335,7 +1432,7 @@ public Object execute(VirtualFrame frame) { |
1335 | 1432 |
|
1336 | 1433 | @Override |
1337 | 1434 | @ExplodeLoop |
1338 | | - public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target) { |
| 1435 | + public void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target, Object targetMetadata) { |
1339 | 1436 | for (int i = 0; i < regs.length; i++) { |
1340 | 1437 | setInt(osrFrame, i, getInt(parentFrame, i)); |
1341 | 1438 | } |
|
0 commit comments