39
39
import com .oracle .graal .python .runtime .PythonContext ;
40
40
import com .oracle .graal .python .runtime .PythonOptions ;
41
41
import com .oracle .graal .python .runtime .exception .PException ;
42
- import com .oracle .graal .python .runtime .exception .PythonErrorType ;
43
42
import com .oracle .truffle .api .CompilerDirectives ;
44
43
import com .oracle .truffle .api .CompilerDirectives .CompilationFinal ;
45
44
import com .oracle .truffle .api .Truffle ;
49
48
import com .oracle .truffle .api .dsl .Specialization ;
50
49
import com .oracle .truffle .api .frame .FrameSlot ;
51
50
import com .oracle .truffle .api .frame .FrameSlotKind ;
52
- import com .oracle .truffle .api .frame .FrameSlotTypeException ;
51
+ import com .oracle .truffle .api .frame .FrameUtil ;
53
52
import com .oracle .truffle .api .frame .VirtualFrame ;
54
53
import com .oracle .truffle .api .nodes .NodeInfo ;
55
54
import com .oracle .truffle .api .nodes .RepeatingNode ;
56
55
57
56
final class ForRepeatingNode extends PNodeWithContext implements RepeatingNode {
58
-
57
+ @ CompilationFinal FrameSlot firstIterationSlot ;
59
58
@ CompilationFinal FrameSlot iteratorSlot ;
59
+ @ CompilationFinal boolean loopNeverSkipped = true ;
60
60
private final ContextReference <PythonContext > contextRef = PythonLanguage .getContextRef ();
61
61
@ Child ForNextElementNode nextElement ;
62
62
@ Child StatementNode body ;
@@ -68,16 +68,30 @@ public ForRepeatingNode(StatementNode target, StatementNode body) {
68
68
}
69
69
70
70
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
+ }
74
90
}
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 ;
79
94
}
80
- throw raise .raise (PythonErrorType .RuntimeError , "internal error: unexpected frame slot type" );
81
95
}
82
96
body .executeVoid (frame );
83
97
contextRef .get ().triggerAsyncActions (frame , this );
@@ -87,7 +101,6 @@ public boolean executeRepeating(VirtualFrame frame) {
87
101
88
102
@ ImportStatic ({PythonOptions .class , SpecialMethodNames .class })
89
103
abstract class ForNextElementNode extends PNodeWithContext {
90
-
91
104
@ Child StatementNode target ;
92
105
93
106
public ForNextElementNode (StatementNode target ) {
@@ -152,11 +165,10 @@ protected boolean doIterator(VirtualFrame frame, Object object,
152
165
153
166
@ NodeInfo (shortName = "for" )
154
167
public final class ForNode extends LoopNode {
155
-
156
168
@ CompilationFinal private FrameSlot iteratorSlot ;
157
-
158
- @ Child private com .oracle .truffle .api .nodes .LoopNode loopNode ;
169
+ @ CompilationFinal private FrameSlot firstIterationSlot ;
159
170
@ Child private ExpressionNode iterator ;
171
+ @ Child private com .oracle .truffle .api .nodes .LoopNode loopNode ;
160
172
161
173
public ForNode (StatementNode body , StatementNode target , ExpressionNode iterator ) {
162
174
this .iterator = iterator ;
@@ -167,22 +179,25 @@ public StatementNode getTarget() {
167
179
return ((ForRepeatingNode ) loopNode .getRepeatingNode ()).nextElement .target ;
168
180
}
169
181
170
- public ExpressionNode getIterator () {
171
- return iterator ;
172
- }
173
-
174
182
@ Override
175
183
public StatementNode getBody () {
176
184
return ((ForRepeatingNode ) loopNode .getRepeatingNode ()).body ;
177
185
}
178
186
187
+ public ExpressionNode getIterator () {
188
+ return iterator ;
189
+ }
190
+
179
191
@ Override
180
192
public void executeVoid (VirtualFrame frame ) {
181
193
if (iteratorSlot == null ) {
182
194
CompilerDirectives .transferToInterpreterAndInvalidate ();
183
195
iteratorSlot = frame .getFrameDescriptor ().addFrameSlot (new Object (), FrameSlotKind .Object );
184
196
((ForRepeatingNode ) loopNode .getRepeatingNode ()).iteratorSlot = iteratorSlot ;
197
+ firstIterationSlot = frame .getFrameDescriptor ().addFrameSlot (new Object (), FrameSlotKind .Boolean );
198
+ ((ForRepeatingNode ) loopNode .getRepeatingNode ()).firstIterationSlot = firstIterationSlot ;
185
199
}
200
+ frame .setBoolean (firstIterationSlot , true );
186
201
frame .setObject (iteratorSlot , iterator .execute (frame ));
187
202
try {
188
203
loopNode .executeLoop (frame );
0 commit comments