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); |