2015-05-11 16:28:28 +00:00
|
|
|
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/ast/ast.h"
|
2015-05-18 08:34:05 +00:00
|
|
|
#include "src/messages.h"
|
2017-01-09 13:43:28 +00:00
|
|
|
#include "src/objects-inl.h"
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/parsing/parameter-initializer-rewriter.h"
|
|
|
|
#include "src/parsing/parser.h"
|
2015-05-11 16:28:28 +00:00
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
2015-05-15 09:56:31 +00:00
|
|
|
void Parser::PatternRewriter::DeclareAndInitializeVariables(
|
2016-08-31 08:31:36 +00:00
|
|
|
Parser* parser, Block* block,
|
|
|
|
const DeclarationDescriptor* declaration_descriptor,
|
2015-05-15 09:56:31 +00:00
|
|
|
const DeclarationParsingResult::Declaration* declaration,
|
|
|
|
ZoneList<const AstRawString*>* names, bool* ok) {
|
|
|
|
PatternRewriter rewriter;
|
2015-05-11 16:28:28 +00:00
|
|
|
|
2016-03-08 09:35:11 +00:00
|
|
|
DCHECK(block->ignore_completion_value());
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
rewriter.scope_ = declaration_descriptor->scope;
|
2016-08-31 08:31:36 +00:00
|
|
|
rewriter.parser_ = parser;
|
2015-12-04 17:20:10 +00:00
|
|
|
rewriter.context_ = BINDING;
|
2015-05-15 09:56:31 +00:00
|
|
|
rewriter.pattern_ = declaration->pattern;
|
|
|
|
rewriter.initializer_position_ = declaration->initializer_position;
|
|
|
|
rewriter.block_ = block;
|
|
|
|
rewriter.descriptor_ = declaration_descriptor;
|
|
|
|
rewriter.names_ = names;
|
|
|
|
rewriter.ok_ = ok;
|
2015-12-22 13:28:34 +00:00
|
|
|
rewriter.recursion_level_ = 0;
|
2015-05-11 16:28:28 +00:00
|
|
|
|
2015-05-15 09:56:31 +00:00
|
|
|
rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::RewriteDestructuringAssignment(
|
2016-02-19 15:58:57 +00:00
|
|
|
Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
|
2016-11-24 09:47:57 +00:00
|
|
|
DCHECK(!scope->HasBeenRemoved());
|
2015-12-04 17:20:10 +00:00
|
|
|
DCHECK(!to_rewrite->is_rewritten());
|
|
|
|
|
2015-12-11 19:38:57 +00:00
|
|
|
bool ok = true;
|
2016-11-24 09:47:57 +00:00
|
|
|
|
|
|
|
PatternRewriter rewriter;
|
2015-12-04 17:20:10 +00:00
|
|
|
rewriter.scope_ = scope;
|
|
|
|
rewriter.parser_ = parser;
|
|
|
|
rewriter.context_ = ASSIGNMENT;
|
|
|
|
rewriter.pattern_ = to_rewrite;
|
|
|
|
rewriter.block_ = nullptr;
|
|
|
|
rewriter.descriptor_ = nullptr;
|
|
|
|
rewriter.names_ = nullptr;
|
2015-12-11 19:38:57 +00:00
|
|
|
rewriter.ok_ = &ok;
|
2015-12-22 13:28:34 +00:00
|
|
|
rewriter.recursion_level_ = 0;
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
rewriter.RecurseIntoSubpattern(rewriter.pattern_, nullptr);
|
2015-12-11 19:38:57 +00:00
|
|
|
DCHECK(ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Expression* Parser::PatternRewriter::RewriteDestructuringAssignment(
|
|
|
|
Parser* parser, Assignment* assignment, Scope* scope) {
|
|
|
|
DCHECK_NOT_NULL(assignment);
|
|
|
|
DCHECK_EQ(Token::ASSIGN, assignment->op());
|
2016-02-19 15:58:57 +00:00
|
|
|
auto to_rewrite = parser->factory()->NewRewritableExpression(assignment);
|
2015-12-11 19:38:57 +00:00
|
|
|
RewriteDestructuringAssignment(parser, to_rewrite, scope);
|
|
|
|
return to_rewrite->expression();
|
2015-12-04 17:20:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Parser::PatternRewriter::PatternContext
|
|
|
|
Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) {
|
|
|
|
PatternContext old_context = context();
|
2016-04-07 13:25:24 +00:00
|
|
|
// AssignmentExpressions may occur in the Initializer position of a
|
|
|
|
// SingleNameBinding. Such expressions should not prompt a change in the
|
|
|
|
// pattern's context.
|
|
|
|
if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN &&
|
|
|
|
!IsInitializerContext()) {
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(ASSIGNMENT);
|
|
|
|
}
|
|
|
|
return old_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Parser::PatternRewriter::PatternContext
|
|
|
|
Parser::PatternRewriter::SetInitializerContextIfNeeded(Expression* node) {
|
|
|
|
// Set appropriate initializer context for BindingElement and
|
|
|
|
// AssignmentElement nodes
|
|
|
|
PatternContext old_context = context();
|
|
|
|
bool is_destructuring_assignment =
|
2016-02-19 15:58:57 +00:00
|
|
|
node->IsRewritableExpression() &&
|
|
|
|
!node->AsRewritableExpression()->is_rewritten();
|
2015-12-04 17:20:10 +00:00
|
|
|
bool is_assignment =
|
|
|
|
node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN;
|
|
|
|
if (is_destructuring_assignment || is_assignment) {
|
|
|
|
switch (old_context) {
|
|
|
|
case BINDING:
|
|
|
|
set_context(INITIALIZER);
|
|
|
|
break;
|
|
|
|
case ASSIGNMENT:
|
|
|
|
set_context(ASSIGNMENT_INITIALIZER);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return old_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-11 16:28:28 +00:00
|
|
|
void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
|
|
|
Expression* value = current_value_;
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
if (IsAssignmentContext()) {
|
|
|
|
// In an assignment context, simply perform the assignment
|
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, pattern, value, pattern->position());
|
|
|
|
block_->statements()->Add(
|
2015-12-22 08:20:47 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, pattern->position()),
|
2015-12-04 17:20:10 +00:00
|
|
|
zone());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-30 20:22:23 +00:00
|
|
|
descriptor_->scope->RemoveUnresolved(pattern);
|
2015-05-11 16:28:28 +00:00
|
|
|
|
|
|
|
// Declare variable.
|
|
|
|
// Note that we *always* must treat the initial value via a separate init
|
|
|
|
// assignment for variables and constants because the value must be assigned
|
|
|
|
// when the variable is encountered in the source. But the variable/constant
|
|
|
|
// is declared (and set to 'undefined') upon entering the function within
|
|
|
|
// which the variable or constant is declared. Only function variables have
|
|
|
|
// an initial value in the declaration (because they are initialized upon
|
|
|
|
// entering the function).
|
|
|
|
const AstRawString* name = pattern->raw_name();
|
2016-10-27 11:03:06 +00:00
|
|
|
VariableProxy* proxy =
|
|
|
|
factory()->NewVariableProxy(name, NORMAL_VARIABLE, pattern->position());
|
2015-05-11 16:28:28 +00:00
|
|
|
Declaration* declaration = factory()->NewVariableDeclaration(
|
2016-08-10 08:10:18 +00:00
|
|
|
proxy, descriptor_->scope, descriptor_->declaration_pos);
|
2017-02-01 16:55:21 +00:00
|
|
|
|
|
|
|
// When an extra declaration scope needs to be inserted to account for
|
|
|
|
// a sloppy eval in a default parameter or function body, the parameter
|
|
|
|
// needs to be declared in the function's scope, not in the varblock
|
|
|
|
// scope which will be used for the initializer expression.
|
|
|
|
Scope* outer_function_scope = nullptr;
|
|
|
|
if (DeclaresParameterContainingSloppyEval()) {
|
|
|
|
outer_function_scope = descriptor_->scope->outer_scope();
|
|
|
|
}
|
2016-09-07 08:47:48 +00:00
|
|
|
Variable* var = parser_->Declare(
|
|
|
|
declaration, descriptor_->declaration_kind, descriptor_->mode,
|
|
|
|
Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
|
2017-02-01 16:55:21 +00:00
|
|
|
outer_function_scope);
|
2015-05-11 16:28:28 +00:00
|
|
|
if (!*ok_) return;
|
|
|
|
DCHECK_NOT_NULL(var);
|
2016-08-10 08:10:18 +00:00
|
|
|
DCHECK(proxy->is_resolved());
|
2016-06-30 09:26:30 +00:00
|
|
|
DCHECK(initializer_position_ != kNoSourcePosition);
|
2016-08-09 08:48:34 +00:00
|
|
|
var->set_initializer_position(initializer_position_);
|
2015-05-15 09:56:31 +00:00
|
|
|
|
2017-02-01 16:55:21 +00:00
|
|
|
Scope* declaration_scope =
|
|
|
|
outer_function_scope != nullptr
|
|
|
|
? outer_function_scope
|
|
|
|
: (IsLexicalVariableMode(descriptor_->mode)
|
|
|
|
? descriptor_->scope
|
|
|
|
: descriptor_->scope->GetDeclarationScope());
|
2016-07-13 19:28:56 +00:00
|
|
|
if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
|
2015-12-04 17:20:10 +00:00
|
|
|
parser_->ReportMessage(MessageTemplate::kTooManyVariables);
|
2015-05-11 16:28:28 +00:00
|
|
|
*ok_ = false;
|
|
|
|
return;
|
|
|
|
}
|
2015-05-15 09:56:31 +00:00
|
|
|
if (names_) {
|
|
|
|
names_->Add(name, zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
2016-08-08 19:18:20 +00:00
|
|
|
// If there's no initializer, we're done.
|
|
|
|
if (value == nullptr) return;
|
|
|
|
|
2017-02-10 13:24:49 +00:00
|
|
|
Scope* var_init_scope = descriptor_->scope;
|
2017-02-07 20:43:17 +00:00
|
|
|
MarkLoopVariableAsAssigned(var_init_scope, proxy->var());
|
|
|
|
|
2016-08-08 19:18:20 +00:00
|
|
|
// A declaration of the form:
|
2015-05-11 16:28:28 +00:00
|
|
|
//
|
|
|
|
// var v = x;
|
|
|
|
//
|
|
|
|
// is syntactic sugar for:
|
|
|
|
//
|
|
|
|
// var v; v = x;
|
|
|
|
//
|
2016-08-08 19:18:20 +00:00
|
|
|
// In particular, we need to re-lookup 'v' as it may be a different
|
|
|
|
// 'v' than the 'v' in the declaration (e.g., if we are inside a
|
|
|
|
// 'with' statement or 'catch' block). Global var declarations
|
|
|
|
// also need special treatment.
|
|
|
|
|
|
|
|
if (descriptor_->mode == VAR && var_init_scope->is_script_scope()) {
|
|
|
|
// Global variable declarations must be compiled in a specific
|
|
|
|
// way. When the script containing the global variable declaration
|
|
|
|
// is entered, the global variable must be declared, so that if it
|
|
|
|
// doesn't exist (on the global object itself, see ES5 errata) it
|
|
|
|
// gets created with an initial undefined value. This is handled
|
|
|
|
// by the declarations part of the function representing the
|
|
|
|
// top-level global code; see Runtime::DeclareGlobalVariable. If
|
|
|
|
// it already exists (in the object or in a prototype), it is
|
|
|
|
// *not* touched until the variable declaration statement is
|
|
|
|
// executed.
|
|
|
|
//
|
|
|
|
// Executing the variable declaration statement will always
|
|
|
|
// guarantee to give the global object an own property.
|
|
|
|
// This way, global variable declarations can shadow
|
|
|
|
// properties in the prototype chain, but only after the variable
|
|
|
|
// declaration statement has been executed. This is important in
|
|
|
|
// browsers where the global object (window) has lots of
|
|
|
|
// properties defined in prototype objects.
|
|
|
|
|
2015-05-11 16:28:28 +00:00
|
|
|
ZoneList<Expression*>* arguments =
|
|
|
|
new (zone()) ZoneList<Expression*>(3, zone());
|
2015-05-21 17:47:07 +00:00
|
|
|
arguments->Add(
|
|
|
|
factory()->NewStringLiteral(name, descriptor_->declaration_pos),
|
|
|
|
zone());
|
2016-08-08 19:18:20 +00:00
|
|
|
arguments->Add(factory()->NewNumberLiteral(var_init_scope->language_mode(),
|
|
|
|
kNoSourcePosition),
|
|
|
|
zone());
|
|
|
|
arguments->Add(value, zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
|
2016-08-08 19:18:20 +00:00
|
|
|
CallRuntime* initialize = factory()->NewCallRuntime(
|
|
|
|
Runtime::kInitializeVarGlobal, arguments, value->position());
|
|
|
|
block_->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(initialize, initialize->position()),
|
|
|
|
zone());
|
|
|
|
} else {
|
2016-04-14 01:00:22 +00:00
|
|
|
// For 'let' and 'const' declared variables the initialization always
|
|
|
|
// assigns to the declared variable.
|
2016-08-08 19:18:20 +00:00
|
|
|
// But for var declarations we need to do a new lookup.
|
|
|
|
if (descriptor_->mode == VAR) {
|
|
|
|
proxy = var_init_scope->NewUnresolved(factory(), name);
|
|
|
|
} else {
|
|
|
|
DCHECK_NOT_NULL(proxy);
|
|
|
|
DCHECK_NOT_NULL(proxy->var());
|
|
|
|
}
|
2015-12-22 13:28:34 +00:00
|
|
|
// Add break location for destructured sub-pattern.
|
2016-03-07 13:39:49 +00:00
|
|
|
int pos = IsSubPattern() ? pattern->position() : value->position();
|
2015-12-22 13:28:34 +00:00
|
|
|
Assignment* assignment =
|
|
|
|
factory()->NewAssignment(Token::INIT, proxy, value, pos);
|
2015-10-01 13:59:36 +00:00
|
|
|
block_->statements()->Add(
|
2015-12-22 13:28:34 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, pos), zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:29:50 +00:00
|
|
|
Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
|
2015-12-04 17:20:10 +00:00
|
|
|
auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
|
2015-05-20 08:08:26 +00:00
|
|
|
if (value != nullptr) {
|
|
|
|
auto assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(temp), value,
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition);
|
2015-05-18 20:15:08 +00:00
|
|
|
|
2015-10-01 13:59:36 +00:00
|
|
|
block_->statements()->Add(
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition),
|
2015-05-20 08:08:26 +00:00
|
|
|
zone());
|
|
|
|
}
|
2015-05-19 14:29:50 +00:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2015-05-18 20:15:08 +00:00
|
|
|
|
2016-02-19 15:58:57 +00:00
|
|
|
void Parser::PatternRewriter::VisitRewritableExpression(
|
|
|
|
RewritableExpression* node) {
|
|
|
|
// If this is not a destructuring assignment...
|
2016-09-02 07:52:18 +00:00
|
|
|
if (!IsAssignmentContext()) {
|
2016-02-19 15:58:57 +00:00
|
|
|
// Mark the node as rewritten to prevent redundant rewriting, and
|
2015-12-04 17:20:10 +00:00
|
|
|
// perform BindingPattern rewriting
|
|
|
|
DCHECK(!node->is_rewritten());
|
|
|
|
node->Rewrite(node->expression());
|
2016-07-15 07:56:06 +00:00
|
|
|
return Visit(node->expression());
|
2016-09-02 07:52:18 +00:00
|
|
|
} else if (!node->expression()->IsAssignment()) {
|
|
|
|
return Visit(node->expression());
|
2015-12-04 17:20:10 +00:00
|
|
|
}
|
2015-05-19 16:27:21 +00:00
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
if (node->is_rewritten()) return;
|
|
|
|
DCHECK(IsAssignmentContext());
|
|
|
|
Assignment* assign = node->expression()->AsAssignment();
|
|
|
|
DCHECK_NOT_NULL(assign);
|
|
|
|
DCHECK_EQ(Token::ASSIGN, assign->op());
|
|
|
|
|
|
|
|
auto initializer = assign->value();
|
|
|
|
auto value = initializer;
|
|
|
|
|
|
|
|
if (IsInitializerContext()) {
|
|
|
|
// let {<pattern> = <init>} = <value>
|
|
|
|
// becomes
|
|
|
|
// temp = <value>;
|
|
|
|
// <pattern> = temp === undefined ? <init> : temp;
|
|
|
|
auto temp_var = CreateTempVar(current_value_);
|
|
|
|
Expression* is_undefined = factory()->NewCompareOperation(
|
|
|
|
Token::EQ_STRICT, factory()->NewVariableProxy(temp_var),
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
|
2015-12-04 17:20:10 +00:00
|
|
|
value = factory()->NewConditional(is_undefined, initializer,
|
|
|
|
factory()->NewVariableProxy(temp_var),
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition);
|
2015-12-04 17:20:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
|
|
|
|
int pos = assign->position();
|
|
|
|
Block* old_block = block_;
|
2016-03-08 09:35:11 +00:00
|
|
|
block_ = factory()->NewBlock(nullptr, 8, true, pos);
|
2015-12-04 17:20:10 +00:00
|
|
|
Variable* temp = nullptr;
|
|
|
|
Expression* pattern = assign->target();
|
|
|
|
Expression* old_value = current_value_;
|
|
|
|
current_value_ = value;
|
|
|
|
if (pattern->IsObjectLiteral()) {
|
|
|
|
VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
|
|
|
|
} else {
|
|
|
|
DCHECK(pattern->IsArrayLiteral());
|
|
|
|
VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
|
|
|
|
}
|
|
|
|
DCHECK_NOT_NULL(temp);
|
|
|
|
current_value_ = old_value;
|
|
|
|
Expression* expr = factory()->NewDoExpression(block_, temp, pos);
|
|
|
|
node->Rewrite(expr);
|
|
|
|
block_ = old_block;
|
|
|
|
if (block_) {
|
|
|
|
block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
|
|
|
|
zone());
|
|
|
|
}
|
2017-01-10 03:07:32 +00:00
|
|
|
set_context(old_context);
|
2015-12-04 17:20:10 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 16:55:21 +00:00
|
|
|
bool Parser::PatternRewriter::DeclaresParameterContainingSloppyEval() const {
|
|
|
|
// Need to check for a binding context to make sure we have a descriptor.
|
|
|
|
if (IsBindingContext() &&
|
|
|
|
// Only relevant for parameters.
|
|
|
|
descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
|
|
|
|
// And only when scope is a block scope;
|
|
|
|
// without eval, it is a function scope.
|
|
|
|
scope()->is_block_scope()) {
|
|
|
|
DCHECK(scope()->calls_sloppy_eval());
|
|
|
|
DCHECK(scope()->is_declaration_scope());
|
|
|
|
DCHECK(scope()->outer_scope()->is_function_scope());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-22 23:28:10 +00:00
|
|
|
// When an extra declaration scope needs to be inserted to account for
|
|
|
|
// a sloppy eval in a default parameter or function body, the expressions
|
|
|
|
// needs to be in that new inner scope which was added after initial
|
|
|
|
// parsing.
|
2016-06-23 20:47:00 +00:00
|
|
|
void Parser::PatternRewriter::RewriteParameterScopes(Expression* expr) {
|
2017-02-01 16:55:21 +00:00
|
|
|
if (DeclaresParameterContainingSloppyEval()) {
|
|
|
|
ReparentParameterExpressionScope(parser_->stack_limit(), expr, scope());
|
|
|
|
}
|
2016-06-23 20:47:00 +00:00
|
|
|
}
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
|
|
|
|
Variable** temp_var) {
|
|
|
|
auto temp = *temp_var = CreateTempVar(current_value_);
|
|
|
|
|
2017-01-18 01:05:17 +00:00
|
|
|
ZoneList<Expression*>* rest_runtime_callargs = nullptr;
|
|
|
|
if (pattern->has_rest_property()) {
|
|
|
|
// non_rest_properties_count = pattern->properties()->length - 1;
|
|
|
|
// args_length = 1 + non_rest_properties_count because we need to
|
|
|
|
// pass temp as well to the runtime function.
|
|
|
|
int args_length = pattern->properties()->length();
|
|
|
|
rest_runtime_callargs =
|
|
|
|
new (zone()) ZoneList<Expression*>(args_length, zone());
|
|
|
|
rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
|
|
|
|
}
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
|
2015-05-18 20:15:08 +00:00
|
|
|
|
2015-05-11 16:28:28 +00:00
|
|
|
for (ObjectLiteralProperty* property : *pattern->properties()) {
|
2015-12-04 17:20:10 +00:00
|
|
|
PatternContext context = SetInitializerContextIfNeeded(property->value());
|
2017-01-18 01:05:17 +00:00
|
|
|
Expression* value;
|
|
|
|
|
|
|
|
if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
|
|
|
|
// var { y, [x++]: a, ...c } = temp
|
|
|
|
// becomes
|
2017-01-21 01:09:47 +00:00
|
|
|
// var y = temp.y;
|
|
|
|
// var temp1 = %ToName(x++);
|
|
|
|
// var a = temp[temp1];
|
2017-01-18 01:05:17 +00:00
|
|
|
// var c;
|
2017-01-21 01:09:47 +00:00
|
|
|
// c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
|
2017-01-18 01:05:17 +00:00
|
|
|
value = factory()->NewCallRuntime(
|
|
|
|
Runtime::kCopyDataPropertiesWithExcludedProperties,
|
|
|
|
rest_runtime_callargs, kNoSourcePosition);
|
|
|
|
} else {
|
|
|
|
Expression* key = property->key();
|
|
|
|
|
|
|
|
if (!key->IsLiteral()) {
|
|
|
|
// Computed property names contain expressions which might require
|
|
|
|
// scope rewriting.
|
|
|
|
RewriteParameterScopes(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pattern->has_rest_property()) {
|
2017-01-21 01:09:47 +00:00
|
|
|
Expression* excluded_property = key;
|
|
|
|
|
|
|
|
if (property->is_computed_name()) {
|
|
|
|
DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
|
|
|
|
auto args = new (zone()) ZoneList<Expression*>(1, zone());
|
|
|
|
args->Add(key, zone());
|
|
|
|
auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
|
|
|
|
Runtime::kToName, args, kNoSourcePosition));
|
|
|
|
key = factory()->NewVariableProxy(to_name_key);
|
|
|
|
excluded_property = factory()->NewVariableProxy(to_name_key);
|
|
|
|
} else {
|
|
|
|
DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
|
|
|
|
}
|
2017-01-18 01:05:17 +00:00
|
|
|
|
|
|
|
DCHECK(rest_runtime_callargs != nullptr);
|
2017-01-21 01:09:47 +00:00
|
|
|
rest_runtime_callargs->Add(excluded_property, zone());
|
2017-01-18 01:05:17 +00:00
|
|
|
}
|
2016-06-23 20:47:00 +00:00
|
|
|
|
2017-01-18 01:05:17 +00:00
|
|
|
value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
|
|
|
|
kNoSourcePosition);
|
|
|
|
}
|
2016-06-23 20:47:00 +00:00
|
|
|
|
2017-01-18 01:05:17 +00:00
|
|
|
RecurseIntoSubpattern(property->value(), value);
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(context);
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
|
|
|
|
Variable* temp_var = nullptr;
|
|
|
|
VisitObjectLiteral(node, &temp_var);
|
|
|
|
}
|
|
|
|
|
2015-10-06 17:01:10 +00:00
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
|
|
|
|
Variable** temp_var) {
|
2016-03-10 09:33:29 +00:00
|
|
|
DCHECK(block_->ignore_completion_value());
|
2015-12-04 17:20:10 +00:00
|
|
|
|
2016-03-10 09:33:29 +00:00
|
|
|
auto temp = *temp_var = CreateTempVar(current_value_);
|
2017-02-15 19:39:06 +00:00
|
|
|
auto iterator = CreateTempVar(
|
|
|
|
factory()->NewGetIterator(factory()->NewVariableProxy(temp),
|
|
|
|
IteratorType::kNormal, kNoSourcePosition));
|
2016-06-30 09:26:30 +00:00
|
|
|
auto done =
|
|
|
|
CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
|
2015-05-20 08:08:26 +00:00
|
|
|
auto result = CreateTempVar();
|
|
|
|
auto v = CreateTempVar();
|
2016-03-10 09:33:29 +00:00
|
|
|
auto completion = CreateTempVar();
|
2016-06-30 09:26:30 +00:00
|
|
|
auto nopos = kNoSourcePosition;
|
2016-03-10 09:33:29 +00:00
|
|
|
|
|
|
|
// For the purpose of iterator finalization, we temporarily set block_ to a
|
|
|
|
// new block. In the main body of this function, we write to block_ (both
|
|
|
|
// explicitly and implicitly via recursion). At the end of the function, we
|
|
|
|
// wrap this new block in a try-finally statement, restore block_ to its
|
|
|
|
// original value, and add the try-finally statement to block_.
|
|
|
|
auto target = block_;
|
2016-06-24 01:11:08 +00:00
|
|
|
block_ = factory()->NewBlock(nullptr, 8, true, nopos);
|
2015-05-20 15:05:58 +00:00
|
|
|
|
|
|
|
Spread* spread = nullptr;
|
2015-05-20 08:08:26 +00:00
|
|
|
for (Expression* value : *node->values()) {
|
2015-05-20 15:05:58 +00:00
|
|
|
if (value->IsSpread()) {
|
|
|
|
spread = value->AsSpread();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
PatternContext context = SetInitializerContextIfNeeded(value);
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2015-05-20 08:08:26 +00:00
|
|
|
// if (!done) {
|
2016-03-10 09:33:29 +00:00
|
|
|
// done = true; // If .next, .done or .value throws, don't close.
|
2015-05-20 08:08:26 +00:00
|
|
|
// result = IteratorNext(iterator);
|
2016-03-10 19:11:02 +00:00
|
|
|
// if (result.done) {
|
|
|
|
// v = undefined;
|
|
|
|
// } else {
|
|
|
|
// v = result.value;
|
|
|
|
// done = false;
|
|
|
|
// }
|
2015-05-20 08:08:26 +00:00
|
|
|
// }
|
2016-03-10 19:11:02 +00:00
|
|
|
Statement* if_not_done;
|
2016-03-10 09:33:29 +00:00
|
|
|
{
|
2016-03-10 19:11:02 +00:00
|
|
|
auto result_done = factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(ast_value_factory()->done_string(),
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition),
|
|
|
|
kNoSourcePosition);
|
2016-03-10 19:11:02 +00:00
|
|
|
|
|
|
|
auto assign_undefined = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(v),
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
|
2016-03-10 19:11:02 +00:00
|
|
|
|
|
|
|
auto assign_value = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(v),
|
|
|
|
factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(ast_value_factory()->value_string(),
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition),
|
|
|
|
kNoSourcePosition),
|
|
|
|
kNoSourcePosition);
|
2016-03-10 19:11:02 +00:00
|
|
|
|
|
|
|
auto unset_done = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewBooleanLiteral(false, kNoSourcePosition),
|
|
|
|
kNoSourcePosition);
|
2016-03-10 19:11:02 +00:00
|
|
|
|
|
|
|
auto inner_else =
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewBlock(nullptr, 2, true, kNoSourcePosition);
|
2016-03-10 19:11:02 +00:00
|
|
|
inner_else->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(assign_value, nopos), zone());
|
|
|
|
inner_else->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(unset_done, nopos), zone());
|
|
|
|
|
|
|
|
auto inner_if = factory()->NewIfStatement(
|
|
|
|
result_done,
|
|
|
|
factory()->NewExpressionStatement(assign_undefined, nopos),
|
|
|
|
inner_else, nopos);
|
|
|
|
|
2016-03-10 09:33:29 +00:00
|
|
|
auto next_block =
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewBlock(nullptr, 3, true, kNoSourcePosition);
|
2016-03-10 09:33:29 +00:00
|
|
|
next_block->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewBooleanLiteral(true, nopos), nopos),
|
|
|
|
nopos),
|
|
|
|
zone());
|
|
|
|
next_block->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(
|
|
|
|
parser_->BuildIteratorNextResult(
|
|
|
|
factory()->NewVariableProxy(iterator), result,
|
2017-02-15 19:39:06 +00:00
|
|
|
IteratorType::kNormal, kNoSourcePosition),
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition),
|
2016-03-10 09:33:29 +00:00
|
|
|
zone());
|
2016-03-10 19:11:02 +00:00
|
|
|
next_block->statements()->Add(inner_if, zone());
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-03-10 19:11:02 +00:00
|
|
|
if_not_done = factory()->NewIfStatement(
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewUnaryOperation(
|
|
|
|
Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
|
|
|
|
next_block, factory()->NewEmptyStatement(kNoSourcePosition),
|
|
|
|
kNoSourcePosition);
|
2016-03-10 09:33:29 +00:00
|
|
|
}
|
2016-03-10 19:11:02 +00:00
|
|
|
block_->statements()->Add(if_not_done, zone());
|
2015-05-20 08:08:26 +00:00
|
|
|
|
|
|
|
if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
|
2016-06-24 01:11:08 +00:00
|
|
|
{
|
2016-03-10 09:33:29 +00:00
|
|
|
// completion = kAbruptCompletion;
|
|
|
|
Expression* proxy = factory()->NewVariableProxy(completion);
|
|
|
|
Expression* assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, proxy,
|
|
|
|
factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
|
|
|
|
block_->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(assignment, nopos), zone());
|
|
|
|
}
|
|
|
|
|
2015-05-20 08:08:26 +00:00
|
|
|
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-06-24 01:11:08 +00:00
|
|
|
{
|
2016-03-10 09:33:29 +00:00
|
|
|
// completion = kNormalCompletion;
|
|
|
|
Expression* proxy = factory()->NewVariableProxy(completion);
|
|
|
|
Expression* assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, proxy,
|
|
|
|
factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
|
|
|
|
block_->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(assignment, nopos), zone());
|
|
|
|
}
|
2015-05-20 08:08:26 +00:00
|
|
|
}
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(context);
|
2015-05-20 08:08:26 +00:00
|
|
|
}
|
2015-05-20 15:05:58 +00:00
|
|
|
|
|
|
|
if (spread != nullptr) {
|
2016-03-10 09:33:29 +00:00
|
|
|
// A spread can only occur as the last component. It is not handled by
|
|
|
|
// RecurseIntoSubpattern above.
|
|
|
|
|
|
|
|
// let array = [];
|
2016-04-05 08:56:07 +00:00
|
|
|
// while (!done) {
|
2016-04-28 09:59:53 +00:00
|
|
|
// done = true; // If .next, .done or .value throws, don't close.
|
2016-04-05 08:56:07 +00:00
|
|
|
// result = IteratorNext(iterator);
|
2016-04-28 09:59:53 +00:00
|
|
|
// if (!result.done) {
|
2016-04-05 08:56:07 +00:00
|
|
|
// %AppendElement(array, result.value);
|
2016-04-28 09:59:53 +00:00
|
|
|
// done = false;
|
2016-04-05 08:56:07 +00:00
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// let array = [];
|
|
|
|
Variable* array;
|
|
|
|
{
|
|
|
|
auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
|
2017-01-30 12:31:35 +00:00
|
|
|
array = CreateTempVar(
|
|
|
|
factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
|
2016-04-05 08:56:07 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 09:33:29 +00:00
|
|
|
// done = true;
|
2016-04-05 08:56:07 +00:00
|
|
|
Statement* set_done = factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewBooleanLiteral(true, nopos), nopos),
|
|
|
|
nopos);
|
|
|
|
|
2016-04-28 09:59:53 +00:00
|
|
|
// result = IteratorNext(iterator);
|
|
|
|
Statement* get_next = factory()->NewExpressionStatement(
|
|
|
|
parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
|
2017-02-15 19:39:06 +00:00
|
|
|
result, IteratorType::kNormal, nopos),
|
2016-04-28 09:59:53 +00:00
|
|
|
nopos);
|
|
|
|
|
2016-04-05 08:56:07 +00:00
|
|
|
// %AppendElement(array, result.value);
|
|
|
|
Statement* append_element;
|
|
|
|
{
|
|
|
|
auto args = new (zone()) ZoneList<Expression*>(2, zone());
|
|
|
|
args->Add(factory()->NewVariableProxy(array), zone());
|
|
|
|
args->Add(factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(
|
|
|
|
ast_value_factory()->value_string(), nopos),
|
|
|
|
nopos),
|
|
|
|
zone());
|
|
|
|
append_element = factory()->NewExpressionStatement(
|
|
|
|
factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
|
|
|
|
nopos);
|
|
|
|
}
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-04-28 09:59:53 +00:00
|
|
|
// done = false;
|
|
|
|
Statement* unset_done = factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewBooleanLiteral(false, nopos), nopos),
|
|
|
|
nopos);
|
|
|
|
|
|
|
|
// if (!result.done) { #append_element; #unset_done }
|
|
|
|
Statement* maybe_append_and_unset_done;
|
2016-04-05 08:56:07 +00:00
|
|
|
{
|
|
|
|
Expression* result_done =
|
|
|
|
factory()->NewProperty(factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(
|
|
|
|
ast_value_factory()->done_string(), nopos),
|
|
|
|
nopos);
|
2016-04-28 09:59:53 +00:00
|
|
|
|
|
|
|
Block* then = factory()->NewBlock(nullptr, 2, true, nopos);
|
|
|
|
then->statements()->Add(append_element, zone());
|
|
|
|
then->statements()->Add(unset_done, zone());
|
|
|
|
|
|
|
|
maybe_append_and_unset_done = factory()->NewIfStatement(
|
|
|
|
factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
|
|
|
|
factory()->NewEmptyStatement(nopos), nopos);
|
2016-04-05 08:56:07 +00:00
|
|
|
}
|
2015-05-20 15:05:58 +00:00
|
|
|
|
2016-04-05 08:56:07 +00:00
|
|
|
// while (!done) {
|
2016-04-28 09:59:53 +00:00
|
|
|
// #set_done;
|
2016-04-05 08:56:07 +00:00
|
|
|
// #get_next;
|
2016-04-28 09:59:53 +00:00
|
|
|
// #maybe_append_and_unset_done;
|
2016-04-05 08:56:07 +00:00
|
|
|
// }
|
|
|
|
WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
|
|
|
|
{
|
|
|
|
Expression* condition = factory()->NewUnaryOperation(
|
|
|
|
Token::NOT, factory()->NewVariableProxy(done), nopos);
|
2016-04-28 09:59:53 +00:00
|
|
|
Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
|
|
|
|
body->statements()->Add(set_done, zone());
|
2016-04-05 08:56:07 +00:00
|
|
|
body->statements()->Add(get_next, zone());
|
2016-04-28 09:59:53 +00:00
|
|
|
body->statements()->Add(maybe_append_and_unset_done, zone());
|
2016-04-05 08:56:07 +00:00
|
|
|
loop->Initialize(condition, body);
|
|
|
|
}
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-04-05 08:56:07 +00:00
|
|
|
block_->statements()->Add(loop, zone());
|
2015-05-20 15:05:58 +00:00
|
|
|
RecurseIntoSubpattern(spread->expression(),
|
|
|
|
factory()->NewVariableProxy(array));
|
|
|
|
}
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-06-24 01:11:08 +00:00
|
|
|
Expression* closing_condition = factory()->NewUnaryOperation(
|
|
|
|
Token::NOT, factory()->NewVariableProxy(done), nopos);
|
2016-11-24 09:47:57 +00:00
|
|
|
|
|
|
|
parser_->FinalizeIteratorUse(scope(), completion, closing_condition, iterator,
|
2017-02-15 19:39:06 +00:00
|
|
|
block_, target, IteratorType::kNormal);
|
2016-06-24 01:11:08 +00:00
|
|
|
block_ = target;
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
|
|
|
|
Variable* temp_var = nullptr;
|
|
|
|
VisitArrayLiteral(node, &temp_var);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-11 16:28:28 +00:00
|
|
|
void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
|
2015-05-19 14:29:50 +00:00
|
|
|
// let {<pattern> = <init>} = <value>
|
|
|
|
// becomes
|
|
|
|
// temp = <value>;
|
|
|
|
// <pattern> = temp === undefined ? <init> : temp;
|
2015-12-04 17:20:10 +00:00
|
|
|
DCHECK_EQ(Token::ASSIGN, node->op());
|
|
|
|
|
|
|
|
auto initializer = node->value();
|
|
|
|
auto value = initializer;
|
2015-05-19 14:29:50 +00:00
|
|
|
auto temp = CreateTempVar(current_value_);
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
if (IsInitializerContext()) {
|
|
|
|
Expression* is_undefined = factory()->NewCompareOperation(
|
|
|
|
Token::EQ_STRICT, factory()->NewVariableProxy(temp),
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
|
2015-12-04 17:20:10 +00:00
|
|
|
value = factory()->NewConditional(is_undefined, initializer,
|
|
|
|
factory()->NewVariableProxy(temp),
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition);
|
2015-10-21 12:04:10 +00:00
|
|
|
}
|
2015-12-04 17:20:10 +00:00
|
|
|
|
2016-06-23 20:47:00 +00:00
|
|
|
// Initializer may have been parsed in the wrong scope.
|
|
|
|
RewriteParameterScopes(initializer);
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
|
2015-05-19 14:29:50 +00:00
|
|
|
RecurseIntoSubpattern(node->target(), value);
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(old_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =============== AssignmentPattern only ==================
|
|
|
|
|
|
|
|
void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
|
|
|
|
DCHECK(IsAssignmentContext());
|
|
|
|
auto value = current_value_;
|
|
|
|
|
|
|
|
Assignment* assignment =
|
|
|
|
factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
|
|
|
|
|
|
|
|
block_->statements()->Add(
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =============== UNREACHABLE =============================
|
|
|
|
|
|
|
|
#define NOT_A_PATTERN(Node) \
|
|
|
|
void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
|
|
|
|
UNREACHABLE(); \
|
|
|
|
}
|
|
|
|
|
|
|
|
NOT_A_PATTERN(BinaryOperation)
|
|
|
|
NOT_A_PATTERN(Block)
|
|
|
|
NOT_A_PATTERN(BreakStatement)
|
|
|
|
NOT_A_PATTERN(Call)
|
|
|
|
NOT_A_PATTERN(CallNew)
|
|
|
|
NOT_A_PATTERN(CallRuntime)
|
|
|
|
NOT_A_PATTERN(CaseClause)
|
|
|
|
NOT_A_PATTERN(ClassLiteral)
|
|
|
|
NOT_A_PATTERN(CompareOperation)
|
|
|
|
NOT_A_PATTERN(Conditional)
|
|
|
|
NOT_A_PATTERN(ContinueStatement)
|
|
|
|
NOT_A_PATTERN(CountOperation)
|
|
|
|
NOT_A_PATTERN(DebuggerStatement)
|
2015-10-21 02:55:47 +00:00
|
|
|
NOT_A_PATTERN(DoExpression)
|
2015-05-11 16:28:28 +00:00
|
|
|
NOT_A_PATTERN(DoWhileStatement)
|
|
|
|
NOT_A_PATTERN(EmptyStatement)
|
2015-09-30 20:22:23 +00:00
|
|
|
NOT_A_PATTERN(EmptyParentheses)
|
2015-05-11 16:28:28 +00:00
|
|
|
NOT_A_PATTERN(ExpressionStatement)
|
|
|
|
NOT_A_PATTERN(ForInStatement)
|
|
|
|
NOT_A_PATTERN(ForOfStatement)
|
|
|
|
NOT_A_PATTERN(ForStatement)
|
|
|
|
NOT_A_PATTERN(FunctionDeclaration)
|
|
|
|
NOT_A_PATTERN(FunctionLiteral)
|
[ignition] desugar GetIterator() via bytecode rather than via AST
Introduces:
- a new AST node representing the GetIterator() algorithm in the specification, to be used by ForOfStatement, YieldExpression (in the case of delegating yield*), and the future `for-await-of` loop proposed in http://tc39.github.io/proposal-async-iteration/#sec-async-iterator-value-unwrap-functions.
- a new opcode (JumpIfJSReceiver), which is useful for `if Type(object) is not Object` checks which are common throughout the specification. This node is easily eliminated by TurboFan.
The AST node is desugared specially in bytecode, rather than manually when building the AST. The benefit of this is that desugaring in the BytecodeGenerator is much simpler and easier to understand than desugaring the AST.
This also reduces parse time very slightly, and allows us to use LoadIC rather than KeyedLoadIC, which seems to have better baseline performance. This results in a ~20% improvement in test/js-perf-test/Iterators micro-benchmarks, which I believe owes to the use of the slightly faster LoadIC as opposed to the KeyedLoadIC in the baseline case. Both produce identical optimized code via TurboFan when the type check can be eliminated, and the load can be replaced with a constant value.
BUG=v8:4280
R=bmeurer@chromium.org, rmcilroy@chromium.org, adamk@chromium.org, neis@chromium.org, jarin@chromium.org
TBR=rossberg@chromium.org
Review-Url: https://codereview.chromium.org/2557593004
Cr-Commit-Position: refs/heads/master@{#41555}
2016-12-07 15:19:52 +00:00
|
|
|
NOT_A_PATTERN(GetIterator)
|
2015-05-11 16:28:28 +00:00
|
|
|
NOT_A_PATTERN(IfStatement)
|
|
|
|
NOT_A_PATTERN(Literal)
|
|
|
|
NOT_A_PATTERN(NativeFunctionLiteral)
|
|
|
|
NOT_A_PATTERN(RegExpLiteral)
|
|
|
|
NOT_A_PATTERN(ReturnStatement)
|
2015-09-30 20:22:23 +00:00
|
|
|
NOT_A_PATTERN(SloppyBlockFunctionStatement)
|
|
|
|
NOT_A_PATTERN(Spread)
|
2015-06-02 22:04:25 +00:00
|
|
|
NOT_A_PATTERN(SuperPropertyReference)
|
|
|
|
NOT_A_PATTERN(SuperCallReference)
|
2015-05-11 16:28:28 +00:00
|
|
|
NOT_A_PATTERN(SwitchStatement)
|
|
|
|
NOT_A_PATTERN(ThisFunction)
|
|
|
|
NOT_A_PATTERN(Throw)
|
|
|
|
NOT_A_PATTERN(TryCatchStatement)
|
|
|
|
NOT_A_PATTERN(TryFinallyStatement)
|
|
|
|
NOT_A_PATTERN(UnaryOperation)
|
|
|
|
NOT_A_PATTERN(VariableDeclaration)
|
|
|
|
NOT_A_PATTERN(WhileStatement)
|
|
|
|
NOT_A_PATTERN(WithStatement)
|
|
|
|
NOT_A_PATTERN(Yield)
|
|
|
|
|
|
|
|
#undef NOT_A_PATTERN
|
2015-06-01 22:46:54 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|