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, |