Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(370)

Unified Diff: src/parsing/parser.cc

Issue 1692713005: ES6: Desugaring of instanceof to support @@hasInstance (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@blah
Patch Set: Fixed todos. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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,

Powered by Google App Engine
This is Rietveld 408576698