Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index d8e7553ea5b37f20485eba0576a96bc9a008b406..833b4612b173786281e1c25bc0102cb71b1293b3 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -6288,6 +6288,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) { |
|
rossberg
2016/02/19 12:19:00
Given that my CL has landed, can you now change Fi
mvstanton
2016/02/19 18:15:59
Done.
|
| + 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, |