@@ -533,12 +533,16 @@ case StartFor(var _, var elemName, var step) -> {
533533 seq ));
534534 var init = new Constant (SEXPs .integer (0 ));
535535 var index = insertAndReturn ("_idx" , new Aea (init ));
536+ // Must be pushed for deopt in body
537+ push (length );
536538 push (index );
537539 setJump (goto_ (stepBb ));
538540
539541 // For loop step
540542 moveTo (stepBb );
541543 // Increment the index
544+ index = pop ();
545+ length = top ();
542546 var index1 =
543547 insertAndReturn (
544548 "_idx" ,
@@ -548,7 +552,7 @@ case StartFor(var _, var elemName, var step) -> {
548552 ImmutableList .of (Type .BOXED_INTEGER , Type .BOXED_INTEGER ),
549553 Type .BOXED_INTEGER ,
550554 Effects .NONE ),
551- pop () ,
555+ index ,
552556 new Constant (SEXPs .integer (1 ))));
553557 push (index1 );
554558 // Compare the index to the length
@@ -651,7 +655,8 @@ case StepFor(var body) -> {
651655 }
652656 case EndFor () -> {
653657 compileEndLoop (LoopType .FOR );
654- // Pop index and replace with `NULL` (a SEXP, in case we use it)
658+ // Pop index and length and push `NULL` (loop's "output")
659+ pop ();
655660 pop ();
656661 push (new Constant (SEXPs .NULL ));
657662 }
@@ -661,31 +666,34 @@ case EndFor() -> {
661666 case LdTrue () -> push (new Constant (SEXPs .TRUE ));
662667 case LdFalse () -> push (new Constant (SEXPs .FALSE ));
663668 case GetVar (var name ) -> {
669+ var preStack = ImmutableList .copyOf (stack );
664670 pushInsert (getStr (name ), new Load (LoadType .LOCAL_VAR , getVar (name )));
665- tryAddCheckpoint (false );
671+ tryAddCheckpoint (false , preStack );
672+
666673 pushInsert (getStr (name ), new Force (true , pop ()));
667674 insert (intrinsic ("checkMissing" , top ()));
668- tryAddCheckpoint (true );
675+ tryAddCheckpoint (true , stack );
669676 }
670677 case DdVal (var name ) -> {
678+ var preStack = ImmutableList .copyOf (stack );
671679 var ddIndex = NamedVariable .ddNum (get (name ).ddNum ());
672680 pushInsert (getStr (name ), new Load (LoadType .LOCAL_VAR , ddIndex ));
673- tryAddCheckpoint (false );
681+ tryAddCheckpoint (false , preStack );
682+
674683 pushInsert (getStr (name ), new Force (true , pop ()));
675684 insert (intrinsic ("checkMissing" , top ()));
676- tryAddCheckpoint (true );
685+ tryAddCheckpoint (true , stack );
677686 }
678687 case SetVar (var name ) -> insert (new Store (StoreType .LOCAL_VAR , getVar (name ), top ()));
679688 case GetFun (var name ) -> {
680- tryAddCheckpoint (false );
681689 var fun = insertAndReturn (getStr (name ), new Load (LoadType .LOCAL_FUN , getVar (name )));
682690 pushCall (fun );
683- tryAddCheckpoint (true );
691+ tryAddCheckpoint (true , stack );
684692 }
685693 case GetGlobFun (var name ) -> {
686694 var fun = insertAndReturn (getStr (name ), new Load (LoadType .GLOBAL_FUN , getVar (name )));
687695 pushCall (fun );
688- tryAddCheckpoint (true );
696+ tryAddCheckpoint (true , stack );
689697 }
690698 case GetBuiltin (var name ) -> pushCall (new Builtin (get (name ).name ()));
691699 case GetIntlBuiltin (var name ) -> pushCall (new Builtin (get (name ).name ()));
@@ -890,14 +898,18 @@ case Or2nd(var _) -> {
890898 insert (this ::goto_ );
891899 }
892900 case GetVarMissOk (var name ) -> {
901+ var preStack = ImmutableList .copyOf (stack );
893902 pushInsert (getStr (name ), new Load (LoadType .LOCAL_VAR , getVar (name )));
894- tryAddCheckpoint (false );
903+ tryAddCheckpoint (false , preStack );
904+
895905 pushInsertThenCp (getStr (name ), new Force (true , pop ()));
896906 }
897907 case DdValMissOk (var name ) -> {
908+ var preStack = ImmutableList .copyOf (stack );
898909 var ddIndex = get (name ).ddNum ();
899910 pushInsert (getStr (name ), new Load (LoadType .LOCAL_VAR , NamedVariable .ddNum (ddIndex )));
900- tryAddCheckpoint (false );
911+ tryAddCheckpoint (false , preStack );
912+
901913 pushInsertThenCp (getStr (name ), new Force (true , pop ()));
902914 }
903915 case Visible () -> insert (intrinsic ("setVisible" ));
@@ -1196,9 +1208,9 @@ private Argument compilePromise(SEXP codeSexp) {
11961208 return insertAndReturn ("_p" , new Promise (Type .ANY_VALUE_SEXP , Effects .REFLECT , cfg ));
11971209 }
11981210
1199- /// End the previously-compiled for loop instruction (the latest [#pushWhileOrRepeatLoop(BB,
1200- /// BB )] or [#pushForLoop(BB,BB,BB)]): pop its data, assert that the loop is of the correct
1201- /// type, and that the cursor is right after its end.
1211+ /// End the previously-compiled for loop instruction (the latest
1212+ /// [#pushWhileOrRepeatLoop(BB, BB )] or [#pushForLoop(BB,BB,BB)]): pop its data, assert that
1213+ /// the loop is of the correct type, and that the cursor is right after its end.
12021214 private void compileEndLoop (LoopType type ) {
12031215 var loop = popLoop ();
12041216 if (loop .type != type ) {
@@ -1288,27 +1300,33 @@ private void compileCall(Call call) {
12881300 // endregion compile instructions
12891301
12901302 // region checkpoints
1291- void pushInsertThenCp (String name , Expression expression ) {
1303+ private void pushInsertThenCp (String name , Expression expression ) {
12921304 pushInsert (name , expression );
1293- tryAddCheckpoint (true );
1305+ tryAddCheckpoint (true , stack );
12941306 }
12951307
1296- void pushInsertThenCp (Expression expression ) {
1308+ private void pushInsertThenCp (Expression expression ) {
12971309 pushInsert (expression );
1298- tryAddCheckpoint (true );
1310+ tryAddCheckpoint (true , stack );
12991311 }
13001312
1301- void tryAddCheckpoint (boolean afterInstruction ) {
1302- var deoptBcPos = afterInstruction ? bcPos + 1 : bcPos ;
1313+ /// Add a checkpoint at the current FIŘ position, before or after the current bytecode
1314+ /// position
1315+ ///
1316+ /// - If `afterBcInstr = false`, `stack` must be the stack before the bytecode was compiled,
1317+ /// and every FIŘ instruction emitted for the bytecode so far must be pure.
1318+ /// - If `afterBcInstr = true`, `stack` must be the current stack, and no more FIŘ
1319+ /// instructions can be emitted for this bytecode instruction.
1320+ private void tryAddCheckpoint (boolean afterBcInstr , List <Argument > stack ) {
1321+ var deoptBcPos = afterBcInstr ? bcPos + 1 : bcPos ;
13031322 var deopt = cfg .addBB ("D" + numDeopts ++);
1304- deopt .setJump (new Deopt (deoptBcPos , ImmutableList . copyOf ( stack ) ));
1323+ deopt .setJump (new Deopt (deoptBcPos , stack ));
13051324
13061325 // Don't add phis because they're never necessary.
13071326 // Don't use `insert` because it adds phis.
13081327 var success = cfg .addBB ();
13091328 cursor .bb ().setJump (new Checkpoint (new Target (success ), new Target (deopt )));
13101329 cursor .moveToStart (success );
1311- // TODO: Is the below correct?
13121330 bbsWithPhis .add (success );
13131331 }
13141332
@@ -1537,8 +1555,8 @@ private void pushInsert(String name, Expression expression) {
15371555 push (insertAndReturn (name , expression ));
15381556 }
15391557
1540- /// Push a value onto the "virtual stack" so that the next call to [#pop(Class )] or
1541- /// [#top(Class )] will return it.
1558+ /// Push a value onto the "virtual stack" so that the next call to [#pop()] or
1559+ /// [#top()] will return it.
15421560 ///
15431561 /// The bytecode is stack-based and IR is SSA-form. To convert properly, when the compiler
15441562 /// encounters `BcInstr.Ld...` and other instructions that push real values onto the
@@ -1767,8 +1785,8 @@ private Expression warning(String message) {
17671785 new Constant (SEXPs .NULL ));
17681786 }
17691787
1770- /// Stub for function guard (TODO what does [# BcInstr.CheckFun] do again?), which can fallback to
1771- /// an intrinsic but usually gets caught and turned into [DynamicCallee].
1788+ /// Stub for function guard (TODO what does [BcInstr.CheckFun] do again?), which can fallback
1789+ /// to an intrinsic but usually gets caught and turned into [DynamicCallee].
17721790 private Expression checkFun (Argument fun ) {
17731791 return intrinsic ("checkFun" , fun );
17741792 }
0 commit comments