Skip to content

Commit d1381e5

Browse files
msimacektimfel
authored andcommitted
Prevent deopts after exitting OSR
1 parent fcb3de7 commit d1381e5

File tree

3 files changed

+101
-13
lines changed

3 files changed

+101
-13
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.nodes.bytecode;
42+
43+
final class OSRInterpreterState {
44+
public final int stackTop;
45+
public final int loopEndBci;
46+
47+
public OSRInterpreterState(int stackTop, int loopEndBci) {
48+
this.stackTop = stackTop;
49+
this.loopEndBci = loopEndBci;
50+
}
51+
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,12 @@ private void profileFrameSlots(MaterializedFrame generatorFrame) {
163163
}
164164

165165
@Override
166-
public Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterState) {
167-
Integer osrStackTop = (Integer) interpreterState;
166+
public Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterStateObject) {
167+
OSRInterpreterState interpreterState = (OSRInterpreterState) interpreterStateObject;
168168
MaterializedFrame generatorFrame = PArguments.getGeneratorFrame(osrFrame);
169169
copyStackSlotsIntoVirtualFrame(generatorFrame, osrFrame);
170-
copyOSRStackRemainderIntoVirtualFrame(generatorFrame, osrFrame, osrStackTop);
171-
return rootNode.executeFromBci(osrFrame, generatorFrame, osrFrame, this, target, osrStackTop);
170+
copyOSRStackRemainderIntoVirtualFrame(generatorFrame, osrFrame, interpreterState.stackTop);
171+
return rootNode.executeFromBci(osrFrame, generatorFrame, osrFrame, this, target, interpreterState.stackTop, interpreterState.loopEndBci);
172172
}
173173

174174
@ExplodeLoop
@@ -205,7 +205,7 @@ public Object execute(VirtualFrame frame) {
205205
stackFrame = frame;
206206
}
207207
try {
208-
return rootNode.executeFromBci(frame, generatorFrame, stackFrame, this, resumeBci, resumeStackTop);
208+
return rootNode.executeFromBci(frame, generatorFrame, stackFrame, this, resumeBci, resumeStackTop, Integer.MAX_VALUE);
209209
} finally {
210210
calleeContext.exit(frame, this);
211211
}

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

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ public Object execute(VirtualFrame virtualFrame) {
712712
copyArgsAndCells(virtualFrame, virtualFrame.getArguments());
713713
}
714714

715-
return executeFromBci(virtualFrame, virtualFrame, virtualFrame, this, 0, getInitialStackTop());
715+
return executeFromBci(virtualFrame, virtualFrame, virtualFrame, this, 0, getInitialStackTop(), Integer.MAX_VALUE);
716716
} finally {
717717
calleeContext.exit(virtualFrame, this);
718718
}
@@ -731,14 +731,25 @@ public Frame restoreParentFrameFromArguments(Object[] arguments) {
731731
}
732732

733733
@Override
734-
public Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterState) {
735-
return executeFromBci(osrFrame, osrFrame, osrFrame, this, target, (Integer) interpreterState);
734+
public Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterStateObject) {
735+
OSRInterpreterState interpreterState = (OSRInterpreterState) interpreterStateObject;
736+
return executeFromBci(osrFrame, osrFrame, osrFrame, this, target, interpreterState.stackTop, interpreterState.loopEndBci);
737+
}
738+
739+
private static final class OSRContinuation {
740+
public final int bci;
741+
public final int stackTop;
742+
743+
private OSRContinuation(int bci, int stackTop) {
744+
this.bci = bci;
745+
this.stackTop = stackTop;
746+
}
736747
}
737748

738749
@BytecodeInterpreterSwitch
739750
@ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.MERGE_EXPLODE)
740751
@SuppressWarnings("fallthrough")
741-
Object executeFromBci(VirtualFrame virtualFrame, Frame localFrame, Frame stackFrame, BytecodeOSRNode osrNode, int initialBci, int initialStackTop) {
752+
Object executeFromBci(VirtualFrame virtualFrame, Frame localFrame, Frame stackFrame, BytecodeOSRNode osrNode, int initialBci, int initialStackTop, int loopEndBci) {
742753
Object globals = PArguments.getGlobals(virtualFrame);
743754
Object locals = PArguments.getSpecialArgument(virtualFrame);
744755

@@ -787,6 +798,22 @@ Object executeFromBci(VirtualFrame virtualFrame, Frame localFrame, Frame stackFr
787798
CompilerAsserts.partialEvaluationConstant(bci);
788799
CompilerAsserts.partialEvaluationConstant(stackTop);
789800

801+
if (CompilerDirectives.inCompiledCode() && bci > loopEndBci) {
802+
/*
803+
* This means we're in OSR and we just jumped out of the OSR compiled loop. We want
804+
* to return to the caller to continue in interpreter again otherwise we would most
805+
* likely deopt on the next instruction. The caller handles the special return value
806+
* in JUMP_BACKWARD. In generators, we need to additionally copy the stack items
807+
* back to the generator frame.
808+
*/
809+
if (localFrame != stackFrame) {
810+
copyStackSlotsToGeneratorFrame(stackFrame, localFrame, stackTop);
811+
// Clear slots that were popped (if any)
812+
clearFrameSlots(localFrame, stackTop + 1, initialStackTop);
813+
}
814+
return new OSRContinuation(bci, stackTop);
815+
}
816+
790817
try {
791818
switch (bc) {
792819
case OpCodesConstants.LOAD_NONE:
@@ -1185,12 +1212,22 @@ Object executeFromBci(VirtualFrame virtualFrame, Frame localFrame, Frame stackFr
11851212
* will get mixed up. To retain such state, put it into the frame
11861213
* instead.
11871214
*/
1188-
Object osrResult = BytecodeOSRNode.tryOSR(osrNode, bci, stackTop, null, virtualFrame);
1215+
Object osrResult = BytecodeOSRNode.tryOSR(osrNode, bci, new OSRInterpreterState(stackTop, beginBci), null, virtualFrame);
11891216
if (osrResult != null) {
1190-
if (CompilerDirectives.hasNextTier() && loopCount[0] > 0) {
1191-
LoopNode.reportLoopCount(this, loopCount[0]);
1217+
if (osrResult instanceof OSRContinuation) {
1218+
// We should continue executing in interpreter after the loop
1219+
OSRContinuation continuation = (OSRContinuation) osrResult;
1220+
bci = continuation.bci;
1221+
stackTop = continuation.stackTop;
1222+
oparg = 0;
1223+
continue;
1224+
} else {
1225+
// We reached a return/yield
1226+
if (CompilerDirectives.hasNextTier() && loopCount[0] > 0) {
1227+
LoopNode.reportLoopCount(this, loopCount[0]);
1228+
}
1229+
return osrResult;
11921230
}
1193-
return osrResult;
11941231
}
11951232
}
11961233
oparg = 0;

0 commit comments

Comments
 (0)