V4: Fix unwind handler reset after for-in loop

Consider this JavaScript snippet:
    function f() {
        for (var i in []) {}
    }

This generates the following bytecode sequence:
       2       0: 14 00 09                 MoveConst r3, C0
               3: ec 00 00                 DefineArray (function), 0
               6: da 00                    GetIterator 0
               8: 18 08                    StoreReg r2
              10: c0 0f                    SetUnwindHandler 27
              12: 50 04                    Jump 18
              14: 16 0a                    LoadReg r4
              16: 18 07                    StoreReg r1
       3      18: 16 08                    LoadReg r2
              20: dc 0a 09                 IteratorNext r4, r3
              23: 54 f5                    JumpFalse 14
              25: 50 03                    Jump 30
              27: c0 00                    SetUnwindHandler <null>
              29: c2                       UnwindDispatch
       4      30: 0e                       LoadUndefined
              31: 02                       Ret

The problem is a normal loop exit: instruction 23 will not jump back,
but fall through, and then instruction 25 will jump over the
instructions resetting the unwind handler (27 + 29). Removing this jump
fixes the issue.

Change-Id: Ic9f03555ebebc27144490bce04e9a4166ed7c97c
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Erik Verbruggen 2019-01-25 14:18:30 +01:00
parent a8729cf143
commit 205f836e5d
1 changed files with 2 additions and 5 deletions

View File

@ -3339,7 +3339,6 @@ bool Codegen::visit(ForEachStatement *ast)
BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
{
auto cleanup = [ast, iterator, iteratorDone, this]() {
@ -3397,13 +3396,11 @@ bool Codegen::visit(ForEachStatement *ast)
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
bytecodeGenerator->addJumpInstruction(Instruction::JumpFalse()).link(body);
bytecodeGenerator->jump().link(done);
end.link();
// all execution paths need to end up here (normal loop exit, break, and exceptions) in
// order to reset the unwind handler, and to close the iterator in calse of an for-of loop.
}
done.link();
return false;
}