Skip to content

Commit f99d777

Browse files
committed
speculate that a loop is always executed at least once
1 parent e2588ec commit f99d777

File tree

1 file changed

+34
-19
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/control

1 file changed

+34
-19
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/control/ForNode.java

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import com.oracle.graal.python.runtime.PythonContext;
4040
import com.oracle.graal.python.runtime.PythonOptions;
4141
import com.oracle.graal.python.runtime.exception.PException;
42-
import com.oracle.graal.python.runtime.exception.PythonErrorType;
4342
import com.oracle.truffle.api.CompilerDirectives;
4443
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
4544
import com.oracle.truffle.api.Truffle;
@@ -49,14 +48,15 @@
4948
import com.oracle.truffle.api.dsl.Specialization;
5049
import com.oracle.truffle.api.frame.FrameSlot;
5150
import com.oracle.truffle.api.frame.FrameSlotKind;
52-
import com.oracle.truffle.api.frame.FrameSlotTypeException;
51+
import com.oracle.truffle.api.frame.FrameUtil;
5352
import com.oracle.truffle.api.frame.VirtualFrame;
5453
import com.oracle.truffle.api.nodes.NodeInfo;
5554
import com.oracle.truffle.api.nodes.RepeatingNode;
5655

5756
final class ForRepeatingNode extends PNodeWithContext implements RepeatingNode {
58-
57+
@CompilationFinal FrameSlot firstIterationSlot;
5958
@CompilationFinal FrameSlot iteratorSlot;
59+
@CompilationFinal boolean loopNeverSkipped = true;
6060
private final ContextReference<PythonContext> contextRef = PythonLanguage.getContextRef();
6161
@Child ForNextElementNode nextElement;
6262
@Child StatementNode body;
@@ -68,16 +68,30 @@ public ForRepeatingNode(StatementNode target, StatementNode body) {
6868
}
6969

7070
public boolean executeRepeating(VirtualFrame frame) {
71-
try {
72-
if (!nextElement.execute(frame, frame.getObject(iteratorSlot))) {
73-
return false;
71+
Object iteratorObject = FrameUtil.getObjectSafe(frame, iteratorSlot);
72+
if (loopNeverSkipped) {
73+
boolean firstIteration = FrameUtil.getBooleanSafe(frame, firstIterationSlot);
74+
if (firstIteration) {
75+
// first loop iteration, write the iterator
76+
if (!nextElement.execute(frame, iteratorObject)) {
77+
// if we ever skip the loop we invalidate here. this helps the
78+
// compiler understand if a loop is never skipped, that the loop
79+
// variable can never be null after the loop, so it doesn't have
80+
// to merge the last value of the loop variable with null
81+
CompilerDirectives.transferToInterpreterAndInvalidate();
82+
loopNeverSkipped = false;
83+
return false;
84+
}
85+
frame.setBoolean(firstIterationSlot, false);
86+
} else {
87+
if (!nextElement.execute(frame, iteratorObject)) {
88+
return false;
89+
}
7490
}
75-
} catch (FrameSlotTypeException e) {
76-
if (raise == null) {
77-
CompilerDirectives.transferToInterpreterAndInvalidate();
78-
raise = insert(PRaiseNode.create());
91+
} else {
92+
if (!nextElement.execute(frame, iteratorObject)) {
93+
return false;
7994
}
80-
throw raise.raise(PythonErrorType.RuntimeError, "internal error: unexpected frame slot type");
8195
}
8296
body.executeVoid(frame);
8397
contextRef.get().triggerAsyncActions(frame, this);
@@ -87,7 +101,6 @@ public boolean executeRepeating(VirtualFrame frame) {
87101

88102
@ImportStatic({PythonOptions.class, SpecialMethodNames.class})
89103
abstract class ForNextElementNode extends PNodeWithContext {
90-
91104
@Child StatementNode target;
92105

93106
public ForNextElementNode(StatementNode target) {
@@ -152,11 +165,10 @@ protected boolean doIterator(VirtualFrame frame, Object object,
152165

153166
@NodeInfo(shortName = "for")
154167
public final class ForNode extends LoopNode {
155-
156168
@CompilationFinal private FrameSlot iteratorSlot;
157-
158-
@Child private com.oracle.truffle.api.nodes.LoopNode loopNode;
169+
@CompilationFinal private FrameSlot firstIterationSlot;
159170
@Child private ExpressionNode iterator;
171+
@Child private com.oracle.truffle.api.nodes.LoopNode loopNode;
160172

161173
public ForNode(StatementNode body, StatementNode target, ExpressionNode iterator) {
162174
this.iterator = iterator;
@@ -167,22 +179,25 @@ public StatementNode getTarget() {
167179
return ((ForRepeatingNode) loopNode.getRepeatingNode()).nextElement.target;
168180
}
169181

170-
public ExpressionNode getIterator() {
171-
return iterator;
172-
}
173-
174182
@Override
175183
public StatementNode getBody() {
176184
return ((ForRepeatingNode) loopNode.getRepeatingNode()).body;
177185
}
178186

187+
public ExpressionNode getIterator() {
188+
return iterator;
189+
}
190+
179191
@Override
180192
public void executeVoid(VirtualFrame frame) {
181193
if (iteratorSlot == null) {
182194
CompilerDirectives.transferToInterpreterAndInvalidate();
183195
iteratorSlot = frame.getFrameDescriptor().addFrameSlot(new Object(), FrameSlotKind.Object);
184196
((ForRepeatingNode) loopNode.getRepeatingNode()).iteratorSlot = iteratorSlot;
197+
firstIterationSlot = frame.getFrameDescriptor().addFrameSlot(new Object(), FrameSlotKind.Boolean);
198+
((ForRepeatingNode) loopNode.getRepeatingNode()).firstIterationSlot = firstIterationSlot;
185199
}
200+
frame.setBoolean(firstIterationSlot, true);
186201
frame.setObject(iteratorSlot, iterator.execute(frame));
187202
try {
188203
loopNode.executeLoop(frame);

0 commit comments

Comments
 (0)