Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index 9216b8d959aa05517c58192781275c657bec1be4..6feaa9b1d2abdb62510a551e5e4960e8129755ae 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -6278,11 +6278,12 @@ Expression* ParserTraits::RewriteYieldStar( |
| return yield_star; |
| } |
| + |
| // Desugaring of (lhs) instanceof (rhs) |
| // ==================================== |
| // |
| // We desugar instanceof into a load of property @@hasInstance on the rhs. |
| -// We end up with roughly the following code (O, C): |
| +// We end up with roughly the following code: |
| // |
| // do { |
| // let O = lhs; |
| @@ -6366,7 +6367,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, |
| // if (!IS_CALLABLE(C)) { |
| // throw MakeTypeError(kCalledNonCallableInstanceOf); |
| // } |
| - // result = %ordinary_has_instance(C, O); |
| + // handler_result = %ordinary_has_instance(C, O); |
| // } else { |
| // handler_result = !!%_Call(handler_result, C, O); |
| // } |
| @@ -6437,6 +6438,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, |
| return instanceof; |
| } |
| + |
| Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) { |
| auto factory = parser_->factory(); |
| auto avfactory = parser_->ast_value_factory(); |
| @@ -6458,6 +6460,7 @@ Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) { |
| return validate_var; |
| } |
| + |
| void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, |
| Variable* iterator, |
| Maybe<Variable*> input, |
| @@ -6563,8 +6566,117 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, |
| } |
| -// Runtime encoding of different completion modes. |
| -enum ForOfLoopBodyCompletion { BODY_COMPLETED, BODY_ABORTED, BODY_THREW }; |
| +void ParserTraits::FinalizeIteratorUse( |
| + Variable* completion, Expression* condition, Variable* iter, |
| + Block* iterator_use, Block* target) { |
| + if (!FLAG_harmony_iterator_close) return; |
| + |
| + // |
| + // This function adds two statements to [target], corresponding to the |
| + // following code: |
|
adamk
2016/03/08 01:57:07
It's somewhat confusing that this code contains a
neis
2016/03/08 13:40:10
Done.
|
| + // |
| + // completion = NORMAL; |
| + // try { |
| + // iterator_use |
| + // } catch(e) { |
| + // if (completion === ABRUPT) completion = THROW; |
| + // throw e; |
| + // } finally { |
| + // if (condition) { |
| + // #BuildIteratorCloseForCompletion(iter, completion) |
| + // } |
| + // } |
| + // |
| + |
| + const int nopos = RelocInfo::kNoPosition; |
| + auto factory = parser_->factory(); |
|
adamk
2016/03/08 01:57:07
If you put this function in Parser instead of Pars
|
| + auto avfactory = parser_->ast_value_factory(); |
| + auto scope = parser_->scope_; |
| + auto zone = parser_->zone(); |
| + |
| + // completion = NORMAL; |
| + Statement* initialize_completion; |
| + { |
| + Expression* proxy = factory->NewVariableProxy(completion); |
| + Expression* assignment = factory->NewAssignment( |
| + Token::ASSIGN, proxy, |
| + factory->NewSmiLiteral(Parser::NORMAL, nopos), nopos); |
| + initialize_completion = |
| + factory->NewExpressionStatement(assignment, nopos); |
| + } |
| + |
| + // if (completion === ABRUPT) completion = THROW; |
| + Statement* set_completion_throw; |
| + { |
| + Expression* condition = factory->NewCompareOperation( |
| + Token::EQ_STRICT, factory->NewVariableProxy(completion), |
| + factory->NewSmiLiteral(Parser::ABRUPT, nopos), nopos); |
| + |
| + Expression* proxy = factory->NewVariableProxy(completion); |
| + Expression* assignment = factory->NewAssignment( |
| + Token::ASSIGN, proxy, factory->NewSmiLiteral(Parser::THROW, nopos), |
| + nopos); |
| + Statement* statement = factory->NewExpressionStatement(assignment, nopos); |
| + set_completion_throw = factory->NewIfStatement( |
| + condition, statement, factory->NewEmptyStatement(nopos), nopos); |
| + } |
| + |
| + // if (condition) { |
| + // #BuildIteratorCloseForCompletion(iter, completion) |
| + // } |
| + Block* maybe_close; |
| + { |
| + Block* block = factory->NewBlock(nullptr, 2, true, nopos); |
| + parser_->BuildIteratorCloseForCompletion( |
| + block->statements(), iter, completion); |
| + DCHECK(block->statements()->length() == 2); |
| + |
| + maybe_close = factory->NewBlock(nullptr, 1, true, nopos); |
| + maybe_close->statements()->Add(factory->NewIfStatement( |
| + condition, block, factory->NewEmptyStatement(nopos), nopos), zone); |
| + } |
| + |
| + // try { #try_block } |
| + // catch(e) { |
| + // #set_completion_throw; |
| + // throw e; |
| + // } |
| + Statement* try_catch; |
| + { |
| + Scope* catch_scope = parser_->NewScope(scope, CATCH_SCOPE); |
| + Variable* catch_variable = catch_scope->DeclareLocal( |
| + avfactory->dot_catch_string(), VAR, kCreatedInitialized, |
| + Variable::NORMAL); |
| + |
| + Statement* rethrow; |
| + { |
| + Expression* proxy = factory->NewVariableProxy(catch_variable); |
| + rethrow = factory->NewExpressionStatement( |
| + factory->NewThrow(proxy, nopos), nopos); |
| + } |
| + |
| + Block* catch_block = factory->NewBlock(nullptr, 2, false, nopos); |
| + catch_block->statements()->Add(set_completion_throw, zone); |
| + catch_block->statements()->Add(rethrow, zone); |
| + |
| + try_catch = factory->NewTryCatchStatement( |
| + iterator_use, catch_scope, catch_variable, catch_block, nopos); |
| + } |
| + |
| + // try { #try_catch } finally { #maybe_close } |
| + Statement* try_finally; |
| + { |
| + Block* try_block = factory->NewBlock(nullptr, 1, false, nopos); |
| + try_block->statements()->Add(try_catch, zone); |
| + |
| + try_finally = |
| + factory->NewTryFinallyStatement(try_block, maybe_close, nopos); |
| + } |
| + |
| + target->statements()->Add(initialize_completion, zone); |
| + target->statements()->Add(try_finally, zone); |
| +} |
| + |
| void ParserTraits::BuildIteratorCloseForCompletion( |
| ZoneList<Statement*>* statements, Variable* iterator, |
| @@ -6575,7 +6687,7 @@ void ParserTraits::BuildIteratorCloseForCompletion( |
| // |
| // let iteratorReturn = iterator.return; |
| // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { |
| - // if (completion === BODY_THREW) { |
| + // if (completion === THROW) { |
| // if (!IS_CALLABLE(iteratorReturn)) { |
| // throw MakeTypeError(kReturnMethodNotCallable); |
| // } |
| @@ -6693,7 +6805,7 @@ void ParserTraits::BuildIteratorCloseForCompletion( |
| validate_return->statements()->Add(check_return, zone); |
| } |
| - // if (completion === BODY_THREW) { |
| + // if (completion === THROW) { |
| // #check_return_callable; |
| // #try_call_return; |
| // } else { |
| @@ -6703,7 +6815,7 @@ void ParserTraits::BuildIteratorCloseForCompletion( |
| { |
| Expression* condition = factory->NewCompareOperation( |
| Token::EQ_STRICT, factory->NewVariableProxy(completion), |
| - factory->NewSmiLiteral(BODY_THREW, nopos), nopos); |
| + factory->NewSmiLiteral(Parser::THROW, nopos), nopos); |
| Block* then_block = factory->NewBlock(nullptr, 2, false, nopos); |
| then_block->statements()->Add(check_return_callable, zone); |
| @@ -6737,15 +6849,15 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
| // |
| // This function replaces the loop with the following wrapping: |
| // |
| - // let completion = BODY_COMPLETED; |
| // let each; |
| + // let completion = NORMAL; |
| // try { |
| // #loop; |
| // } catch(e) { |
| - // if (completion === BODY_ABORTED) completion = BODY_THREW; |
| + // if (completion === ABRUPT) completion = THROW; |
| // throw e; |
| // } finally { |
| - // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) { |
| + // if (!(completion === NORMAL || IS_UNDEFINED(#iterator))) { |
| // #BuildIteratorCloseForCompletion(#iterator, completion) |
| // } |
| // } |
| @@ -6754,15 +6866,16 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
| // |
| // { |
| // #loop-body |
| - // {{completion = BODY_COMPLETED;}} |
| + // {{completion = NORMAL;}} |
| // } |
| // |
| - // and assign_each is wrapped as follows |
| + // and the loop's assign_each is wrapped as follows |
| // |
| // do { |
| - // {{completion = BODY_ABORTED;}} |
| + // {{completion = ABRUPT;}} |
| // #assign-each |
| - // } into each |
| + // } |
| + // |
| const int nopos = RelocInfo::kNoPosition; |
| auto factory = parser_->factory(); |
| @@ -6770,17 +6883,7 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
| auto scope = parser_->scope_; |
| auto zone = parser_->zone(); |
| - // let completion = BODY_COMPLETED; |
| Variable* var_completion = scope->NewTemporary(avfactory->empty_string()); |
| - Statement* initialize_completion; |
| - { |
| - Expression* proxy = factory->NewVariableProxy(var_completion); |
| - Expression* assignment = factory->NewAssignment( |
| - Token::ASSIGN, proxy, |
| - factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos); |
| - initialize_completion = |
| - factory->NewExpressionStatement(assignment, nopos); |
| - } |
| // let each; |
| Variable* var_each = scope->NewTemporary(avfactory->empty_string()); |
| @@ -6794,104 +6897,27 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
| factory->NewExpressionStatement(assignment, nopos); |
| } |
| - // if (completion === BODY_ABORTED) completion = BODY_THREW; |
| - Statement* set_completion_throw; |
| + // !(completion === NORMAL || IS_UNDEFINED(#iterator)) |
| + Expression* condition; |
|
adamk
2016/03/07 20:28:05
Can you give this a better name? Maybe "iterator_c
neis
2016/03/08 13:40:10
Done.
|
| { |
| - Expression* condition = factory->NewCompareOperation( |
| + Expression* lhs = factory->NewCompareOperation( |
| Token::EQ_STRICT, factory->NewVariableProxy(var_completion), |
| - factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos); |
| - |
| - Expression* proxy = factory->NewVariableProxy(var_completion); |
| - Expression* assignment = factory->NewAssignment( |
| - Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_THREW, nopos), |
| - nopos); |
| - Statement* statement = factory->NewExpressionStatement(assignment, nopos); |
| - set_completion_throw = factory->NewIfStatement( |
| - condition, statement, factory->NewEmptyStatement(nopos), nopos); |
| - } |
| - |
| - // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) { |
| - // #BuildIteratorCloseForCompletion(#iterator, completion) |
| - // } |
| - Block* maybe_close; |
| - { |
| - Expression* condition1 = factory->NewCompareOperation( |
| - Token::EQ_STRICT, factory->NewVariableProxy(var_completion), |
| - factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos); |
| - Expression* condition2 = factory->NewCompareOperation( |
| + factory->NewSmiLiteral(Parser::NORMAL, nopos), nopos); |
| + Expression* rhs = factory->NewCompareOperation( |
| Token::EQ_STRICT, factory->NewVariableProxy(loop->iterator()), |
| factory->NewUndefinedLiteral(nopos), nopos); |
| - Expression* condition = factory->NewBinaryOperation( |
| - Token::OR, condition1, condition2, nopos); |
| - |
| - Block* block = factory->NewBlock(nullptr, 2, false, nopos); |
| - BuildIteratorCloseForCompletion( |
| - block->statements(), loop->iterator(), var_completion); |
| - DCHECK(block->statements()->length() == 2); |
| - |
| - maybe_close = factory->NewBlock(nullptr, 1, false, nopos); |
| - maybe_close->statements()->Add(factory->NewIfStatement( |
| - condition, factory->NewEmptyStatement(nopos), block, nopos), zone); |
| - } |
| - |
| - // try { #try_block } |
| - // catch(e) { |
| - // #set_completion_throw; |
| - // throw e; |
| - // } |
| - Statement* try_catch; |
| - { |
| - Scope* catch_scope = NewScope(scope, CATCH_SCOPE); |
| - Variable* catch_variable = catch_scope->DeclareLocal( |
| - avfactory->dot_catch_string(), VAR, kCreatedInitialized, |
| - Variable::NORMAL); |
| - |
| - Statement* rethrow; |
| - { |
| - Expression* proxy = factory->NewVariableProxy(catch_variable); |
| - rethrow = factory->NewExpressionStatement( |
| - factory->NewThrow(proxy, nopos), nopos); |
| - } |
| - |
| - Block* try_block = factory->NewBlock(nullptr, 1, false, nopos); |
| - try_block->statements()->Add(loop, zone); |
| - |
| - Block* catch_block = factory->NewBlock(nullptr, 2, false, nopos); |
| - catch_block->statements()->Add(set_completion_throw, zone); |
| - catch_block->statements()->Add(rethrow, zone); |
| - |
| - try_catch = factory->NewTryCatchStatement( |
| - try_block, catch_scope, catch_variable, catch_block, nopos); |
| - } |
| - |
| - // try { #try_catch } finally { #maybe_close } |
| - Statement* try_finally; |
| - { |
| - Block* try_block = factory->NewBlock(nullptr, 1, false, nopos); |
| - try_block->statements()->Add(try_catch, zone); |
| - |
| - try_finally = |
| - factory->NewTryFinallyStatement(try_block, maybe_close, nopos); |
| - } |
| - |
| - // #initialize_completion; |
| - // #initialize_each; |
| - // #try_finally; |
| - Statement* final_loop; |
| - { |
| - Block* block = factory->NewBlock(nullptr, 2, false, nopos); |
| - block->statements()->Add(initialize_completion, zone); |
| - block->statements()->Add(initialize_each, zone); |
| - block->statements()->Add(try_finally, zone); |
| - final_loop = block; |
| + condition = factory->NewUnaryOperation( |
| + Token::NOT, |
| + factory->NewBinaryOperation(Token::OR, lhs, rhs, nopos), |
| + nopos); |
| } |
| - // {{completion = BODY_COMPLETED;}} |
| + // {{completion = NORMAL;}} |
| Statement* set_completion_normal; |
| { |
| Expression* proxy = factory->NewVariableProxy(var_completion); |
| Expression* assignment = factory->NewAssignment( |
| - Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_COMPLETED, nopos), |
| + Token::ASSIGN, proxy, factory->NewSmiLiteral(Parser::NORMAL, nopos), |
| nopos); |
| Block* block = factory->NewBlock(nullptr, 1, true, nopos); |
| @@ -6900,36 +6926,53 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
| set_completion_normal = block; |
| } |
| - // { #loop-body; #set_completion_normal } |
| - Block* new_body = factory->NewBlock(nullptr, 2, false, nopos); |
| - new_body->statements()->Add(loop->body(), zone); |
| - new_body->statements()->Add(set_completion_normal, zone); |
| - |
| - loop->set_body(new_body); |
| - |
| - // {{completion = BODY_ABORTED;}} |
| - Statement* set_completion_break; |
| + // {{completion = ABRUPT;}} |
| + Statement* set_completion_abrupt; |
| { |
| Expression* proxy = factory->NewVariableProxy(var_completion); |
| Expression* assignment = factory->NewAssignment( |
| - Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_ABORTED, nopos), |
| + Token::ASSIGN, proxy, factory->NewSmiLiteral(Parser::ABRUPT, nopos), |
| nopos); |
| Block* block = factory->NewBlock(nullptr, 1, true, nopos); |
| block->statements()->Add(factory->NewExpressionStatement(assignment, nopos), |
| zone); |
| - set_completion_break = block; |
| + set_completion_abrupt = block; |
| } |
| - // { #set_completion_break; #assign-each } |
| + // { #loop-body; #set_completion_normal } |
| + Block* new_body = factory->NewBlock(nullptr, 2, false, nopos); |
| + { |
| + new_body->statements()->Add(loop->body(), zone); |
| + new_body->statements()->Add(set_completion_normal, zone); |
| + } |
| + |
| + // { #set_completion_abrupt; #assign-each } |
| Block* new_assign_each = factory->NewBlock(nullptr, 2, false, nopos); |
| - new_assign_each->statements()->Add(set_completion_break, zone); |
| - new_assign_each->statements()->Add( |
| - factory->NewExpressionStatement(loop->assign_each(), nopos), zone); |
| + { |
| + new_assign_each->statements()->Add(set_completion_abrupt, zone); |
| + new_assign_each->statements()->Add( |
| + factory->NewExpressionStatement(loop->assign_each(), nopos), zone); |
| + } |
| - Expression* do_each = |
| - factory->NewDoExpression(new_assign_each, var_each, nopos); |
| - loop->set_assign_each(do_each); |
| + // Now put things together. |
| + |
| + loop->set_body(new_body); |
| + loop->set_assign_each( |
| + factory->NewDoExpression(new_assign_each, var_each, nopos)); |
| + |
| + Statement* final_loop; |
| + { |
| + Block* target = factory->NewBlock(nullptr, 3, false, nopos); |
| + target->statements()->Add(initialize_each, zone); |
| + |
| + Block* try_block = factory->NewBlock(nullptr, 1, false, nopos); |
| + try_block->statements()->Add(loop, zone); |
| + |
| + FinalizeIteratorUse( |
| + var_completion, condition, loop->iterator(), try_block, target); |
| + final_loop = target; |
| + } |
| return final_loop; |
| } |