| Index: src/parsing/parser.cc
|
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
|
| index d926e92d770079fd24f5feefb3f67d4968d06672..8005479a32670b05c34eef744975b0d47d86af17 100644
|
| --- a/src/parsing/parser.cc
|
| +++ b/src/parsing/parser.cc
|
| @@ -6292,6 +6292,185 @@ 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):
|
| +//
|
| +// do {
|
| +// let O = lhs;
|
| +// let C = rhs;
|
| +// if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
|
| +// let handler_result = C[Symbol.hasInstance];
|
| +// if (handler_result === undefined) {
|
| +// if (!IS_CALLABLE(C)) {
|
| +// throw MakeTypeError(kCalledNonCallableInstanceOf);
|
| +// }
|
| +// handler_result = %ordinary_has_instance(C, O);
|
| +// } else {
|
| +// handler_result = !!(%_Call(handler_result, C, O));
|
| +// }
|
| +// handler_result;
|
| +// }
|
| +//
|
| +Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
|
| + 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();
|
| +
|
| + // let O = lhs;
|
| + Variable* var_O = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* get_O;
|
| + {
|
| + Expression* O_proxy = factory->NewVariableProxy(var_O);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, O_proxy, lhs, nopos);
|
| + get_O = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // let C = lhs;
|
| + Variable* var_C = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* get_C;
|
| + {
|
| + Expression* C_proxy = factory->NewVariableProxy(var_C);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, C_proxy, rhs, nopos);
|
| + get_C = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
|
| + Statement* validate_C;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_C), zone);
|
| + Expression* is_receiver_call =
|
| + factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
|
| + Expression* call =
|
| + NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck,
|
| + avfactory->empty_string(), nopos);
|
| + Statement* throw_call = factory->NewExpressionStatement(call, nopos);
|
| +
|
| + validate_C =
|
| + factory->NewIfStatement(is_receiver_call,
|
| + factory->NewEmptyStatement(nopos),
|
| + throw_call,
|
| + nopos);
|
| + }
|
| +
|
| + // let handler_result = C[Symbol.hasInstance];
|
| + Variable* var_handler_result = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* initialize_handler;
|
| + {
|
| + Expression* hasInstance_symbol_literal =
|
| + factory->NewSymbolLiteral("hasInstance_symbol", RelocInfo::kNoPosition);
|
| + Expression* prop = factory->NewProperty(factory->NewVariableProxy(var_C),
|
| + hasInstance_symbol_literal, pos);
|
| + Expression* handler_proxy = factory->NewVariableProxy(var_handler_result);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, handler_proxy, prop, nopos);
|
| + initialize_handler = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // if (handler_result === undefined) {
|
| + // if (!IS_CALLABLE(C)) {
|
| + // throw MakeTypeError(kCalledNonCallableInstanceOf);
|
| + // }
|
| + // result = %ordinary_has_instance(C, O);
|
| + // } else {
|
| + // handler_result = !!%_Call(handler_result, C, O);
|
| + // }
|
| + Statement* call_handler;
|
| + {
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result),
|
| + factory->NewUndefinedLiteral(nopos), nopos);
|
| +
|
| + Block* then_side = factory->NewBlock(nullptr, 2, false, nopos);
|
| + {
|
| + Expression* throw_expr =
|
| + NewThrowTypeError(MessageTemplate::kCalledNonCallableInstanceOf,
|
| + avfactory->empty_string(), nopos);
|
| + Statement* validate_C = CheckCallable(var_C, throw_expr);
|
| + ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone);
|
| + args->Add(factory->NewVariableProxy(var_C), zone);
|
| + args->Add(factory->NewVariableProxy(var_O), zone);
|
| + CallRuntime* call = factory->NewCallRuntime(
|
| + Context::ORDINARY_HAS_INSTANCE_INDEX, args, pos);
|
| + Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos);
|
| + Statement* assignment_return =
|
| + factory->NewExpressionStatement(assignment, nopos);
|
| +
|
| + then_side->statements()->Add(validate_C, zone);
|
| + then_side->statements()->Add(assignment_return, zone);
|
| + }
|
| +
|
| + Statement* else_side;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(3, zone);
|
| + args->Add(factory->NewVariableProxy(var_handler_result), zone);
|
| + args->Add(factory->NewVariableProxy(var_C), zone);
|
| + args->Add(factory->NewVariableProxy(var_O), zone);
|
| + Expression* call =
|
| + factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
|
| + Expression* inner_not =
|
| + factory->NewUnaryOperation(Token::NOT, call, nopos);
|
| + Expression* outer_not =
|
| + factory->NewUnaryOperation(Token::NOT, inner_not, nopos);
|
| + Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
|
| + Expression* assignment =
|
| + factory->NewAssignment(Token::ASSIGN, result_proxy, outer_not, nopos);
|
| +
|
| + else_side = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| + call_handler =
|
| + factory->NewIfStatement(condition, then_side, else_side, nopos);
|
| + }
|
| +
|
| + // do { ... }
|
| + DoExpression* instanceof;
|
| + {
|
| + Block* block = factory->NewBlock(nullptr, 5, true, nopos);
|
| + block->statements()->Add(get_O, zone);
|
| + block->statements()->Add(get_C, zone);
|
| + block->statements()->Add(validate_C, zone);
|
| + block->statements()->Add(initialize_handler, zone);
|
| + block->statements()->Add(call_handler, zone);
|
| +
|
| + // Here is the desugared instanceof.
|
| + instanceof = factory->NewDoExpression(block, var_handler_result, nopos);
|
| + Rewriter::Rewrite(parser_, instanceof, avfactory);
|
| + }
|
| +
|
| + return instanceof;
|
| +}
|
| +
|
| +Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) {
|
| + auto factory = parser_->factory();
|
| + auto avfactory = parser_->ast_value_factory();
|
| + const int nopos = RelocInfo::kNoPosition;
|
| + Statement* validate_var;
|
| + {
|
| + Expression* type_of = factory->NewUnaryOperation(
|
| + Token::TYPEOF, factory->NewVariableProxy(var), nopos);
|
| + Expression* function_literal =
|
| + factory->NewStringLiteral(avfactory->function_string(), nopos);
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ_STRICT, type_of, function_literal, nopos);
|
| +
|
| + Statement* throw_call = factory->NewExpressionStatement(error, nopos);
|
| +
|
| + validate_var = factory->NewIfStatement(
|
| + condition, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| + }
|
| + return validate_var;
|
| +}
|
|
|
| void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
|
| Variable* iterator,
|
| @@ -6440,20 +6619,10 @@ void ParserTraits::BuildIteratorCloseForCompletion(
|
| // }
|
| Statement* check_return_callable;
|
| {
|
| - Expression* type_of = factory->NewUnaryOperation(
|
| - Token::TYPEOF, factory->NewVariableProxy(var_return), nopos);
|
| - Expression* function_literal = factory->NewStringLiteral(
|
| - avfactory->function_string(), nopos);
|
| - Expression* condition = factory->NewCompareOperation(
|
| - Token::EQ_STRICT, type_of, function_literal, nopos);
|
| -
|
| - Expression* call = NewThrowTypeError(
|
| + Expression* throw_expr = NewThrowTypeError(
|
| MessageTemplate::kReturnMethodNotCallable,
|
| avfactory->empty_string(), nopos);
|
| - Statement* throw_call = factory->NewExpressionStatement(call, nopos);
|
| -
|
| - check_return_callable = factory->NewIfStatement(
|
| - condition, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| + check_return_callable = CheckCallable(var_return, throw_expr);
|
| }
|
|
|
| // output = %_Call(iteratorReturn, iterator);
|
|
|