Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index cd7691efc6471fb04537166c23331427701f4578..288187e6091fd2ddb28864d41cfcb884ffcf4821 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -6239,6 +6239,191 @@ Expression* ParserTraits::RewriteYieldStar( |
| return yield_star; |
| } |
| +// Desugaring of (lhs) instanceof (rhs) |
| +// ==================== |
|
rossberg
2016/02/12 14:11:31
Nit: underline all of it?
mvstanton
2016/02/18 02:12:17
Done.
|
| +// |
| +// 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; |
| +// let result; |
| +// if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck); |
| +// let handler = C[Symbol.hasInstance]; |
| +// if (handler === undefined) { |
| +// result = %ordinary_has_instance(C, O); |
|
mvstanton
2016/02/18 02:12:17
I had to add an IS_CALLABLE check here, because %o
|
| +// } else { |
| +// if (!%IsCallable(handler)) { |
|
rossberg
2016/02/12 14:11:32
Is this actually necessary? %_Call would throw the
mvstanton
2016/02/18 02:12:17
Indeed, I was able to remove it, thanks!
|
| +// throw MakeTypeError(kFoundNonCallableHasInstance); |
| +// } |
| +// result = !!(%_Call(handler, C, O)); |
| +// } |
| +// } |
|
rossberg
2016/02/12 14:11:31
result; as the last statement?
mvstanton
2016/02/18 02:12:17
Done.
|
| +// |
| +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); |
| + } |
| + |
| + Statement* skip = factory->NewEmptyStatement(nopos); |
|
rossberg
2016/02/12 14:11:31
It looks like you are using this AST node twice. T
mvstanton
2016/02/18 02:12:17
Done.
|
| + |
| + // if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck); |
| + Statement* validate_C; |
| + { |
| + Expression* is_receiver_call; |
| + { |
| + auto args = new (zone) ZoneList<Expression*>(1, zone); |
| + args->Add(factory->NewVariableProxy(var_C), zone); |
| + is_receiver_call = |
| + factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos); |
| + } |
| + |
| + Statement* throw_call; |
| + { |
| + Expression* call = |
| + NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck, |
| + avfactory->empty_string(), nopos); |
| + throw_call = factory->NewExpressionStatement(call, nopos); |
| + } |
| + |
| + validate_C = |
| + factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos); |
| + } |
| + |
| + Variable* var_result = scope->NewTemporary(avfactory->empty_string()); |
|
rossberg
2016/02/12 14:11:32
Nit: you can probably reuse the same temporary for
mvstanton
2016/02/18 02:12:17
Done.
|
| + |
| + // let handler = C[Symbol.hasInstance]; |
| + Variable* var_handler = 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); |
| + Expression* assignment = |
| + factory->NewAssignment(Token::ASSIGN, handler_proxy, prop, nopos); |
| + initialize_handler = factory->NewExpressionStatement(assignment, nopos); |
| + } |
| + |
| + // if (handler === undefined) { |
| + // result = %ordinary_has_instance(C, O); |
| + // } else { |
| + // result = !!%_Call(handler, C, O); |
| + // } |
| + Statement* call_handler; |
| + { |
| + Expression* condition = factory->NewCompareOperation( |
| + Token::EQ_STRICT, factory->NewVariableProxy(var_handler), |
| + factory->NewUndefinedLiteral(nopos), nopos); |
| + Statement* then_side; |
| + { |
| + 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_result); |
| + Expression* assignment = |
| + factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos); |
| + then_side = factory->NewExpressionStatement(assignment, nopos); |
| + } |
| + Statement* else_side; |
| + { |
| + Block* block = factory->NewBlock(nullptr, 2, true, nopos); |
| + |
| + // if (!%IsCallable(handler)) { |
| + // throw MakeTypeError(kFoundNonCallableHasInstance); |
| + // } |
| + Statement* validate_handler; |
| + { |
| + Expression* is_callable_call; |
| + { |
| + auto args = new (zone) ZoneList<Expression*>(1, zone); |
| + args->Add(factory->NewVariableProxy(var_handler), zone); |
| + is_callable_call = |
| + factory->NewCallRuntime(Runtime::kIsCallable, args, nopos); |
| + } |
| + |
| + Statement* throw_call; |
| + { |
| + Expression* call = |
| + NewThrowTypeError(MessageTemplate::kFoundNonCallableHasInstance, |
| + avfactory->empty_string(), nopos); |
| + throw_call = factory->NewExpressionStatement(call, nopos); |
| + } |
| + |
| + validate_handler = |
| + factory->NewIfStatement(is_callable_call, skip, throw_call, nopos); |
| + } |
| + |
| + auto args = new (zone) ZoneList<Expression*>(3, zone); |
| + args->Add(factory->NewVariableProxy(var_handler), 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_result); |
| + Expression* assignment = |
| + factory->NewAssignment(Token::ASSIGN, result_proxy, outer_not, nopos); |
| + Statement* assignment_return = |
| + factory->NewExpressionStatement(assignment, nopos); |
| + |
| + block->statements()->Add(validate_handler, zone); |
| + block->statements()->Add(assignment_return, zone); |
| + |
| + else_side = block; |
| + } |
| + 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_result, nopos); |
| + Rewriter::Rewrite(parser_, instanceof, avfactory); |
| + } |
| + |
| + return instanceof; |
| +} |
| void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, |
| Variable* iterator, |