| Index: src/parsing/parser.cc
|
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
|
| index 1b5b7e6779be608e70c4fdc487871cc94bce30fd..c9b3d495a3699d4900e3ea24bee7af61632a282c 100644
|
| --- a/src/parsing/parser.cc
|
| +++ b/src/parsing/parser.cc
|
| @@ -5797,5 +5797,574 @@ void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
|
| }
|
|
|
|
|
| +// Desugaring of yield*
|
| +// ====================
|
| +//
|
| +// With the help of do-expressions and function.sent, we desugar yield* into a
|
| +// loop containing a "raw" yield (a yield that doesn't wrap an iterator result
|
| +// object around its argument). Concretely, "yield* iterable" turns into
|
| +// roughly the following code:
|
| +//
|
| +// do {
|
| +// const kNext = 0;
|
| +// const kReturn = 1;
|
| +// const kThrow = 2;
|
| +//
|
| +// let input = function.sent;
|
| +// let mode = kNext;
|
| +// let output = undefined;
|
| +//
|
| +// let iterator = iterable[Symbol.iterator]();
|
| +// if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
|
| +//
|
| +// while (true) {
|
| +// // From the generator to the iterator:
|
| +// // Forward input according to resume mode and obtain output.
|
| +// switch (mode) {
|
| +// case kNext:
|
| +// output = iterator.next(input);
|
| +// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
|
| +// break;
|
| +// case kReturn:
|
| +// IteratorClose(iterator, input); // See below.
|
| +// break;
|
| +// case kThrow:
|
| +// let iteratorThrow = iterator.throw;
|
| +// if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
|
| +// IteratorClose(iterator); // See below.
|
| +// throw MakeTypeError(kThrowMethodMissing);
|
| +// }
|
| +// output = %_Call(iteratorThrow, iterator, input);
|
| +// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
|
| +// break;
|
| +// }
|
| +// if (output.done) break;
|
| +//
|
| +// // From the generator to its user:
|
| +// // Forward output, receive new input, and determine resume mode.
|
| +// mode = kReturn;
|
| +// try {
|
| +// try {
|
| +// RawYield(output); // See explanation above.
|
| +// mode = kNext;
|
| +// } catch (error) {
|
| +// mode = kThrow;
|
| +// }
|
| +// } finally {
|
| +// input = function.sent;
|
| +// continue;
|
| +// }
|
| +// }
|
| +//
|
| +// output.value;
|
| +// }
|
| +//
|
| +// IteratorClose(iterator) expands to the following:
|
| +//
|
| +// let iteratorReturn = iterator.return;
|
| +// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return;
|
| +// let result = %_Call(iteratorReturn, iterator);
|
| +// if (!IS_RECEIVER(result)) %ThrowIterResultNotAnObject(result);
|
| +//
|
| +// IteratorClose(iterator, input) expands to the following:
|
| +//
|
| +// let iteratorReturn = iterator.return;
|
| +// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
|
| +// let result = %_Call(iteratorReturn, iterator, input);
|
| +// if (!IS_RECEIVER(result)) %ThrowIterResultNotAnObject(result);
|
| +
|
| +
|
| +Expression* ParserTraits::RewriteYieldStar(
|
| + Expression* generator, Expression* iterable, int pos) {
|
| +
|
| + const int nopos = RelocInfo::kNoPosition;
|
| +
|
| + auto factory = parser_->factory();
|
| + auto avfactory = parser_->ast_value_factory();
|
| + auto scope = parser_->scope_;
|
| + auto zone = parser_->zone();
|
| +
|
| + Statement* skip = factory->NewEmptyStatement(nopos);
|
| +
|
| + enum { kNext, kReturn, kThrow };
|
| + // TODO(neis): Use JSGenerator::ResumeMode once extended with RETURN.
|
| +
|
| + // Forward definition for break/continue statements.
|
| + WhileStatement* loop = factory->NewWhileStatement(nullptr, nopos);
|
| +
|
| +
|
| + // let input = undefined;
|
| + Variable* var_input = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* initialize_input;
|
| + {
|
| + Expression* input_proxy = factory->NewVariableProxy(var_input);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, input_proxy, factory->NewUndefinedLiteral(nopos), nopos);
|
| + initialize_input = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // let mode = kNext;
|
| + Variable* var_mode = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* initialize_mode;
|
| + {
|
| + Expression* mode_proxy = factory->NewVariableProxy(var_mode);
|
| + Expression* knext = factory->NewSmiLiteral(kNext, nopos);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
|
| + initialize_mode = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // let output = undefined;
|
| + Variable* var_output = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* initialize_output;
|
| + {
|
| + Expression* output_proxy = factory->NewVariableProxy(var_output);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, output_proxy, factory->NewUndefinedLiteral(nopos),
|
| + nopos);
|
| + initialize_output = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // let iterator = iterable[Symbol.iterator];
|
| + Variable* var_iterator = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* get_iterator;
|
| + {
|
| + Expression* iterator = GetIterator(iterable, factory, nopos);
|
| + Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, iterator_proxy, iterator, nopos);
|
| + get_iterator = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
|
| + Statement* validate_iterator;
|
| + {
|
| + Expression* is_receiver_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_iterator), zone);
|
| + is_receiver_call =
|
| + factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
|
| + }
|
| +
|
| + Statement* throw_call;
|
| + {
|
| + Expression* call = NewThrowTypeError(
|
| + MessageTemplate::kSymbolIteratorInvalid, avfactory->empty_string(),
|
| + nopos);
|
| + throw_call = factory->NewExpressionStatement(call, nopos);
|
| + }
|
| +
|
| + validate_iterator =
|
| + factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + }
|
| +
|
| +
|
| + // output = iterator.next(input);
|
| + Statement* call_next;
|
| + {
|
| + Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
|
| + Expression* literal =
|
| + factory->NewStringLiteral(avfactory->next_string(), nopos);
|
| + Expression* next_property =
|
| + factory->NewProperty(iterator_proxy, literal, nopos);
|
| + Expression* input_proxy = factory->NewVariableProxy(var_input);
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(input_proxy, zone);
|
| + Expression* call = factory->NewCall(next_property, args, nopos);
|
| + Expression* output_proxy = factory->NewVariableProxy(var_output);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
|
| + call_next = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
|
| + Statement* validate_next_output;
|
| + {
|
| + Expression* is_receiver_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| + is_receiver_call =
|
| + factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
|
| + }
|
| +
|
| + Statement* throw_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| + Expression* call = factory->NewCallRuntime(
|
| + Runtime::kThrowIteratorResultNotAnObject, args, nopos);
|
| + throw_call = factory->NewExpressionStatement(call, nopos);
|
| + }
|
| +
|
| + validate_next_output =
|
| + factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + }
|
| +
|
| +
|
| + // let iteratorThrow = iterator.throw;
|
| + Variable* var_throw = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* get_throw;
|
| + {
|
| + Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
|
| + Expression* literal =
|
| + factory->NewStringLiteral(avfactory->throw_string(), nopos);
|
| + Expression* property =
|
| + factory->NewProperty(iterator_proxy, literal, nopos);
|
| + Expression* throw_proxy = factory->NewVariableProxy(var_throw);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, throw_proxy, property, nopos);
|
| + get_throw = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // if (IS_NULL_OR_UNDEFINED(iteratorThrow) {
|
| + // IteratorClose(iterator);
|
| + // throw MakeTypeError(kThrowMethodMissing);
|
| + // }
|
| + Statement* check_throw;
|
| + {
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ, factory->NewVariableProxy(var_throw),
|
| + factory->NewNullLiteral(nopos), nopos);
|
| +
|
| + Expression* call = NewThrowTypeError(
|
| + MessageTemplate::kThrowMethodMissing,
|
| + avfactory->empty_string(), nopos);
|
| + Statement* throw_call = factory->NewExpressionStatement(call, nopos);
|
| +
|
| + Block* then = factory->NewBlock(nullptr, 4+1, false, nopos);
|
| + BuildIteratorClose(then->statements(), var_iterator, Nothing<Variable*>());
|
| + then->statements()->Add(throw_call, zone);
|
| + check_throw =
|
| + factory->NewIfStatement(condition, then, skip, nopos);
|
| + }
|
| +
|
| +
|
| + // output = %_Call(iteratorThrow, iterator, input);
|
| + Statement* call_throw;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(3, zone);
|
| + args->Add(factory->NewVariableProxy(var_throw), zone);
|
| + args->Add(factory->NewVariableProxy(var_iterator), zone);
|
| + args->Add(factory->NewVariableProxy(var_input), zone);
|
| + Expression* call =
|
| + factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
|
| + call_throw = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
|
| + Statement* validate_throw_output;
|
| + {
|
| + Expression* is_receiver_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| + is_receiver_call =
|
| + factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
|
| + }
|
| +
|
| + Statement* throw_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| + Expression* call = factory->NewCallRuntime(
|
| + Runtime::kThrowIteratorResultNotAnObject, args, nopos);
|
| + throw_call = factory->NewExpressionStatement(call, nopos);
|
| + }
|
| +
|
| + validate_throw_output =
|
| + factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + }
|
| +
|
| +
|
| + // if (output.done) break;
|
| + Statement* if_done;
|
| + {
|
| + Expression* output_proxy = factory->NewVariableProxy(var_output);
|
| + Expression* literal =
|
| + factory->NewStringLiteral(avfactory->done_string(), nopos);
|
| + Expression* property = factory->NewProperty(output_proxy, literal, nopos);
|
| + BreakStatement* break_loop = factory->NewBreakStatement(loop, nopos);
|
| + if_done = factory->NewIfStatement(property, break_loop, skip, nopos);
|
| + }
|
| +
|
| +
|
| + // mode = kReturn;
|
| + Statement* set_mode_return;
|
| + {
|
| + Expression* mode_proxy = factory->NewVariableProxy(var_mode);
|
| + Expression* kreturn = factory->NewSmiLiteral(kReturn, nopos);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, mode_proxy, kreturn, nopos);
|
| + set_mode_return = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // RawYield(output);
|
| + Statement* yield_output;
|
| + {
|
| + Expression* output_proxy = factory->NewVariableProxy(var_output);
|
| + Yield* yield = factory->NewYield(
|
| + generator, output_proxy, Yield::kInitial, nopos);
|
| + yield_output = factory->NewExpressionStatement(yield, nopos);
|
| + }
|
| +
|
| +
|
| + // mode = kNext;
|
| + Statement* set_mode_next;
|
| + {
|
| + Expression* mode_proxy = factory->NewVariableProxy(var_mode);
|
| + Expression* knext = factory->NewSmiLiteral(kNext, nopos);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
|
| + set_mode_next = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // mode = kThrow;
|
| + Statement* set_mode_throw;
|
| + {
|
| + Expression* mode_proxy = factory->NewVariableProxy(var_mode);
|
| + Expression* kthrow = factory->NewSmiLiteral(kThrow, nopos);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos);
|
| + set_mode_throw = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // input = function.sent;
|
| + Statement* get_input;
|
| + {
|
| + Expression* function_sent = FunctionSentExpression(scope, factory, nopos);
|
| + Expression* input_proxy = factory->NewVariableProxy(var_input);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, input_proxy, function_sent, nopos);
|
| + get_input = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| +
|
| + // output.value;
|
| + Statement* get_value;
|
| + {
|
| + Expression* output_proxy = factory->NewVariableProxy(var_output);
|
| + Expression* literal =
|
| + factory->NewStringLiteral(avfactory->value_string(), nopos);
|
| + Expression* property = factory->NewProperty(output_proxy, literal, nopos);
|
| + get_value = factory->NewExpressionStatement(property, nopos);
|
| + }
|
| +
|
| +
|
| + // Now put things together.
|
| +
|
| +
|
| + // try { ... } catch(e) { ... }
|
| + Statement* try_catch;
|
| + {
|
| + Block* try_block = factory->NewBlock(nullptr, 2, false, nopos);
|
| + try_block->statements()->Add(yield_output, zone);
|
| + try_block->statements()->Add(set_mode_next, zone);
|
| +
|
| + Block* catch_block = factory->NewBlock(nullptr, 1, false, nopos);
|
| + catch_block->statements()->Add(set_mode_throw, zone);
|
| +
|
| + Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
|
| + const AstRawString* name = avfactory->dot_catch_string();
|
| + Variable* catch_variable =
|
| + catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
|
| + Variable::NORMAL);
|
| +
|
| + try_catch = factory->NewTryCatchStatement(
|
| + try_block, catch_scope, catch_variable, catch_block, nopos);
|
| + }
|
| +
|
| +
|
| + // try { ... } finally { ... }
|
| + Statement* try_finally;
|
| + {
|
| + Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
|
| + try_block->statements()->Add(try_catch, zone);
|
| +
|
| + Block* finally = factory->NewBlock(nullptr, 2, false, nopos);
|
| + finally->statements()->Add(get_input, zone);
|
| + finally->statements()->Add(
|
| + factory->NewContinueStatement(loop, nopos), zone);
|
| +
|
| + try_finally = factory->NewTryFinallyStatement(try_block, finally, nopos);
|
| + }
|
| +
|
| +
|
| + // switch (mode) { ... }
|
| + SwitchStatement* switch_mode = factory->NewSwitchStatement(nullptr, nopos);
|
| + {
|
| + auto case_next = new (zone) ZoneList<Statement*>(3, zone);
|
| + case_next->Add(call_next, zone);
|
| + case_next->Add(validate_next_output, zone);
|
| + case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
|
| +
|
| + auto case_return = new (zone) ZoneList<Statement*>(5, zone);
|
| + BuildIteratorClose(case_return, var_iterator, Just(var_input));
|
| + case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
|
| +
|
| + auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
|
| + case_throw->Add(get_throw, zone);
|
| + case_throw->Add(check_throw, zone);
|
| + case_throw->Add(call_throw, zone);
|
| + case_throw->Add(validate_throw_output, zone);
|
| + case_throw->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
|
| +
|
| + auto cases = new (zone) ZoneList<CaseClause*>(3, zone);
|
| + Expression* knext = factory->NewSmiLiteral(kNext, nopos);
|
| + Expression* kreturn = factory->NewSmiLiteral(kReturn, nopos);
|
| + Expression* kthrow = factory->NewSmiLiteral(kThrow, nopos);
|
| + cases->Add(factory->NewCaseClause(knext, case_next, nopos), zone);
|
| + cases->Add(factory->NewCaseClause(kreturn, case_return, nopos), zone);
|
| + cases->Add(factory->NewCaseClause(kthrow, case_throw, nopos), zone);
|
| +
|
| + switch_mode->Initialize(factory->NewVariableProxy(var_mode), cases);
|
| + }
|
| +
|
| +
|
| + // while (true) { ... }
|
| + // Already defined earlier: WhileStatement* loop = ...
|
| + {
|
| + Block* loop_body = factory->NewBlock(nullptr, 4, false, nopos);
|
| + loop_body->statements()->Add(switch_mode, zone);
|
| + loop_body->statements()->Add(if_done, zone);
|
| + loop_body->statements()->Add(set_mode_return, zone);
|
| + loop_body->statements()->Add(try_finally, zone);
|
| +
|
| + loop->Initialize(factory->NewBooleanLiteral(true, nopos), loop_body);
|
| + }
|
| +
|
| +
|
| + // do { ... }
|
| + DoExpression* yield_star;
|
| + {
|
| + // The rewriter needs to process the get_value statement only, hence we
|
| + // put the preceding statements into an init block.
|
| +
|
| + Block* do_block_ = factory->NewBlock(nullptr, 6, true, nopos);
|
| + do_block_->statements()->Add(initialize_input, zone);
|
| + do_block_->statements()->Add(initialize_mode, zone);
|
| + do_block_->statements()->Add(initialize_output, zone);
|
| + do_block_->statements()->Add(get_iterator, zone);
|
| + do_block_->statements()->Add(validate_iterator, zone);
|
| + do_block_->statements()->Add(loop, zone);
|
| +
|
| + Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
|
| + do_block->statements()->Add(do_block_, zone);
|
| + do_block->statements()->Add(get_value, zone);
|
| +
|
| + Variable* dot_result = scope->NewTemporary(avfactory->dot_result_string());
|
| + yield_star = factory->NewDoExpression(do_block, dot_result, nopos);
|
| + Rewriter::Rewrite(parser_, yield_star, avfactory);
|
| + }
|
| +
|
| + return yield_star;
|
| +}
|
| +
|
| +
|
| +void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
|
| + Variable* iterator,
|
| + Maybe<Variable*> input) {
|
| + const int nopos = RelocInfo::kNoPosition;
|
| + auto factory = parser_->factory();
|
| + auto avfactory = parser_->ast_value_factory();
|
| + auto scope = parser_->scope_;
|
| + auto zone = parser_->zone();
|
| + Statement* skip = factory->NewEmptyStatement(nopos);
|
| +
|
| + // let iteratorReturn = iterator.return;
|
| + Variable* var = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* get_return;
|
| + {
|
| + Expression* iterator_proxy = factory->NewVariableProxy(iterator);
|
| + Expression* literal =
|
| + factory->NewStringLiteral(avfactory->return_string(), nopos);
|
| + Expression* property =
|
| + factory->NewProperty(iterator_proxy, literal, nopos);
|
| + Expression* return_proxy = factory->NewVariableProxy(var);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, return_proxy, property, nopos);
|
| + get_return = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return; OR
|
| + // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
|
| + Statement* check_return;
|
| + {
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ, factory->NewVariableProxy(var),
|
| + factory->NewNullLiteral(nopos), nopos);
|
| +
|
| + Expression* value = input.IsJust() ?
|
| + static_cast<Expression*>(factory->NewVariableProxy(input.FromJust())) :
|
| + factory->NewUndefinedLiteral(nopos);
|
| +
|
| + Statement* return_undefined = factory->NewReturnStatement(value, nopos);
|
| +
|
| + check_return =
|
| + factory->NewIfStatement(condition, return_undefined, skip, nopos);
|
| + }
|
| +
|
| + // let result = %_Call(iteratorReturn, iterator); OR
|
| + // let result = %_Call(iteratorReturn, iterator, input);
|
| + Statement* call_return;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(3, zone);
|
| + args->Add(factory->NewVariableProxy(var), zone);
|
| + args->Add(factory->NewVariableProxy(iterator), zone);
|
| + if (input.IsJust()) {
|
| + args->Add(factory->NewVariableProxy(input.FromJust()), zone);
|
| + }
|
| +
|
| + Expression* call =
|
| + factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, factory->NewVariableProxy(var), call, nopos);
|
| + call_return = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // if (!IS_RECEIVER(result)) %ThrowIterResultNotAnObject(result);
|
| + Statement* validate_result;
|
| + {
|
| + Expression* is_receiver_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var), zone);
|
| + is_receiver_call =
|
| + factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
|
| + }
|
| +
|
| + Statement* throw_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var), zone);
|
| + Expression* call = factory->NewCallRuntime(
|
| + Runtime::kThrowIteratorResultNotAnObject, args, nopos);
|
| + throw_call = factory->NewExpressionStatement(call, nopos);
|
| + }
|
| +
|
| + validate_result =
|
| + factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + }
|
| +
|
| + statements->Add(get_return, zone);
|
| + statements->Add(check_return, zone);
|
| + statements->Add(call_return, zone);
|
| + statements->Add(validate_result, zone);
|
| +}
|
| +
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|