aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/parsing/parser.cc
diff options
context:
space:
mode:
authorAli Ijaz Sheikh <ofrobots@google.com>2016-04-07 14:06:55 -0700
committerAli Ijaz Sheikh <ofrobots@google.com>2016-04-14 10:03:39 -0700
commit52af5c4eebf4de8638aef0338bd826656312a02a (patch)
tree628dc9fb0b558c3a73a2160706fef368876fe548 /deps/v8/src/parsing/parser.cc
parent6e3e8acc7cc7ebd3d67db5ade1247b8b558efe09 (diff)
downloadandroid-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.tar.gz
android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.tar.bz2
android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.zip
deps: upgrade V8 to 5.0.71.32
* Pick up the branch head for V8 5.0 stable [1] * Edit v8 gitignore to allow trace_event copy * Update V8 DEP trace_event as per deps/v8/DEPS [2] [1] https://chromium.googlesource.com/v8/v8.git/+/3c67831 [2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/4b09207e447ae5bd34643b4c6321bee7b76d35f9 Ref: https://github.com/nodejs/node/pull/5945 PR-URL: https://github.com/nodejs/node/pull/6111 Reviewed-By: targos - Michaƫl Zasso <mic.besace@gmail.com> Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com>
Diffstat (limited to 'deps/v8/src/parsing/parser.cc')
-rw-r--r--deps/v8/src/parsing/parser.cc2461
1 files changed, 1911 insertions, 550 deletions
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc
index b1b8c1316b..8005479a32 100644
--- a/deps/v8/src/parsing/parser.cc
+++ b/deps/v8/src/parsing/parser.cc
@@ -6,6 +6,7 @@
#include "src/api.h"
#include "src/ast/ast.h"
+#include "src/ast/ast-expression-rewriter.h"
#include "src/ast/ast-expression-visitor.h"
#include "src/ast/ast-literal-reindexer.h"
#include "src/ast/scopeinfo.h"
@@ -22,6 +23,7 @@
#include "src/parsing/scanner-character-streams.h"
#include "src/runtime/runtime.h"
#include "src/string-stream.h"
+#include "src/tracing/trace-event.h"
namespace v8 {
namespace internal {
@@ -178,15 +180,14 @@ void Parser::SetCachedData(ParseInfo* info) {
}
}
-
-FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
+FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
+ bool call_super, Scope* scope,
int pos, int end_pos,
LanguageMode language_mode) {
int materialized_literal_count = -1;
int expected_property_count = -1;
int parameter_count = 0;
- const AstRawString* name = ast_value_factory()->empty_string();
-
+ if (name == nullptr) name = ast_value_factory()->empty_string();
FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor
: FunctionKind::kDefaultBaseConstructor;
@@ -642,10 +643,16 @@ Expression* ParserTraits::NewTargetExpression(Scope* scope,
}
-Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope,
- int pos, int end_pos,
- LanguageMode mode) {
- return parser_->DefaultConstructor(call_super, scope, pos, end_pos, mode);
+Expression* ParserTraits::FunctionSentExpression(Scope* scope,
+ AstNodeFactory* factory,
+ int pos) {
+ // We desugar function.sent into %GeneratorGetInput(generator).
+ Zone* zone = parser_->zone();
+ ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(1, zone);
+ VariableProxy* generator = factory->NewVariableProxy(
+ parser_->function_state_->generator_object_variable());
+ args->Add(generator, zone);
+ return factory->NewCallRuntime(Runtime::kGeneratorGetInput, args, pos);
}
@@ -721,11 +728,10 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral(
const AstRawString* name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
return parser_->ParseFunctionLiteral(
name, function_name_location, function_name_validity, kind,
- function_token_position, type, arity_restriction, language_mode, ok);
+ function_token_position, type, language_mode, ok);
}
@@ -767,6 +773,7 @@ Parser::Parser(ParseInfo* info)
set_allow_legacy_const(FLAG_legacy_const);
set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
set_allow_harmony_function_name(FLAG_harmony_function_name);
+ set_allow_harmony_function_sent(FLAG_harmony_function_sent);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@@ -789,6 +796,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
DCHECK(parsing_on_main_thread_);
HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
+ TRACE_EVENT0("v8", "V8.Parse");
Handle<String> source(String::cast(info->script()->source()));
isolate->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
@@ -935,13 +943,9 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
if (ok) {
ParserTraits::RewriteDestructuringAssignments();
- result = factory()->NewFunctionLiteral(
- ast_value_factory()->empty_string(), scope_, body,
- function_state.materialized_literal_count(),
- function_state.expected_property_count(), 0,
- FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kGlobalOrEval, FunctionLiteral::kShouldLazyCompile,
- FunctionKind::kNormalFunction, 0);
+ result = factory()->NewScriptOrEvalFunctionLiteral(
+ scope_, body, function_state.materialized_literal_count(),
+ function_state.expected_property_count());
}
}
@@ -957,6 +961,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) {
// called in the main thread.
DCHECK(parsing_on_main_thread_);
HistogramTimerScope timer_scope(isolate->counters()->parse_lazy());
+ TRACE_EVENT0("v8", "V8.ParseLazy");
Handle<String> source(String::cast(info->script()->source()));
isolate->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
@@ -990,6 +995,18 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) {
return result;
}
+static FunctionLiteral::FunctionType ComputeFunctionType(
+ Handle<SharedFunctionInfo> shared_info) {
+ if (shared_info->is_declaration()) {
+ return FunctionLiteral::kDeclaration;
+ } else if (shared_info->is_named_expression()) {
+ return FunctionLiteral::kNamedExpression;
+ } else if (IsConciseMethod(shared_info->kind()) ||
+ IsAccessorFunction(shared_info->kind())) {
+ return FunctionLiteral::kAccessorOrMethod;
+ }
+ return FunctionLiteral::kAnonymousExpression;
+}
FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
Utf16CharacterStream* source) {
@@ -1028,11 +1045,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
is_strict(info->language_mode()));
DCHECK(info->language_mode() == shared_info->language_mode());
FunctionLiteral::FunctionType function_type =
- shared_info->is_expression()
- ? (shared_info->is_anonymous()
- ? FunctionLiteral::kAnonymousExpression
- : FunctionLiteral::kNamedExpression)
- : FunctionLiteral::kDeclaration;
+ ComputeFunctionType(shared_info);
bool ok = true;
if (shared_info->is_arrow()) {
@@ -1050,7 +1063,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
SetLanguageMode(scope, shared_info->language_mode());
scope->set_start_position(shared_info->start_position());
- ExpressionClassifier formals_classifier;
+ ExpressionClassifier formals_classifier(this);
ParserFormalParameters formals(scope);
Checkpoint checkpoint(this);
{
@@ -1096,15 +1109,15 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
}
}
} else if (shared_info->is_default_constructor()) {
- result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()),
- scope, shared_info->start_position(),
- shared_info->end_position(),
- shared_info->language_mode());
+ result = DefaultConstructor(
+ raw_name, IsSubclassConstructor(shared_info->kind()), scope,
+ shared_info->start_position(), shared_info->end_position(),
+ shared_info->language_mode());
} else {
- result = ParseFunctionLiteral(
- raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck,
- shared_info->kind(), RelocInfo::kNoPosition, function_type,
- FunctionLiteral::kNormalArity, shared_info->language_mode(), &ok);
+ result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
+ kSkipFunctionNameCheck, shared_info->kind(),
+ RelocInfo::kNoPosition, function_type,
+ shared_info->language_mode(), &ok);
}
// Make sure the results agree.
DCHECK(ok == (result != NULL));
@@ -1260,20 +1273,11 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
// Statement
// Declaration
- if (peek() != Token::CLASS) {
- // No more classes follow; reset the start position for the consecutive
- // class declaration group.
- scope_->set_class_declaration_group_start(-1);
- }
-
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
case Token::CLASS:
- if (scope_->class_declaration_group_start() < 0) {
- scope_->set_class_declaration_group_start(
- scanner()->peek_location().beg_pos);
- }
+ Consume(Token::CLASS);
return ParseClassDeclaration(NULL, ok);
case Token::CONST:
if (allow_const()) {
@@ -1345,7 +1349,6 @@ void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
}
}
- scope_->module()->Freeze();
return NULL;
}
@@ -1558,24 +1561,53 @@ Statement* Parser::ParseExportDefault(bool* ok) {
Expect(Token::DEFAULT, CHECK_OK);
Scanner::Location default_loc = scanner()->location();
+ const AstRawString* default_string = ast_value_factory()->default_string();
ZoneList<const AstRawString*> names(1, zone());
- Statement* result = NULL;
+ Statement* result = nullptr;
+ Expression* default_export = nullptr;
switch (peek()) {
- case Token::FUNCTION:
- // TODO(ES6): Support parsing anonymous function declarations here.
- result = ParseFunctionDeclaration(&names, CHECK_OK);
+ case Token::FUNCTION: {
+ Consume(Token::FUNCTION);
+ int pos = position();
+ bool is_generator = Check(Token::MUL);
+ if (peek() == Token::LPAREN) {
+ // FunctionDeclaration[+Default] ::
+ // 'function' '(' FormalParameters ')' '{' FunctionBody '}'
+ //
+ // GeneratorDeclaration[+Default] ::
+ // 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
+ default_export = ParseFunctionLiteral(
+ default_string, Scanner::Location::invalid(),
+ kSkipFunctionNameCheck,
+ is_generator ? FunctionKind::kGeneratorFunction
+ : FunctionKind::kNormalFunction,
+ pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
+ result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ } else {
+ result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK);
+ }
break;
+ }
case Token::CLASS:
- // TODO(ES6): Support parsing anonymous class declarations here.
- result = ParseClassDeclaration(&names, CHECK_OK);
+ Consume(Token::CLASS);
+ if (peek() == Token::EXTENDS || peek() == Token::LBRACE) {
+ // ClassDeclaration[+Default] ::
+ // 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
+ default_export =
+ ParseClassLiteral(default_string, Scanner::Location::invalid(),
+ false, position(), CHECK_OK);
+ result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ } else {
+ result = ParseClassDeclaration(&names, CHECK_OK);
+ }
break;
default: {
int pos = peek_position();
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
Expression* expr = ParseAssignmentExpression(true, &classifier, CHECK_OK);
- expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
ExpectSemicolon(CHECK_OK);
result = factory()->NewExpressionStatement(expr, pos);
@@ -1583,19 +1615,18 @@ Statement* Parser::ParseExportDefault(bool* ok) {
}
}
- const AstRawString* default_string = ast_value_factory()->default_string();
-
DCHECK_LE(names.length(), 1);
if (names.length() == 1) {
scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
if (!*ok) {
ParserTraits::ReportMessageAt(
default_loc, MessageTemplate::kDuplicateExport, default_string);
- return NULL;
+ return nullptr;
}
} else {
// TODO(ES6): Assign result to a const binding with the name "*default*"
// and add an export entry with "*default*" as the local name.
+ USE(default_export);
}
return result;
@@ -1686,6 +1717,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
break;
case Token::CLASS:
+ Consume(Token::CLASS);
result = ParseClassDeclaration(&names, CHECK_OK);
break;
@@ -1921,42 +1953,44 @@ Variable* Parser::Declare(Declaration* declaration,
if (var == NULL) {
// Declare the name.
Variable::Kind kind = Variable::NORMAL;
- int declaration_group_start = -1;
if (is_function_declaration) {
kind = Variable::FUNCTION;
- } else if (declaration->IsVariableDeclaration() &&
- declaration->AsVariableDeclaration()->is_class_declaration()) {
- kind = Variable::CLASS;
- declaration_group_start =
- declaration->AsVariableDeclaration()->declaration_group_start();
}
var = declaration_scope->DeclareLocal(
- name, mode, declaration->initialization(), kind, kNotAssigned,
- declaration_group_start);
- } else if (((IsLexicalVariableMode(mode) ||
- IsLexicalVariableMode(var->mode())) &&
- // Allow duplicate function decls for web compat, see bug 4693.
- (is_strict(language_mode()) || !is_function_declaration ||
- !var->is_function())) ||
- ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
- !declaration_scope->is_script_scope())) {
- // The name was declared in this scope before; check for conflicting
- // re-declarations. We have a conflict if either of the declarations is
- // not a var (in script scope, we also have to ignore legacy const for
- // compatibility). There is similar code in runtime.cc in the Declare
- // functions. The function CheckConflictingVarDeclarations checks for
- // var and let bindings from different scopes whereas this is a check for
- // conflicting declarations within the same scope. This check also covers
- // the special case
- //
- // function () { let x; { var x; } }
- //
- // because the var declaration is hoisted to the function scope where 'x'
- // is already bound.
- DCHECK(IsDeclaredVariableMode(var->mode()));
- if (is_strict(language_mode()) ||
- (allow_harmony_sloppy() && mode != CONST_LEGACY &&
- var->mode() != CONST_LEGACY)) {
+ name, mode, declaration->initialization(), kind, kNotAssigned);
+ } else if ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
+ !declaration_scope->is_script_scope()) {
+ // Duplicate legacy const definitions throw at runtime.
+ DCHECK(is_sloppy(language_mode()));
+ Expression* expression = NewThrowSyntaxError(
+ MessageTemplate::kVarRedeclaration, name, declaration->position());
+ declaration_scope->SetIllegalRedeclaration(expression);
+ } else if ((IsLexicalVariableMode(mode) ||
+ IsLexicalVariableMode(var->mode())) &&
+ // Lexical bindings may appear for some parameters in sloppy
+ // mode even with --harmony-sloppy off.
+ (is_strict(language_mode()) || allow_harmony_sloppy())) {
+ // Allow duplicate function decls for web compat, see bug 4693.
+ if (is_sloppy(language_mode()) && is_function_declaration &&
+ var->is_function()) {
+ DCHECK(IsLexicalVariableMode(mode) &&
+ IsLexicalVariableMode(var->mode()));
+ ++use_counts_[v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition];
+ } else {
+ // The name was declared in this scope before; check for conflicting
+ // re-declarations. We have a conflict if either of the declarations
+ // is not a var (in script scope, we also have to ignore legacy const
+ // for compatibility). There is similar code in runtime.cc in the
+ // Declare functions. The function CheckConflictingVarDeclarations
+ // checks for var and let bindings from different scopes whereas this
+ // is a check for conflicting declarations within the same scope. This
+ // check also covers the special case
+ //
+ // function () { let x; { var x; } }
+ //
+ // because the var declaration is hoisted to the function scope where
+ // 'x' is already bound.
+ DCHECK(IsDeclaredVariableMode(var->mode()));
// In harmony we treat re-declarations as early errors. See
// ES5 16 for a definition of early errors.
if (declaration_kind == DeclarationDescriptor::NORMAL) {
@@ -1967,9 +2001,6 @@ Variable* Parser::Declare(Declaration* declaration,
*ok = false;
return nullptr;
}
- Expression* expression = NewThrowSyntaxError(
- MessageTemplate::kVarRedeclaration, name, declaration->position());
- declaration_scope->SetIllegalRedeclaration(expression);
} else if (mode == VAR) {
var->set_maybe_assigned();
}
@@ -2093,14 +2124,22 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
Statement* Parser::ParseFunctionDeclaration(
ZoneList<const AstRawString*>* names, bool* ok) {
- // FunctionDeclaration ::
- // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
- // GeneratorDeclaration ::
- // 'function' '*' Identifier '(' FormalParameterListopt ')'
- // '{' FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
int pos = position();
bool is_generator = Check(Token::MUL);
+ return ParseFunctionDeclaration(pos, is_generator, names, ok);
+}
+
+
+Statement* Parser::ParseFunctionDeclaration(
+ int pos, bool is_generator, ZoneList<const AstRawString*>* names,
+ bool* ok) {
+ // FunctionDeclaration ::
+ // 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ // GeneratorDeclaration ::
+ // 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ //
+ // 'function' and '*' (if present) have been consumed by the caller.
bool is_strict_reserved = false;
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
@@ -2113,8 +2152,7 @@ Statement* Parser::ParseFunctionDeclaration(
: kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
: FunctionKind::kNormalFunction,
- pos, FunctionLiteral::kDeclaration, FunctionLiteral::kNormalArity,
- language_mode(), CHECK_OK);
+ pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
// Even if we're not at the top-level of the global or a function
// scope, we treat it as such and introduce the function with its
@@ -2151,6 +2189,8 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
// ClassDeclaration ::
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
//
+ // 'class' is expected to be consumed by the caller.
+ //
// A ClassDeclaration
//
// class C { ... }
@@ -2161,7 +2201,6 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
//
// so rewrite it as such.
- Expect(Token::CLASS, CHECK_OK);
if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
ReportMessage(MessageTemplate::kSloppyLexical);
*ok = false;
@@ -2177,30 +2216,10 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
VariableMode mode = is_strong(language_mode()) ? CONST : LET;
VariableProxy* proxy = NewUnresolved(name, mode);
- const bool is_class_declaration = true;
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, mode, scope_, pos, is_class_declaration,
- scope_->class_declaration_group_start());
- Variable* outer_class_variable =
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+ Declaration* declaration =
+ factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
proxy->var()->set_initializer_position(position());
- // This is needed because a class ("class Name { }") creates two bindings (one
- // in the outer scope, and one in the class scope). The method is a function
- // scope inside the inner scope (class scope). The consecutive class
- // declarations are in the outer scope.
- if (value->class_variable_proxy() && value->class_variable_proxy()->var() &&
- outer_class_variable->is_class()) {
- // In some cases, the outer variable is not detected as a class variable;
- // this happens e.g., for lazy methods. They are excluded from strong mode
- // checks for now. TODO(marja, rossberg): re-create variables with the
- // correct Kind and remove this hack.
- value->class_variable_proxy()
- ->var()
- ->AsClassVariable()
- ->set_declaration_group_start(
- outer_class_variable->AsClassVariable()->declaration_group_start());
- }
-
Assignment* assignment =
factory()->NewAssignment(Token::INIT, proxy, value, pos);
Statement* assignment_statement =
@@ -2281,17 +2300,16 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
// is inside an initializer block, it is ignored.
DeclarationParsingResult parsing_result;
- ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK);
+ Block* result =
+ ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK);
ExpectSemicolon(CHECK_OK);
-
- Block* result = parsing_result.BuildInitializationBlock(names, CHECK_OK);
return result;
}
-
-void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
- DeclarationParsingResult* parsing_result,
- bool* ok) {
+Block* Parser::ParseVariableDeclarations(
+ VariableDeclarationContext var_context,
+ DeclarationParsingResult* parsing_result,
+ ZoneList<const AstRawString*>* names, bool* ok) {
// VariableDeclarations ::
// ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
//
@@ -2311,17 +2329,19 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
parsing_result->descriptor.declaration_pos = peek_position();
parsing_result->descriptor.initialization_pos = peek_position();
parsing_result->descriptor.mode = VAR;
- // True if the binding needs initialization. 'let' and 'const' declared
- // bindings are created uninitialized by their declaration nodes and
- // need initialization. 'var' declared bindings are always initialized
- // immediately by their declaration nodes.
- parsing_result->descriptor.needs_init = false;
+
+ Block* init_block = nullptr;
+ if (var_context != kForStatement) {
+ init_block = factory()->NewBlock(
+ NULL, 1, true, parsing_result->descriptor.declaration_pos);
+ }
+
if (peek() == Token::VAR) {
if (is_strong(language_mode())) {
Scanner::Location location = scanner()->peek_location();
ReportMessageAt(location, MessageTemplate::kStrongVar);
*ok = false;
- return;
+ return nullptr;
}
Consume(Token::VAR);
} else if (peek() == Token::CONST && allow_const()) {
@@ -2334,12 +2354,10 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = CONST;
}
- parsing_result->descriptor.needs_init = true;
} else if (peek() == Token::LET && allow_let()) {
Consume(Token::LET);
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = LET;
- parsing_result->descriptor.needs_init = true;
} else {
UNREACHABLE(); // by current callers
}
@@ -2350,7 +2368,6 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
bool first_declaration = true;
int bindings_start = peek_position();
- bool is_for_iteration_variable;
do {
FuncNameInferrer::State fni_state(fni_);
@@ -2360,27 +2377,20 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Expression* pattern;
int decl_pos = peek_position();
{
- ExpressionClassifier pattern_classifier;
+ ExpressionClassifier pattern_classifier(this);
Token::Value next = peek();
- pattern = ParsePrimaryExpression(&pattern_classifier, ok);
- if (!*ok) return;
- ValidateBindingPattern(&pattern_classifier, ok);
- if (!*ok) return;
+ pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+ ValidateBindingPattern(&pattern_classifier, CHECK_OK);
if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
- ValidateLetPattern(&pattern_classifier, ok);
- if (!*ok) return;
+ ValidateLetPattern(&pattern_classifier, CHECK_OK);
}
if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) {
ReportUnexpectedToken(next);
*ok = false;
- return;
+ return nullptr;
}
}
- bool is_pattern =
- (pattern->IsObjectLiteral() || pattern->IsArrayLiteral()) &&
- !pattern->is_parenthesized();
-
Scanner::Location variable_loc = scanner()->location();
const AstRawString* single_name =
pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name()
@@ -2389,25 +2399,13 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
if (fni_ != NULL) fni_->PushVariableName(single_name);
}
- is_for_iteration_variable =
- var_context == kForStatement &&
- (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
- if (is_for_iteration_variable &&
- (parsing_result->descriptor.mode == CONST ||
- parsing_result->descriptor.mode == CONST_LEGACY)) {
- parsing_result->descriptor.needs_init = false;
- }
-
Expression* value = NULL;
- // Harmony consts have non-optional initializers.
int initializer_position = RelocInfo::kNoPosition;
if (Check(Token::ASSIGN)) {
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
value = ParseAssignmentExpression(var_context != kForStatement,
- &classifier, ok);
- if (!*ok) return;
- value = ParserTraits::RewriteNonPattern(value, &classifier, ok);
- if (!*ok) return;
+ &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
variable_loc.end_pos = scanner()->location().end_pos;
if (!parsing_result->first_initializer_loc.IsValid()) {
@@ -2424,48 +2422,60 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
}
}
- if (allow_harmony_function_name() && single_name) {
- if (value->IsFunctionLiteral()) {
- auto function_literal = value->AsFunctionLiteral();
- if (function_literal->is_anonymous()) {
- function_literal->set_raw_name(single_name);
- }
- } else if (value->IsClassLiteral()) {
- auto class_literal = value->AsClassLiteral();
- if (class_literal->raw_name() == nullptr) {
- class_literal->set_raw_name(single_name);
- }
- }
+ if (allow_harmony_function_name()) {
+ ParserTraits::SetFunctionNameFromIdentifierRef(value, pattern);
}
// End position of the initializer is after the assignment expression.
initializer_position = scanner()->location().end_pos;
} else {
- if ((parsing_result->descriptor.mode == CONST || is_pattern) &&
- !is_for_iteration_variable) {
- ParserTraits::ReportMessageAt(
- Scanner::Location(decl_pos, scanner()->location().end_pos),
- MessageTemplate::kDeclarationMissingInitializer,
- is_pattern ? "destructuring" : "const");
- *ok = false;
- return;
+ // Initializers may be either required or implied unless this is a
+ // for-in/of iteration variable.
+ if (var_context != kForStatement || !PeekInOrOf()) {
+ // ES6 'const' and binding patterns require initializers.
+ if (parsing_result->descriptor.mode == CONST ||
+ !pattern->IsVariableProxy()) {
+ ParserTraits::ReportMessageAt(
+ Scanner::Location(decl_pos, scanner()->location().end_pos),
+ MessageTemplate::kDeclarationMissingInitializer,
+ !pattern->IsVariableProxy() ? "destructuring" : "const");
+ *ok = false;
+ return nullptr;
+ }
+
+ // 'let x' and (legacy) 'const x' initialize 'x' to undefined.
+ if (parsing_result->descriptor.mode == LET ||
+ parsing_result->descriptor.mode == CONST_LEGACY) {
+ value = GetLiteralUndefined(position());
+ }
}
+
// End position of the initializer is after the variable.
initializer_position = position();
}
- // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
- if (value == NULL && parsing_result->descriptor.needs_init) {
- value = GetLiteralUndefined(position());
+ DeclarationParsingResult::Declaration decl(pattern, initializer_position,
+ value);
+ if (var_context == kForStatement) {
+ // Save the declaration for further handling in ParseForStatement.
+ parsing_result->declarations.Add(decl);
+ } else {
+ // Immediately declare the variable otherwise. This avoids O(N^2)
+ // behavior (where N is the number of variables in a single
+ // declaration) in the PatternRewriter having to do with removing
+ // and adding VariableProxies to the Scope (see bug 4699).
+ DCHECK_NOT_NULL(init_block);
+ PatternRewriter::DeclareAndInitializeVariables(
+ init_block, &parsing_result->descriptor, &decl, names, CHECK_OK);
}
-
- parsing_result->declarations.Add(DeclarationParsingResult::Declaration(
- pattern, initializer_position, value));
first_declaration = false;
} while (peek() == Token::COMMA);
parsing_result->bindings_loc =
Scanner::Location(bindings_start, scanner()->location().end_pos);
+
+ DCHECK(*ok);
+ return init_block;
}
@@ -2511,13 +2521,13 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
IsClassConstructor(function_state_->kind())) {
bool is_this = peek() == Token::THIS;
Expression* expr;
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
if (is_this) {
expr = ParseStrongInitializationExpression(&classifier, CHECK_OK);
} else {
expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK);
}
- expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
switch (peek()) {
case Token::SEMICOLON:
Consume(Token::SEMICOLON);
@@ -2728,23 +2738,22 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
if (IsSubclassConstructor(function_state_->kind())) {
// For subclass constructors we need to return this in case of undefined
- // and throw an exception in case of a non object.
+ // return a Smi (transformed into an exception in the ConstructStub)
+ // for a non object.
//
// return expr;
//
// Is rewritten as:
//
// return (temp = expr) === undefined ? this :
- // %_IsJSReceiver(temp) ? temp : throw new TypeError(...);
+ // %_IsJSReceiver(temp) ? temp : 1;
+
+ // temp = expr
Variable* temp = scope_->NewTemporary(
ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
- Expression* throw_expression =
- NewThrowTypeError(MessageTemplate::kDerivedConstructorReturn,
- ast_value_factory()->empty_string(), pos);
-
// %_IsJSReceiver(temp)
ZoneList<Expression*>* is_spec_object_args =
new (zone()) ZoneList<Expression*>(1, zone());
@@ -2755,7 +2764,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// %_IsJSReceiver(temp) ? temp : throw_expression
Expression* is_object_conditional = factory()->NewConditional(
is_spec_object_call, factory()->NewVariableProxy(temp),
- throw_expression, pos);
+ factory()->NewSmiLiteral(1, pos), pos);
// temp === undefined
Expression* is_undefined = factory()->NewCompareOperation(
@@ -2768,7 +2777,10 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
is_object_conditional, pos);
}
- return_value->MarkTail();
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ if (FLAG_harmony_tailcalls && !is_sloppy(language_mode())) {
+ function_state_->AddExpressionInTailPosition(return_value);
+ }
}
ExpectSemicolon(CHECK_OK);
@@ -2974,6 +2986,40 @@ Statement* Parser::ParseThrowStatement(bool* ok) {
factory()->NewThrow(exception, pos), pos);
}
+class Parser::DontCollectExpressionsInTailPositionScope {
+ public:
+ DontCollectExpressionsInTailPositionScope(
+ Parser::FunctionState* function_state)
+ : function_state_(function_state),
+ old_value_(function_state->collect_expressions_in_tail_position()) {
+ function_state->set_collect_expressions_in_tail_position(false);
+ }
+ ~DontCollectExpressionsInTailPositionScope() {
+ function_state_->set_collect_expressions_in_tail_position(old_value_);
+ }
+
+ private:
+ Parser::FunctionState* function_state_;
+ bool old_value_;
+};
+
+// Collects all return expressions at tail call position in this scope
+// to a separate list.
+class Parser::CollectExpressionsInTailPositionToListScope {
+ public:
+ CollectExpressionsInTailPositionToListScope(
+ Parser::FunctionState* function_state, List<Expression*>* list)
+ : function_state_(function_state), list_(list) {
+ function_state->expressions_in_tail_position().Swap(list_);
+ }
+ ~CollectExpressionsInTailPositionToListScope() {
+ function_state_->expressions_in_tail_position().Swap(list_);
+ }
+
+ private:
+ Parser::FunctionState* function_state_;
+ List<Expression*>* list_;
+};
TryStatement* Parser::ParseTryStatement(bool* ok) {
// TryStatement ::
@@ -2990,7 +3036,11 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::TRY, CHECK_OK);
int pos = position();
- Block* try_block = ParseBlock(NULL, CHECK_OK);
+ Block* try_block;
+ {
+ DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_);
+ try_block = ParseBlock(NULL, CHECK_OK);
+ }
Token::Value tok = peek();
if (tok != Token::CATCH && tok != Token::FINALLY) {
@@ -3002,6 +3052,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Scope* catch_scope = NULL;
Variable* catch_variable = NULL;
Block* catch_block = NULL;
+ List<Expression*> expressions_in_tail_position_in_catch_block;
if (tok == Token::CATCH) {
Consume(Token::CATCH);
@@ -3009,7 +3060,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
catch_scope = NewScope(scope_, CATCH_SCOPE);
catch_scope->set_start_position(scanner()->location().beg_pos);
- ExpressionClassifier pattern_classifier;
+ ExpressionClassifier pattern_classifier(this);
Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
@@ -3027,6 +3078,9 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::RPAREN, CHECK_OK);
{
+ CollectExpressionsInTailPositionToListScope
+ collect_expressions_in_tail_position_scope(
+ function_state_, &expressions_in_tail_position_in_catch_block);
BlockState block_state(&scope_, catch_scope);
// TODO(adamk): Make a version of ParseBlock that takes a scope and
@@ -3047,7 +3101,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
descriptor.scope = scope_;
descriptor.hoist_scope = nullptr;
descriptor.mode = LET;
- descriptor.needs_init = true;
descriptor.declaration_pos = pattern->position();
descriptor.initialization_pos = pattern->position();
@@ -3102,6 +3155,11 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
TryStatement* result = NULL;
if (catch_block != NULL) {
+ // For a try-catch construct append return expressions from the catch block
+ // to the list of return expressions.
+ function_state_->expressions_in_tail_position().AddAll(
+ expressions_in_tail_position_in_catch_block);
+
DCHECK(finally_block == NULL);
DCHECK(catch_scope != NULL && catch_variable != NULL);
result = factory()->NewTryCatchStatement(try_block, catch_scope,
@@ -3262,6 +3320,7 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
}
for_of->Initialize(each, subject, body,
+ iterator,
assign_iterator,
next_result,
result_done,
@@ -3288,9 +3347,8 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
}
}
-
Statement* Parser::DesugarLexicalBindingsInForStatement(
- Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
+ Scope* inner_scope, VariableMode mode, ZoneList<const AstRawString*>* names,
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
Statement* body, bool* ok) {
// ES6 13.7.4.8 specifies that on each loop iteration the let variables are
@@ -3331,7 +3389,6 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// }
DCHECK(names->length() > 0);
- Scope* for_scope = scope_;
ZoneList<Variable*> temps(names->length(), zone());
Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false,
@@ -3384,150 +3441,155 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
ForStatement* outer_loop =
factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
outer_block->statements()->Add(outer_loop, zone());
-
- outer_block->set_scope(for_scope);
- scope_ = inner_scope;
+ outer_block->set_scope(scope_);
Block* inner_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
- Block* ignore_completion_block = factory()->NewBlock(
- NULL, names->length() + 3, true, RelocInfo::kNoPosition);
- ZoneList<Variable*> inner_vars(names->length(), zone());
- // For each let variable x:
- // make statement: let/const x = temp_x.
- VariableMode mode = is_const ? CONST : LET;
- for (int i = 0; i < names->length(); i++) {
- VariableProxy* proxy = NewUnresolved(names->at(i), mode);
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, mode, scope_, RelocInfo::kNoPosition);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
- inner_vars.Add(declaration->proxy()->var(), zone());
- VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
- Assignment* assignment = factory()->NewAssignment(
- Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
- Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
- DCHECK(init->position() != RelocInfo::kNoPosition);
- proxy->var()->set_initializer_position(init->position());
- ignore_completion_block->statements()->Add(assignment_statement, zone());
- }
+ {
+ BlockState block_state(&scope_, inner_scope);
- // Make statement: if (first == 1) { first = 0; } else { next; }
- if (next) {
- DCHECK(first);
- Expression* compare = NULL;
- // Make compare expression: first == 1.
- {
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
- VariableProxy* first_proxy = factory()->NewVariableProxy(first);
- compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
- RelocInfo::kNoPosition);
- }
- Statement* clear_first = NULL;
- // Make statement: first = 0.
- {
- VariableProxy* first_proxy = factory()->NewVariableProxy(first);
- Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+ Block* ignore_completion_block = factory()->NewBlock(
+ NULL, names->length() + 3, true, RelocInfo::kNoPosition);
+ ZoneList<Variable*> inner_vars(names->length(), zone());
+ // For each let variable x:
+ // make statement: let/const x = temp_x.
+ for (int i = 0; i < names->length(); i++) {
+ VariableProxy* proxy = NewUnresolved(names->at(i), mode);
+ Declaration* declaration = factory()->NewVariableDeclaration(
+ proxy, mode, scope_, RelocInfo::kNoPosition);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+ inner_vars.Add(declaration->proxy()->var(), zone());
+ VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
- clear_first =
+ Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
+ Statement* assignment_statement =
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+ DCHECK(init->position() != RelocInfo::kNoPosition);
+ proxy->var()->set_initializer_position(init->position());
+ ignore_completion_block->statements()->Add(assignment_statement, zone());
}
- Statement* clear_first_or_next = factory()->NewIfStatement(
- compare, clear_first, next, RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(clear_first_or_next, zone());
- }
- Variable* flag = scope_->NewTemporary(temp_name);
- // Make statement: flag = 1.
- {
- VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
- Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
- Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(assignment_statement, zone());
- }
+ // Make statement: if (first == 1) { first = 0; } else { next; }
+ if (next) {
+ DCHECK(first);
+ Expression* compare = NULL;
+ // Make compare expression: first == 1.
+ {
+ Expression* const1 =
+ factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+ compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
+ RelocInfo::kNoPosition);
+ }
+ Statement* clear_first = NULL;
+ // Make statement: first = 0.
+ {
+ VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+ Expression* const0 =
+ factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+ Assignment* assignment = factory()->NewAssignment(
+ Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
+ clear_first = factory()->NewExpressionStatement(assignment,
+ RelocInfo::kNoPosition);
+ }
+ Statement* clear_first_or_next = factory()->NewIfStatement(
+ compare, clear_first, next, RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(clear_first_or_next, zone());
+ }
- // Make statement: if (!cond) break.
- if (cond) {
- Statement* stop =
- factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
- Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(
- factory()->NewIfStatement(cond, noop, stop, cond->position()), zone());
- }
+ Variable* flag = scope_->NewTemporary(temp_name);
+ // Make statement: flag = 1.
+ {
+ VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+ Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ Assignment* assignment = factory()->NewAssignment(
+ Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
+ Statement* assignment_statement =
+ factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(assignment_statement, zone());
+ }
- inner_block->statements()->Add(ignore_completion_block, zone());
- // Make cond expression for main loop: flag == 1.
- Expression* flag_cond = NULL;
- {
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
- VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
- RelocInfo::kNoPosition);
- }
+ // Make statement: if (!cond) break.
+ if (cond) {
+ Statement* stop =
+ factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+ Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(
+ factory()->NewIfStatement(cond, noop, stop, cond->position()),
+ zone());
+ }
- // Create chain of expressions "flag = 0, temp_x = x, ..."
- Statement* compound_next_statement = NULL;
- {
- Expression* compound_next = NULL;
- // Make expression: flag = 0.
+ inner_block->statements()->Add(ignore_completion_block, zone());
+ // Make cond expression for main loop: flag == 1.
+ Expression* flag_cond = NULL;
{
+ Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
- compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
- const0, RelocInfo::kNoPosition);
+ flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+ RelocInfo::kNoPosition);
}
- // Make the comma-separated list of temp_x = x assignments.
- int inner_var_proxy_pos = scanner()->location().beg_pos;
- for (int i = 0; i < names->length(); i++) {
- VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
- VariableProxy* proxy =
- factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
- Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
- compound_next = factory()->NewBinaryOperation(
- Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
- }
+ // Create chain of expressions "flag = 0, temp_x = x, ..."
+ Statement* compound_next_statement = NULL;
+ {
+ Expression* compound_next = NULL;
+ // Make expression: flag = 0.
+ {
+ VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+ Expression* const0 =
+ factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+ compound_next = factory()->NewAssignment(
+ Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
+ }
- compound_next_statement = factory()->NewExpressionStatement(
- compound_next, RelocInfo::kNoPosition);
- }
+ // Make the comma-separated list of temp_x = x assignments.
+ int inner_var_proxy_pos = scanner()->location().beg_pos;
+ for (int i = 0; i < names->length(); i++) {
+ VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
+ VariableProxy* proxy =
+ factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
+ Assignment* assignment = factory()->NewAssignment(
+ Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
+ compound_next = factory()->NewBinaryOperation(
+ Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+ }
- // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
- // Note that we re-use the original loop node, which retains its labels
- // and ensures that any break or continue statements in body point to
- // the right place.
- loop->Initialize(NULL, flag_cond, compound_next_statement, body);
- inner_block->statements()->Add(loop, zone());
+ compound_next_statement = factory()->NewExpressionStatement(
+ compound_next, RelocInfo::kNoPosition);
+ }
- // Make statement: {{if (flag == 1) break;}}
- {
- Expression* compare = NULL;
- // Make compare expresion: flag == 1.
+ // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
+ // Note that we re-use the original loop node, which retains its labels
+ // and ensures that any break or continue statements in body point to
+ // the right place.
+ loop->Initialize(NULL, flag_cond, compound_next_statement, body);
+ inner_block->statements()->Add(loop, zone());
+
+ // Make statement: {{if (flag == 1) break;}}
{
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
- VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
- RelocInfo::kNoPosition);
- }
- Statement* stop =
- factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
- Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- Statement* if_flag_break =
- factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
- Block* ignore_completion_block =
- factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(if_flag_break, zone());
- inner_block->statements()->Add(ignore_completion_block, zone());
- }
+ Expression* compare = NULL;
+ // Make compare expresion: flag == 1.
+ {
+ Expression* const1 =
+ factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+ compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+ RelocInfo::kNoPosition);
+ }
+ Statement* stop =
+ factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+ Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ Statement* if_flag_break = factory()->NewIfStatement(
+ compare, stop, empty, RelocInfo::kNoPosition);
+ Block* ignore_completion_block =
+ factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(if_flag_break, zone());
+ inner_block->statements()->Add(ignore_completion_block, zone());
+ }
- inner_scope->set_end_position(scanner()->location().end_pos);
- inner_block->set_scope(inner_scope);
- scope_ = for_scope;
+ inner_scope->set_end_position(scanner()->location().end_pos);
+ inner_block->set_scope(inner_scope);
+ }
outer_loop->Initialize(NULL, NULL, NULL, inner_block);
return outer_block;
@@ -3536,18 +3598,14 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
- // ForStatement ::
- // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
-
int stmt_pos = peek_position();
- bool is_const = false;
Statement* init = NULL;
ZoneList<const AstRawString*> lexical_bindings(1, zone());
// Create an in-between scope for let-bound iteration variables.
- Scope* saved_scope = scope_;
Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
- scope_ = for_scope;
+
+ BlockState block_state(&scope_, for_scope);
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
for_scope->set_start_position(scanner()->location().beg_pos);
@@ -3556,23 +3614,20 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && IsNextLetKeyword())) {
- ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
- is_const = parsing_result.descriptor.mode == CONST;
+ ParseVariableDeclarations(kForStatement, &parsing_result, nullptr,
+ CHECK_OK);
- int num_decl = parsing_result.declarations.length();
- bool accept_IN = num_decl >= 1;
ForEachStatement::VisitMode mode;
int each_beg_pos = scanner()->location().beg_pos;
int each_end_pos = scanner()->location().end_pos;
- if (accept_IN && CheckInOrOf(&mode, ok)) {
+ if (CheckInOrOf(&mode, ok)) {
if (!*ok) return nullptr;
- if (num_decl != 1) {
- const char* loop_type =
- mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
+ if (parsing_result.declarations.length() != 1) {
ParserTraits::ReportMessageAt(
parsing_result.bindings_loc,
- MessageTemplate::kForInOfLoopMultiBindings, loop_type);
+ MessageTemplate::kForInOfLoopMultiBindings,
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return nullptr;
}
@@ -3582,14 +3637,10 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
IsLexicalVariableMode(parsing_result.descriptor.mode) ||
!decl.pattern->IsVariableProxy())) {
- if (mode == ForEachStatement::ITERATE) {
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForOfLoopInitializer);
- } else {
- // TODO(caitp): This should be an error in sloppy mode too.
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForInLoopInitializer);
- }
+ ParserTraits::ReportMessageAt(
+ parsing_result.first_initializer_loc,
+ MessageTemplate::kForInOfLoopInitializer,
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return nullptr;
}
@@ -3599,6 +3650,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// special case for legacy for (var/const x =.... in)
if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
+ ++use_counts_[v8::Isolate::kForInInitializer];
const AstRawString* name =
decl.pattern->AsVariableProxy()->raw_name();
VariableProxy* single_var = scope_->NewUnresolved(
@@ -3630,52 +3682,59 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// let x; // for TDZ
// }
- Variable* temp = scope_->NewTemporary(
- ast_value_factory()->dot_for_string());
+ Variable* temp =
+ scope_->NewTemporary(ast_value_factory()->dot_for_string());
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop);
- Expression* enumerable = ParseExpression(true, CHECK_OK);
+ Expression* enumerable;
+ if (mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ enumerable = ParseExpression(true, CHECK_OK);
+ }
Expect(Token::RPAREN, CHECK_OK);
Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
body_scope->set_start_position(scanner()->location().beg_pos);
- scope_ = body_scope;
-
- Statement* body = ParseSubStatement(NULL, CHECK_OK);
Block* body_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
- auto each_initialization_block =
- factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
{
- auto descriptor = parsing_result.descriptor;
- descriptor.declaration_pos = RelocInfo::kNoPosition;
- descriptor.initialization_pos = RelocInfo::kNoPosition;
- decl.initializer = factory()->NewVariableProxy(temp);
+ BlockState block_state(&scope_, body_scope);
+
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
+
+ auto each_initialization_block =
+ factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+ {
+ auto descriptor = parsing_result.descriptor;
+ descriptor.declaration_pos = RelocInfo::kNoPosition;
+ descriptor.initialization_pos = RelocInfo::kNoPosition;
+ decl.initializer = factory()->NewVariableProxy(temp);
+
+ PatternRewriter::DeclareAndInitializeVariables(
+ each_initialization_block, &descriptor, &decl,
+ IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
+ : nullptr,
+ CHECK_OK);
+ }
- PatternRewriter::DeclareAndInitializeVariables(
- each_initialization_block, &descriptor, &decl,
- IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
- : nullptr,
- CHECK_OK);
+ body_block->statements()->Add(each_initialization_block, zone());
+ body_block->statements()->Add(body, zone());
+ VariableProxy* temp_proxy =
+ factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
+ InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
+ false);
}
-
- body_block->statements()->Add(each_initialization_block, zone());
- body_block->statements()->Add(body, zone());
- VariableProxy* temp_proxy =
- factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
- InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
- false);
- scope_ = for_scope;
body_scope->set_end_position(scanner()->location().end_pos);
body_scope = body_scope->FinalizeBlockScope();
- if (body_scope != nullptr) {
- body_block->set_scope(body_scope);
- }
+ body_block->set_scope(body_scope);
// Create a TDZ for any lexically-bound names.
if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
@@ -3688,28 +3747,31 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// TODO(adamk): This needs to be some sort of special
// INTERNAL variable that's invisible to the debugger
// but visible to everything else.
- VariableProxy* tdz_proxy = NewUnresolved(lexical_bindings[i], LET);
+ VariableProxy* tdz_proxy =
+ NewUnresolved(lexical_bindings[i], LET);
Declaration* tdz_decl = factory()->NewVariableDeclaration(
tdz_proxy, LET, scope_, RelocInfo::kNoPosition);
- Variable* tdz_var = Declare(tdz_decl, DeclarationDescriptor::NORMAL,
- true, CHECK_OK);
+ Variable* tdz_var = Declare(
+ tdz_decl, DeclarationDescriptor::NORMAL, true, CHECK_OK);
tdz_var->set_initializer_position(position());
}
}
- scope_ = saved_scope;
+ Statement* final_loop = loop->IsForOfStatement()
+ ? FinalizeForOfStatement(
+ loop->AsForOfStatement(), RelocInfo::kNoPosition)
+ : loop;
+
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
// Parsed for-in loop w/ variable declarations.
if (init_block != nullptr) {
- init_block->statements()->Add(loop, zone());
- if (for_scope != nullptr) {
- init_block->set_scope(for_scope);
- }
+ init_block->statements()->Add(final_loop, zone());
+ init_block->set_scope(for_scope);
return init_block;
} else {
DCHECK_NULL(for_scope);
- return loop;
+ return final_loop;
}
} else {
init = parsing_result.BuildInitializationBlock(
@@ -3720,7 +3782,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
}
} else {
int lhs_beg_pos = peek_position();
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
Expression* expression = ParseExpression(false, &classifier, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
ForEachStatement::VisitMode mode;
@@ -3738,8 +3800,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
if (is_destructuring) {
ValidateAssignmentPattern(&classifier, CHECK_OK);
} else {
- expression =
- ParserTraits::RewriteNonPattern(expression, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
}
if (is_for_each) {
@@ -3753,7 +3814,15 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop);
- Expression* enumerable = ParseExpression(true, CHECK_OK);
+ Expression* enumerable;
+ if (mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ enumerable = ParseExpression(true, CHECK_OK);
+ }
+
Expect(Token::RPAREN, CHECK_OK);
// Make a block around the statement in case a lexical binding
@@ -3763,24 +3832,28 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// expressions in head of the loop should actually have variables
// resolved in the outer scope.
Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE);
- scope_ = body_scope;
- Block* block =
- factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
- Statement* body = ParseSubStatement(NULL, CHECK_OK);
- block->statements()->Add(body, zone());
- InitializeForEachStatement(loop, expression, enumerable, block,
- is_destructuring);
- scope_ = saved_scope;
- body_scope->set_end_position(scanner()->location().end_pos);
- body_scope = body_scope->FinalizeBlockScope();
- if (body_scope != nullptr) {
+ {
+ BlockState block_state(&scope_, body_scope);
+ Block* block =
+ factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
+ block->statements()->Add(body, zone());
+ InitializeForEachStatement(loop, expression, enumerable, block,
+ is_destructuring);
+ body_scope->set_end_position(scanner()->location().end_pos);
+ body_scope = body_scope->FinalizeBlockScope();
block->set_scope(body_scope);
}
+
+ Statement* final_loop = loop->IsForOfStatement()
+ ? FinalizeForOfStatement(
+ loop->AsForOfStatement(), RelocInfo::kNoPosition)
+ : loop;
+
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
DCHECK(for_scope == nullptr);
- // Parsed for-in loop.
- return loop;
+ return final_loop;
} else {
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
@@ -3802,40 +3875,42 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
}
Expect(Token::SEMICOLON, CHECK_OK);
+ Expression* cond = NULL;
+ Statement* next = NULL;
+ Statement* body = NULL;
+
// If there are let bindings, then condition and the next statement of the
// for loop must be parsed in a new scope.
- Scope* inner_scope = NULL;
+ Scope* inner_scope = scope_;
if (lexical_bindings.length() > 0) {
inner_scope = NewScope(for_scope, BLOCK_SCOPE);
inner_scope->set_start_position(scanner()->location().beg_pos);
- scope_ = inner_scope;
}
+ {
+ BlockState block_state(&scope_, inner_scope);
- Expression* cond = NULL;
- if (peek() != Token::SEMICOLON) {
- cond = ParseExpression(true, CHECK_OK);
- }
- Expect(Token::SEMICOLON, CHECK_OK);
+ if (peek() != Token::SEMICOLON) {
+ cond = ParseExpression(true, CHECK_OK);
+ }
+ Expect(Token::SEMICOLON, CHECK_OK);
- Statement* next = NULL;
- if (peek() != Token::RPAREN) {
- Expression* exp = ParseExpression(true, CHECK_OK);
- next = factory()->NewExpressionStatement(exp, exp->position());
- }
- Expect(Token::RPAREN, CHECK_OK);
+ if (peek() != Token::RPAREN) {
+ Expression* exp = ParseExpression(true, CHECK_OK);
+ next = factory()->NewExpressionStatement(exp, exp->position());
+ }
+ Expect(Token::RPAREN, CHECK_OK);
- Statement* body = ParseSubStatement(NULL, CHECK_OK);
+ body = ParseSubStatement(NULL, CHECK_OK);
+ }
Statement* result = NULL;
if (lexical_bindings.length() > 0) {
- scope_ = for_scope;
+ BlockState block_state(&scope_, for_scope);
result = DesugarLexicalBindingsInForStatement(
- inner_scope, is_const, &lexical_bindings, loop, init, cond,
- next, body, CHECK_OK);
- scope_ = saved_scope;
+ inner_scope, parsing_result.descriptor.mode, &lexical_bindings, loop,
+ init, cond, next, body, CHECK_OK);
for_scope->set_end_position(scanner()->location().end_pos);
} else {
- scope_ = saved_scope;
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
if (for_scope) {
@@ -4035,7 +4110,7 @@ void ParserTraits::ParseArrowFunctionFormalParameterList(
ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
if (!*ok) return;
- ExpressionClassifier classifier;
+ Type::ExpressionClassifier classifier(parser_);
if (!parameters->is_simple) {
classifier.RecordNonSimpleParameter();
}
@@ -4069,7 +4144,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
const AstRawString* function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -4137,17 +4211,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
int materialized_literal_count = -1;
int expected_property_count = -1;
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
- ExpressionClassifier formals_classifier(&duplicate_finder);
FunctionLiteral::EagerCompileHint eager_compile_hint =
parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
: FunctionLiteral::kShouldLazyCompile;
bool should_be_used_once_hint = false;
+ bool has_duplicate_parameters;
// Parse function.
{
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, scope, kind,
&function_factory);
scope_->SetScopeName(function_name);
+ ExpressionClassifier formals_classifier(this, &duplicate_finder);
if (is_generator) {
// For generators, allocating variables in contexts is currently a win
@@ -4172,11 +4247,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(arity, arity_restriction,
- formals.has_rest, start_position,
+ CheckArityRestrictions(arity, kind, formals.has_rest, start_position,
formals_end_position, CHECK_OK);
Expect(Token::LBRACE, CHECK_OK);
+ // Don't include the rest parameter into the function's formal parameter
+ // count (esp. the SharedFunctionInfo::internal_formal_parameter_count,
+ // which says whether we need to create an arguments adaptor frame).
+ if (formals.has_rest) arity--;
+
// Determine if the function can be parsed lazily. Lazy parsing is different
// from lazy compilation; we need to parse more eagerly than we compile.
@@ -4321,10 +4400,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// If body can be inspected, rewrite queued destructuring assignments
ParserTraits::RewriteDestructuringAssignments();
}
+ has_duplicate_parameters =
+ !formals_classifier.is_valid_formal_parameter_list_without_duplicates();
}
- bool has_duplicate_parameters =
- !formals_classifier.is_valid_formal_parameter_list_without_duplicates();
FunctionLiteral::ParameterFlag duplicate_parameters =
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
: FunctionLiteral::kNoDuplicateParameters;
@@ -4337,10 +4416,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (should_be_used_once_hint)
function_literal->set_should_be_used_once_hint();
- if (scope->has_rest_parameter()) {
- function_literal->set_dont_optimize_reason(kRestParameter);
- }
-
if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
return function_literal;
}
@@ -4462,8 +4537,7 @@ class InitializerRewriter : public AstExpressionVisitor {
private:
void VisitExpression(Expression* expr) {
- RewritableAssignmentExpression* to_rewrite =
- expr->AsRewritableAssignmentExpression();
+ RewritableExpression* to_rewrite = expr->AsRewritableExpression();
if (to_rewrite == nullptr || to_rewrite->is_rewritten()) return;
Parser::PatternRewriter::RewriteDestructuringAssignment(parser_, to_rewrite,
@@ -4497,7 +4571,6 @@ Block* Parser::BuildParameterInitializationBlock(
descriptor.scope = scope_;
descriptor.hoist_scope = nullptr;
descriptor.mode = LET;
- descriptor.needs_init = true;
descriptor.declaration_pos = parameter.pattern->position();
// The position that will be used by the AssignmentExpression
// which copies from the temp parameter to the pattern.
@@ -4597,35 +4670,72 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
{
BlockState block_state(&scope_, inner_scope);
- // For generators, allocate and yield an iterator on function entry.
if (IsGeneratorFunction(kind)) {
- ZoneList<Expression*>* arguments =
- new(zone()) ZoneList<Expression*>(0, zone());
- CallRuntime* allocation = factory()->NewCallRuntime(
- Runtime::kCreateJSGeneratorObject, arguments, pos);
- VariableProxy* init_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Assignment* assignment = factory()->NewAssignment(
- Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
- VariableProxy* get_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Yield* yield = factory()->NewYield(
- get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
- }
+ // We produce:
+ //
+ // try { InitialYield; ...body...; FinalYield }
+ // finally { %GeneratorClose(generator) }
+ //
+ // - InitialYield yields the actual generator object.
+ // - FinalYield yields {value: foo, done: true} where foo is the
+ // completion value of body. (This is needed here in case the body
+ // falls through without an explicit return.)
+ // - Any return statement inside the body will be converted into a similar
+ // FinalYield.
+ // - If the generator terminates for whatever reason, we must close it.
+ // Hence the finally clause.
+
+ Block* try_block =
+ factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition);
- ParseStatementList(body, Token::RBRACE, CHECK_OK);
+ {
+ ZoneList<Expression*>* arguments =
+ new (zone()) ZoneList<Expression*>(0, zone());
+ CallRuntime* allocation = factory()->NewCallRuntime(
+ Runtime::kCreateJSGeneratorObject, arguments, pos);
+ VariableProxy* init_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Assignment* assignment = factory()->NewAssignment(
+ Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
+ VariableProxy* get_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Yield* yield = factory()->NewYield(
+ get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
+ try_block->statements()->Add(
+ factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+ zone());
+ }
+
+ ParseStatementList(try_block->statements(), Token::RBRACE, CHECK_OK);
- if (IsGeneratorFunction(kind)) {
VariableProxy* get_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
Expression* undefined =
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal,
RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
+ try_block->statements()->Add(
+ factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+ zone());
+
+ Block* finally_block =
+ factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
+ ZoneList<Expression*>* args =
+ new (zone()) ZoneList<Expression*>(1, zone());
+ VariableProxy* call_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ args->Add(call_proxy, zone());
+ Expression* call = factory()->NewCallRuntime(
+ Runtime::kGeneratorClose, args, RelocInfo::kNoPosition);
+ finally_block->statements()->Add(
+ factory()->NewExpressionStatement(call, RelocInfo::kNoPosition),
+ zone());
+
+ body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
+ RelocInfo::kNoPosition),
+ zone());
+ } else {
+ ParseStatementList(body, Token::RBRACE, CHECK_OK);
}
if (IsSubclassConstructor(kind)) {
@@ -4682,6 +4792,13 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
RelocInfo::kNoPosition));
}
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ // Mark collected return expressions that are in tail call position.
+ const List<Expression*>& expressions_in_tail_position =
+ function_state_->expressions_in_tail_position();
+ for (int i = 0; i < expressions_in_tail_position.length(); ++i) {
+ expressions_in_tail_position[i]->MarkTail();
+ }
return result;
}
@@ -4693,6 +4810,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Start();
}
+ TRACE_EVENT0("v8", "V8.PreParse");
+
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
if (reusable_preparser_ == NULL) {
@@ -4709,6 +4828,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
SET_ALLOW(strong_mode);
SET_ALLOW(harmony_do_expressions);
SET_ALLOW(harmony_function_name);
+ SET_ALLOW(harmony_function_sent);
#undef SET_ALLOW
}
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
@@ -4751,19 +4871,17 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
VariableProxy* proxy = NULL;
if (name != NULL) {
proxy = NewUnresolved(name, CONST);
- const bool is_class_declaration = true;
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, CONST, block_scope, pos, is_class_declaration,
- scope_->class_declaration_group_start());
+ Declaration* declaration =
+ factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
}
Expression* extends = NULL;
if (Check(Token::EXTENDS)) {
block_scope->set_start_position(scanner()->location().end_pos);
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
extends = ParseLeftHandSideExpression(&classifier, CHECK_OK);
- extends = ParserTraits::RewriteNonPattern(extends, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
} else {
block_scope->set_start_position(scanner()->location().end_pos);
}
@@ -4784,25 +4902,27 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
const bool is_static = false;
bool is_computed_name = false; // Classes do not care about computed
// property names here.
- ExpressionClassifier classifier;
- const AstRawString* name = nullptr;
+ ExpressionClassifier classifier(this);
+ const AstRawString* property_name = nullptr;
ObjectLiteral::Property* property = ParsePropertyDefinition(
&checker, in_class, has_extends, is_static, &is_computed_name,
- &has_seen_constructor, &classifier, &name, CHECK_OK);
- property = ParserTraits::RewriteNonPatternObjectLiteralProperty(
- property, &classifier, CHECK_OK);
+ &has_seen_constructor, &classifier, &property_name, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
if (has_seen_constructor && constructor == NULL) {
constructor = GetPropertyValue(property)->AsFunctionLiteral();
DCHECK_NOT_NULL(constructor);
+ constructor->set_raw_name(
+ name != nullptr ? name : ast_value_factory()->empty_string());
} else {
properties->Add(property, zone());
}
if (fni_ != NULL) fni_->Infer();
- if (allow_harmony_function_name()) {
- SetFunctionNameFromPropertyName(property, name);
+ if (allow_harmony_function_name() &&
+ property_name != ast_value_factory()->constructor_string()) {
+ SetFunctionNameFromPropertyName(property, property_name);
}
}
@@ -4810,8 +4930,8 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
int end_pos = scanner()->location().end_pos;
if (constructor == NULL) {
- constructor = DefaultConstructor(extends != NULL, block_scope, pos, end_pos,
- block_scope->language_mode());
+ constructor = DefaultConstructor(name, extends != NULL, block_scope, pos,
+ end_pos, block_scope->language_mode());
}
// Note that we do not finalize this block scope because strong
@@ -4823,8 +4943,8 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
proxy->var()->set_initializer_position(end_pos);
}
- return factory()->NewClassLiteral(name, block_scope, proxy, extends,
- constructor, properties, pos, end_pos);
+ return factory()->NewClassLiteral(block_scope, proxy, extends, constructor,
+ properties, pos, end_pos);
}
@@ -4838,10 +4958,9 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
const AstRawString* name = ParseIdentifier(kAllowRestrictedIdentifiers,
CHECK_OK);
Scanner::Location spread_pos;
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ZoneList<Expression*>* args =
ParseArguments(&spread_pos, &classifier, CHECK_OK);
- args = RewriteNonPatternArguments(args, &classifier, CHECK_OK);
DCHECK(!spread_pos.IsValid());
@@ -5051,6 +5170,12 @@ void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) {
isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
}
}
+ if (scanner_.FoundHtmlComment()) {
+ isolate->CountUsage(v8::Isolate::kHtmlComment);
+ if (script->line_offset() == 0 && script->column_offset() == 0) {
+ isolate->CountUsage(v8::Isolate::kHtmlCommentInExternalScript);
+ }
+ }
isolate->counters()->total_preparse_skipped()->Increment(
total_preparse_skipped_);
}
@@ -5404,143 +5529,1379 @@ void ParserTraits::RewriteDestructuringAssignments() {
}
-Expression* ParserTraits::RewriteNonPattern(
- Expression* expr, const ExpressionClassifier* classifier, bool* ok) {
- return parser_->RewriteNonPattern(expr, classifier, ok);
+void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
+ bool* ok) {
+ parser_->RewriteNonPattern(classifier, ok);
}
-ZoneList<Expression*>* ParserTraits::RewriteNonPatternArguments(
- ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
- bool* ok) {
- return parser_->RewriteNonPatternArguments(args, classifier, ok);
+Zone* ParserTraits::zone() const {
+ return parser_->function_state_->scope()->zone();
}
-ObjectLiteralProperty* ParserTraits::RewriteNonPatternObjectLiteralProperty(
- ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
- bool* ok) {
- return parser_->RewriteNonPatternObjectLiteralProperty(property, classifier,
- ok);
+ZoneList<Expression*>* ParserTraits::GetNonPatternList() const {
+ return parser_->function_state_->non_patterns_to_rewrite();
}
-Expression* Parser::RewriteNonPattern(Expression* expr,
- const ExpressionClassifier* classifier,
- bool* ok) {
- // For the time being, this does no rewriting at all.
- ValidateExpression(classifier, ok);
- return expr;
-}
+class NonPatternRewriter : public AstExpressionRewriter {
+ public:
+ NonPatternRewriter(uintptr_t stack_limit, Parser* parser)
+ : AstExpressionRewriter(stack_limit), parser_(parser) {}
+ ~NonPatternRewriter() override {}
+ private:
+ bool RewriteExpression(Expression* expr) override {
+ if (expr->IsRewritableExpression()) return true;
+ // Rewrite only what could have been a pattern but is not.
+ if (expr->IsArrayLiteral()) {
+ // Spread rewriting in array literals.
+ ArrayLiteral* lit = expr->AsArrayLiteral();
+ VisitExpressions(lit->values());
+ replacement_ = parser_->RewriteSpreads(lit);
+ return false;
+ }
+ if (expr->IsObjectLiteral()) {
+ return true;
+ }
+ if (expr->IsBinaryOperation() &&
+ expr->AsBinaryOperation()->op() == Token::COMMA) {
+ return true;
+ }
+ // Everything else does not need rewriting.
+ return false;
+ }
-ZoneList<Expression*>* Parser::RewriteNonPatternArguments(
- ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
- bool* ok) {
- // For the time being, this does no rewriting at all.
- ValidateExpression(classifier, ok);
- return args;
-}
+ void VisitObjectLiteralProperty(ObjectLiteralProperty* property) override {
+ if (property == nullptr) return;
+ // Do not rewrite (computed) key expressions
+ AST_REWRITE_PROPERTY(Expression, property, value);
+ }
+ Parser* parser_;
+};
-ObjectLiteralProperty* Parser::RewriteNonPatternObjectLiteralProperty(
- ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
- bool* ok) {
- if (property != nullptr) {
- Expression* key = RewriteNonPattern(property->key(), classifier, ok);
- property->set_key(key);
- Expression* value = RewriteNonPattern(property->value(), classifier, ok);
- property->set_value(value);
+
+void Parser::RewriteNonPattern(ExpressionClassifier* classifier, bool* ok) {
+ ValidateExpression(classifier, ok);
+ if (!*ok) return;
+ auto non_patterns_to_rewrite = function_state_->non_patterns_to_rewrite();
+ int begin = classifier->GetNonPatternBegin();
+ int end = non_patterns_to_rewrite->length();
+ if (begin < end) {
+ NonPatternRewriter rewriter(stack_limit_, this);
+ for (int i = begin; i < end; i++) {
+ DCHECK(non_patterns_to_rewrite->at(i)->IsRewritableExpression());
+ rewriter.Rewrite(non_patterns_to_rewrite->at(i));
+ }
+ non_patterns_to_rewrite->Rewind(begin);
}
- return property;
}
void Parser::RewriteDestructuringAssignments() {
- FunctionState* func = function_state_;
if (!allow_harmony_destructuring_assignment()) return;
- const List<DestructuringAssignment>& assignments =
- func->destructuring_assignments_to_rewrite();
+ const auto& assignments =
+ function_state_->destructuring_assignments_to_rewrite();
for (int i = assignments.length() - 1; i >= 0; --i) {
// Rewrite list in reverse, so that nested assignment patterns are rewritten
// correctly.
- DestructuringAssignment pair = assignments.at(i);
- RewritableAssignmentExpression* to_rewrite =
- pair.assignment->AsRewritableAssignmentExpression();
- Scope* scope = pair.scope;
+ const DestructuringAssignment& pair = assignments.at(i);
+ RewritableExpression* to_rewrite =
+ pair.assignment->AsRewritableExpression();
DCHECK_NOT_NULL(to_rewrite);
if (!to_rewrite->is_rewritten()) {
- PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope);
+ PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite,
+ pair.scope);
}
}
}
+Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
+ // Array literals containing spreads are rewritten using do expressions, e.g.
+ // [1, 2, 3, ...x, 4, ...y, 5]
+ // is roughly rewritten as:
+ // do {
+ // $R = [1, 2, 3];
+ // for ($i of x) %AppendElement($R, $i);
+ // %AppendElement($R, 4);
+ // for ($j of y) %AppendElement($R, $j);
+ // %AppendElement($R, 5);
+ // $R
+ // }
+ // where $R, $i and $j are fresh temporary variables.
+ ZoneList<Expression*>::iterator s = lit->FirstSpread();
+ if (s == lit->EndValue()) return nullptr; // no spread, no rewriting...
+ Variable* result =
+ scope_->NewTemporary(ast_value_factory()->dot_result_string());
+ // NOTE: The value assigned to R is the whole original array literal,
+ // spreads included. This will be fixed before the rewritten AST is returned.
+ // $R = lit
+ Expression* init_result =
+ factory()->NewAssignment(Token::INIT, factory()->NewVariableProxy(result),
+ lit, RelocInfo::kNoPosition);
+ Block* do_block =
+ factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
+ do_block->statements()->Add(
+ factory()->NewExpressionStatement(init_result, RelocInfo::kNoPosition),
+ zone());
+ // Traverse the array literal starting from the first spread.
+ while (s != lit->EndValue()) {
+ Expression* value = *s++;
+ Spread* spread = value->AsSpread();
+ if (spread == nullptr) {
+ // If the element is not a spread, we're adding a single:
+ // %AppendElement($R, value)
+ ZoneList<Expression*>* append_element_args = NewExpressionList(2, zone());
+ append_element_args->Add(factory()->NewVariableProxy(result), zone());
+ append_element_args->Add(value, zone());
+ do_block->statements()->Add(
+ factory()->NewExpressionStatement(
+ factory()->NewCallRuntime(Runtime::kAppendElement,
+ append_element_args,
+ RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition),
+ zone());
+ } else {
+ // If it's a spread, we're adding a for/of loop iterating through it.
+ Variable* each =
+ scope_->NewTemporary(ast_value_factory()->dot_for_string());
+ Expression* subject = spread->expression();
+ Variable* iterator =
+ scope_->NewTemporary(ast_value_factory()->dot_iterator_string());
+ Variable* element =
+ scope_->NewTemporary(ast_value_factory()->dot_result_string());
+ // iterator = subject[Symbol.iterator]()
+ Expression* assign_iterator = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(iterator),
+ GetIterator(subject, factory(), spread->expression_position()),
+ subject->position());
+ // !%_IsJSReceiver(element = iterator.next()) &&
+ // %ThrowIteratorResultNotAnObject(element)
+ Expression* next_element;
+ {
+ // element = iterator.next()
+ Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
+ next_element = BuildIteratorNextResult(iterator_proxy, element,
+ spread->expression_position());
+ }
+ // element.done
+ Expression* element_done;
+ {
+ Expression* done_literal = factory()->NewStringLiteral(
+ ast_value_factory()->done_string(), RelocInfo::kNoPosition);
+ Expression* element_proxy = factory()->NewVariableProxy(element);
+ element_done = factory()->NewProperty(element_proxy, done_literal,
+ RelocInfo::kNoPosition);
+ }
+ // each = element.value
+ Expression* assign_each;
+ {
+ Expression* value_literal = factory()->NewStringLiteral(
+ ast_value_factory()->value_string(), RelocInfo::kNoPosition);
+ Expression* element_proxy = factory()->NewVariableProxy(element);
+ Expression* element_value = factory()->NewProperty(
+ element_proxy, value_literal, RelocInfo::kNoPosition);
+ assign_each = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(each), element_value,
+ RelocInfo::kNoPosition);
+ }
+ // %AppendElement($R, each)
+ Statement* append_body;
+ {
+ ZoneList<Expression*>* append_element_args =
+ NewExpressionList(2, zone());
+ append_element_args->Add(factory()->NewVariableProxy(result), zone());
+ append_element_args->Add(factory()->NewVariableProxy(each), zone());
+ append_body = factory()->NewExpressionStatement(
+ factory()->NewCallRuntime(Runtime::kAppendElement,
+ append_element_args,
+ RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition);
+ }
+ // for (each of spread) %AppendElement($R, each)
+ ForEachStatement* loop = factory()->NewForEachStatement(
+ ForEachStatement::ITERATE, nullptr, RelocInfo::kNoPosition);
+ ForOfStatement* for_of = loop->AsForOfStatement();
+ for_of->Initialize(factory()->NewVariableProxy(each), subject,
+ append_body, iterator, assign_iterator, next_element,
+ element_done, assign_each);
+ do_block->statements()->Add(for_of, zone());
+ }
+ }
+ // Now, rewind the original array literal to truncate everything from the
+ // first spread (included) until the end. This fixes $R's initialization.
+ lit->RewindSpreads();
+ return factory()->NewDoExpression(do_block, result, lit->position());
+}
+
+
void ParserTraits::QueueDestructuringAssignmentForRewriting(Expression* expr) {
- DCHECK(expr->IsRewritableAssignmentExpression());
+ DCHECK(expr->IsRewritableExpression());
parser_->function_state_->AddDestructuringAssignment(
Parser::DestructuringAssignment(expr, parser_->scope_));
}
+void ParserTraits::QueueNonPatternForRewriting(Expression* expr) {
+ DCHECK(expr->IsRewritableExpression());
+ parser_->function_state_->AddNonPatternForRewriting(expr);
+}
+
+
void ParserTraits::SetFunctionNameFromPropertyName(
ObjectLiteralProperty* property, const AstRawString* name) {
Expression* value = property->value();
- if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
- // TODO(adamk): Support computed names.
+ // Computed name setting must happen at runtime.
if (property->is_computed_name()) return;
+
+ // Getter and setter names are handled here because their names
+ // change in ES2015, even though they are not anonymous.
+ auto function = value->AsFunctionLiteral();
+ if (function != nullptr) {
+ bool is_getter = property->kind() == ObjectLiteralProperty::GETTER;
+ bool is_setter = property->kind() == ObjectLiteralProperty::SETTER;
+ if (is_getter || is_setter) {
+ DCHECK_NOT_NULL(name);
+ const AstRawString* prefix =
+ is_getter ? parser_->ast_value_factory()->get_space_string()
+ : parser_->ast_value_factory()->set_space_string();
+ function->set_raw_name(
+ parser_->ast_value_factory()->NewConsString(prefix, name));
+ return;
+ }
+ }
+
+ if (!value->IsAnonymousFunctionDefinition()) return;
DCHECK_NOT_NULL(name);
// Ignore "__proto__" as a name when it's being used to set the [[Prototype]]
// of an object literal.
if (property->kind() == ObjectLiteralProperty::PROTOTYPE) return;
- if (value->IsFunctionLiteral()) {
- auto function = value->AsFunctionLiteral();
- if (function->is_anonymous()) {
- if (property->kind() == ObjectLiteralProperty::GETTER) {
- function->set_raw_name(parser_->ast_value_factory()->NewConsString(
- parser_->ast_value_factory()->get_space_string(), name));
- } else if (property->kind() == ObjectLiteralProperty::SETTER) {
- function->set_raw_name(parser_->ast_value_factory()->NewConsString(
- parser_->ast_value_factory()->set_space_string(), name));
- } else {
- function->set_raw_name(name);
- DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
- }
- }
+ if (function != nullptr) {
+ function->set_raw_name(name);
+ DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
} else {
DCHECK(value->IsClassLiteral());
DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
- auto class_literal = value->AsClassLiteral();
- if (class_literal->raw_name() == nullptr) {
- class_literal->set_raw_name(name);
- }
+ value->AsClassLiteral()->constructor()->set_raw_name(name);
}
}
void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
Expression* identifier) {
- if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
+ if (!value->IsAnonymousFunctionDefinition()) return;
if (!identifier->IsVariableProxy()) return;
auto name = identifier->AsVariableProxy()->raw_name();
DCHECK_NOT_NULL(name);
- if (value->IsFunctionLiteral()) {
- auto function = value->AsFunctionLiteral();
- if (function->is_anonymous()) {
- function->set_raw_name(name);
- }
+ auto function = value->AsFunctionLiteral();
+ if (function != nullptr) {
+ function->set_raw_name(name);
} else {
DCHECK(value->IsClassLiteral());
- auto class_literal = value->AsClassLiteral();
- if (class_literal->raw_name() == nullptr) {
- class_literal->set_raw_name(name);
+ value->AsClassLiteral()->constructor()->set_raw_name(name);
+ }
+}
+
+
+// Desugaring of yield*
+// ====================
+//
+// With the help of do-expressions and function.sent, we desugar yield* into a
+// loop containing a "raw" yield (a yield that doesn't wrap an iterator result
+// object around its argument). Concretely, "yield* iterable" turns into
+// roughly the following code:
+//
+// do {
+// const kNext = 0;
+// const kReturn = 1;
+// const kThrow = 2;
+//
+// let input = function.sent;
+// let mode = kNext;
+// let output = undefined;
+//
+// let iterator = iterable[Symbol.iterator]();
+// if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
+//
+// while (true) {
+// // From the generator to the iterator:
+// // Forward input according to resume mode and obtain output.
+// switch (mode) {
+// case kNext:
+// output = iterator.next(input);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+// break;
+// case kReturn:
+// IteratorClose(iterator, input, output); // See below.
+// break;
+// case kThrow:
+// let iteratorThrow = iterator.throw;
+// if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
+// IteratorClose(iterator); // See below.
+// throw MakeTypeError(kThrowMethodMissing);
+// }
+// output = %_Call(iteratorThrow, iterator, input);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+// break;
+// }
+// if (output.done) break;
+//
+// // From the generator to its user:
+// // Forward output, receive new input, and determine resume mode.
+// mode = kReturn;
+// try {
+// try {
+// RawYield(output); // See explanation above.
+// mode = kNext;
+// } catch (error) {
+// mode = kThrow;
+// }
+// } finally {
+// input = function.sent;
+// continue;
+// }
+// }
+//
+// output.value;
+// }
+//
+// IteratorClose(iterator) expands to the following:
+//
+// let iteratorReturn = iterator.return;
+// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return;
+// let output = %_Call(iteratorReturn, iterator);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+//
+// IteratorClose(iterator, input, output) expands to the following:
+//
+// let iteratorReturn = iterator.return;
+// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
+// output = %_Call(iteratorReturn, iterator, input);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+
+
+Expression* ParserTraits::RewriteYieldStar(
+ Expression* generator, Expression* iterable, 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();
+
+
+ // Forward definition for break/continue statements.
+ WhileStatement* loop = factory->NewWhileStatement(nullptr, nopos);
+
+
+ // let input = undefined;
+ Variable* var_input = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_input;
+ {
+ Expression* input_proxy = factory->NewVariableProxy(var_input);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, input_proxy, factory->NewUndefinedLiteral(nopos), nopos);
+ initialize_input = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // let mode = kNext;
+ Variable* var_mode = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_mode;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+ initialize_mode = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // let output = undefined;
+ Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_output;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, output_proxy, factory->NewUndefinedLiteral(nopos),
+ nopos);
+ initialize_output = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // let iterator = iterable[Symbol.iterator];
+ Variable* var_iterator = scope->NewTemporary(avfactory->empty_string());
+ Statement* get_iterator;
+ {
+ Expression* iterator = GetIterator(iterable, factory, nopos);
+ Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, iterator_proxy, iterator, nopos);
+ get_iterator = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
+ Statement* validate_iterator;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_iterator), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ Expression* call = NewThrowTypeError(
+ MessageTemplate::kSymbolIteratorInvalid, avfactory->empty_string(),
+ nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_iterator = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+
+ // output = iterator.next(input);
+ Statement* call_next;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->next_string(), nopos);
+ Expression* next_property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* input_proxy = factory->NewVariableProxy(var_input);
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(input_proxy, zone);
+ Expression* call = factory->NewCall(next_property, args, nopos);
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
+ call_next = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ Statement* validate_next_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_next_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+
+ // let iteratorThrow = iterator.throw;
+ Variable* var_throw = scope->NewTemporary(avfactory->empty_string());
+ Statement* get_throw;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->throw_string(), nopos);
+ Expression* property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* throw_proxy = factory->NewVariableProxy(var_throw);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, throw_proxy, property, nopos);
+ get_throw = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (IS_NULL_OR_UNDEFINED(iteratorThrow) {
+ // IteratorClose(iterator);
+ // throw MakeTypeError(kThrowMethodMissing);
+ // }
+ Statement* check_throw;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ, factory->NewVariableProxy(var_throw),
+ factory->NewNullLiteral(nopos), nopos);
+
+ Expression* call = NewThrowTypeError(
+ MessageTemplate::kThrowMethodMissing,
+ avfactory->empty_string(), nopos);
+ Statement* throw_call = factory->NewExpressionStatement(call, nopos);
+
+ Block* then = factory->NewBlock(nullptr, 4+1, false, nopos);
+ Variable* var_tmp = scope->NewTemporary(avfactory->empty_string());
+ BuildIteratorClose(
+ then->statements(), var_iterator, factory->NewUndefinedLiteral(nopos),
+ var_tmp);
+ then->statements()->Add(throw_call, zone);
+ check_throw = factory->NewIfStatement(
+ condition, then, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+
+ // output = %_Call(iteratorThrow, iterator, input);
+ Statement* call_throw;
+ {
+ auto args = new (zone) ZoneList<Expression*>(3, zone);
+ args->Add(factory->NewVariableProxy(var_throw), zone);
+ args->Add(factory->NewVariableProxy(var_iterator), zone);
+ args->Add(factory->NewVariableProxy(var_input), zone);
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
+ call_throw = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ Statement* validate_throw_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
}
+
+ validate_throw_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+
+ // if (output.done) break;
+ Statement* if_done;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->done_string(), nopos);
+ Expression* property = factory->NewProperty(output_proxy, literal, nopos);
+ BreakStatement* break_loop = factory->NewBreakStatement(loop, nopos);
+ if_done = factory->NewIfStatement(
+ property, break_loop, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+
+ // mode = kReturn;
+ Statement* set_mode_return;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* kreturn =
+ factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, kreturn, nopos);
+ set_mode_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // RawYield(output);
+ Statement* yield_output;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Yield* yield = factory->NewYield(
+ generator, output_proxy, Yield::kInitial, nopos);
+ yield_output = factory->NewExpressionStatement(yield, nopos);
+ }
+
+
+ // mode = kNext;
+ Statement* set_mode_next;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+ set_mode_next = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // mode = kThrow;
+ Statement* set_mode_throw;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* kthrow =
+ factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos);
+ set_mode_throw = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // input = function.sent;
+ Statement* get_input;
+ {
+ Expression* function_sent = FunctionSentExpression(scope, factory, nopos);
+ Expression* input_proxy = factory->NewVariableProxy(var_input);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, input_proxy, function_sent, nopos);
+ get_input = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // output.value;
+ Statement* get_value;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->value_string(), nopos);
+ Expression* property = factory->NewProperty(output_proxy, literal, nopos);
+ get_value = factory->NewExpressionStatement(property, nopos);
+ }
+
+
+ // Now put things together.
+
+
+ // try { ... } catch(e) { ... }
+ Statement* try_catch;
+ {
+ Block* try_block = factory->NewBlock(nullptr, 2, false, nopos);
+ try_block->statements()->Add(yield_output, zone);
+ try_block->statements()->Add(set_mode_next, zone);
+
+ Block* catch_block = factory->NewBlock(nullptr, 1, false, nopos);
+ catch_block->statements()->Add(set_mode_throw, zone);
+
+ Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+ const AstRawString* name = avfactory->dot_catch_string();
+ Variable* catch_variable =
+ catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
+ Variable::NORMAL);
+
+ try_catch = factory->NewTryCatchStatement(
+ try_block, catch_scope, catch_variable, catch_block, nopos);
}
+
+
+ // try { ... } finally { ... }
+ Statement* try_finally;
+ {
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(try_catch, zone);
+
+ Block* finally = factory->NewBlock(nullptr, 2, false, nopos);
+ finally->statements()->Add(get_input, zone);
+ finally->statements()->Add(
+ factory->NewContinueStatement(loop, nopos), zone);
+
+ try_finally = factory->NewTryFinallyStatement(try_block, finally, nopos);
+ }
+
+
+ // switch (mode) { ... }
+ SwitchStatement* switch_mode = factory->NewSwitchStatement(nullptr, nopos);
+ {
+ auto case_next = new (zone) ZoneList<Statement*>(3, zone);
+ case_next->Add(call_next, zone);
+ case_next->Add(validate_next_output, zone);
+ case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+ auto case_return = new (zone) ZoneList<Statement*>(5, zone);
+ BuildIteratorClose(case_return, var_iterator,
+ factory->NewVariableProxy(var_input, nopos), var_output);
+ case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+ auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
+ case_throw->Add(get_throw, zone);
+ case_throw->Add(check_throw, zone);
+ case_throw->Add(call_throw, zone);
+ case_throw->Add(validate_throw_output, zone);
+ case_throw->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+ auto cases = new (zone) ZoneList<CaseClause*>(3, zone);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* kreturn =
+ factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+ Expression* kthrow =
+ factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+ cases->Add(factory->NewCaseClause(knext, case_next, nopos), zone);
+ cases->Add(factory->NewCaseClause(kreturn, case_return, nopos), zone);
+ cases->Add(factory->NewCaseClause(kthrow, case_throw, nopos), zone);
+
+ switch_mode->Initialize(factory->NewVariableProxy(var_mode), cases);
+ }
+
+
+ // while (true) { ... }
+ // Already defined earlier: WhileStatement* loop = ...
+ {
+ Block* loop_body = factory->NewBlock(nullptr, 4, false, nopos);
+ loop_body->statements()->Add(switch_mode, zone);
+ loop_body->statements()->Add(if_done, zone);
+ loop_body->statements()->Add(set_mode_return, zone);
+ loop_body->statements()->Add(try_finally, zone);
+
+ loop->Initialize(factory->NewBooleanLiteral(true, nopos), loop_body);
+ }
+
+
+ // do { ... }
+ DoExpression* yield_star;
+ {
+ // The rewriter needs to process the get_value statement only, hence we
+ // put the preceding statements into an init block.
+
+ Block* do_block_ = factory->NewBlock(nullptr, 6, true, nopos);
+ do_block_->statements()->Add(initialize_input, zone);
+ do_block_->statements()->Add(initialize_mode, zone);
+ do_block_->statements()->Add(initialize_output, zone);
+ do_block_->statements()->Add(get_iterator, zone);
+ do_block_->statements()->Add(validate_iterator, zone);
+ do_block_->statements()->Add(loop, zone);
+
+ Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
+ do_block->statements()->Add(do_block_, zone);
+ do_block->statements()->Add(get_value, zone);
+
+ Variable* dot_result = scope->NewTemporary(avfactory->dot_result_string());
+ yield_star = factory->NewDoExpression(do_block, dot_result, nopos);
+ Rewriter::Rewrite(parser_, yield_star, avfactory);
+ }
+
+ 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) {
+ 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,
+ Expression* input,
+ Variable* var_output) {
+ //
+ // This function adds four statements to [statements], corresponding to the
+ // following code:
+ //
+ // let iteratorReturn = iterator.return;
+ // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
+ // output = %_Call(iteratorReturn, iterator);
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ //
+
+ const int nopos = RelocInfo::kNoPosition;
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto zone = parser_->zone();
+
+ // let iteratorReturn = iterator.return;
+ Variable* var_return = var_output; // Reusing the output variable.
+ Statement* get_return;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->return_string(), nopos);
+ Expression* property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* return_proxy = factory->NewVariableProxy(var_return);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, return_proxy, property, nopos);
+ get_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
+ Statement* check_return;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ, factory->NewVariableProxy(var_return),
+ factory->NewNullLiteral(nopos), nopos);
+
+ Statement* return_input = factory->NewReturnStatement(input, nopos);
+
+ check_return = factory->NewIfStatement(
+ condition, return_input, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+ // output = %_Call(iteratorReturn, iterator);
+ Statement* call_return;
+ {
+ auto args = new (zone) ZoneList<Expression*>(3, zone);
+ args->Add(factory->NewVariableProxy(var_return), zone);
+ args->Add(factory->NewVariableProxy(iterator), zone);
+
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, output_proxy, call, nopos);
+ call_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
+ Statement* validate_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+ statements->Add(get_return, zone);
+ statements->Add(check_return, zone);
+ statements->Add(call_return, zone);
+ statements->Add(validate_output, zone);
+}
+
+
+// Runtime encoding of different completion modes.
+enum ForOfLoopBodyCompletion { BODY_COMPLETED, BODY_ABORTED, BODY_THREW };
+
+void ParserTraits::BuildIteratorCloseForCompletion(
+ ZoneList<Statement*>* statements, Variable* iterator,
+ Variable* completion) {
+ //
+ // This function adds two statements to [statements], corresponding to the
+ // following code:
+ //
+ // let iteratorReturn = iterator.return;
+ // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
+ // let output;
+ // if (completion === BODY_THREW) {
+ // if (!IS_CALLABLE(iteratorReturn)) {
+ // throw MakeTypeError(kReturnMethodNotCallable);
+ // }
+ // try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
+ // } else {
+ // output = %_Call(iteratorReturn, iterator);
+ // }
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ // }
+ //
+
+ const int nopos = RelocInfo::kNoPosition;
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto scope = parser_->scope_;
+ auto zone = parser_->zone();
+
+ // let output;
+ Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+
+ // let iteratorReturn = iterator.return;
+ Variable* var_return = var_output; // Reusing the output variable.
+ Statement* get_return;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->return_string(), nopos);
+ Expression* property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* return_proxy = factory->NewVariableProxy(var_return);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, return_proxy, property, nopos);
+ get_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (!IS_CALLABLE(iteratorReturn)) {
+ // throw MakeTypeError(kReturnMethodNotCallable);
+ // }
+ Statement* check_return_callable;
+ {
+ Expression* throw_expr = NewThrowTypeError(
+ MessageTemplate::kReturnMethodNotCallable,
+ avfactory->empty_string(), nopos);
+ check_return_callable = CheckCallable(var_return, throw_expr);
+ }
+
+ // output = %_Call(iteratorReturn, iterator);
+ Statement* call_return;
+ {
+ auto args = new (zone) ZoneList<Expression*>(2, zone);
+ args->Add(factory->NewVariableProxy(var_return), zone);
+ args->Add(factory->NewVariableProxy(iterator), zone);
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, output_proxy, call, nopos);
+ call_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
+ Statement* try_call_return;
+ {
+ auto args = new (zone) ZoneList<Expression*>(2, zone);
+ args->Add(factory->NewVariableProxy(var_return), zone);
+ args->Add(factory->NewVariableProxy(iterator), zone);
+
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
+
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(
+ factory->NewExpressionStatement(assignment, nopos), zone);
+
+ Block* catch_block = factory->NewBlock(nullptr, 0, false, nopos);
+
+ Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+ Variable* catch_variable = catch_scope->DeclareLocal(
+ avfactory->dot_catch_string(), VAR, kCreatedInitialized,
+ Variable::NORMAL);
+
+ try_call_return = factory->NewTryCatchStatement(
+ try_block, catch_scope, catch_variable, catch_block, nopos);
+ }
+
+ // if (completion === ABRUPT_THROW) {
+ // #check_return_callable;
+ // #try_call_return;
+ // } else {
+ // #call_return;
+ // }
+ Statement* call_return_carefully;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(completion),
+ factory->NewSmiLiteral(BODY_THREW, nopos), nopos);
+
+ Block* then_block = factory->NewBlock(nullptr, 2, false, nopos);
+ then_block->statements()->Add(check_return_callable, zone);
+ then_block->statements()->Add(try_call_return, zone);
+
+ call_return_carefully =
+ factory->NewIfStatement(condition, then_block, call_return, nopos);
+ }
+
+ // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
+ Statement* validate_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+ // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { ... }
+ Statement* maybe_call_return;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ, factory->NewVariableProxy(var_return),
+ factory->NewNullLiteral(nopos), nopos);
+
+ Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(call_return_carefully, zone);
+ block->statements()->Add(validate_output, zone);
+
+ maybe_call_return = factory->NewIfStatement(
+ condition, factory->NewEmptyStatement(nopos), block, nopos);
+ }
+
+
+ statements->Add(get_return, zone);
+ statements->Add(maybe_call_return, zone);
+}
+
+
+Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
+ if (!FLAG_harmony_iterator_close) return loop;
+
+ //
+ // This function replaces the loop with the following wrapping:
+ //
+ // let completion = BODY_COMPLETED;
+ // try {
+ // #loop;
+ // } catch(e) {
+ // if (completion === BODY_ABORTED) completion = BODY_THREW;
+ // throw e;
+ // } finally {
+ // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
+ // #BuildIteratorClose(#iterator, completion) // See above.
+ // }
+ // }
+ //
+ // where the loop's body is wrapped as follows:
+ //
+ // {
+ // {{completion = BODY_ABORTED;}}
+ // #loop-body
+ // {{completion = BODY_COMPLETED;}}
+ // }
+
+ const int nopos = RelocInfo::kNoPosition;
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto scope = parser_->scope_;
+ auto zone = parser_->zone();
+
+ // let completion = BODY_COMPLETED;
+ Variable* var_completion = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_completion;
+ {
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
+ initialize_completion =
+ factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (completion === BODY_ABORTED) completion = BODY_THREW;
+ Statement* set_completion_throw;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
+ factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
+
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_THREW, nopos),
+ nopos);
+ Statement* statement = factory->NewExpressionStatement(assignment, nopos);
+ set_completion_throw = factory->NewIfStatement(
+ condition, statement, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+ // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
+ // #BuildIteratorClose(#iterator, completion)
+ // }
+ Block* maybe_close;
+ {
+ Expression* condition1 = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
+ factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
+ Expression* condition2 = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(loop->iterator()),
+ factory->NewUndefinedLiteral(nopos), nopos);
+ Expression* condition = factory->NewBinaryOperation(
+ Token::OR, condition1, condition2, nopos);
+
+ Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+ BuildIteratorCloseForCompletion(
+ block->statements(), loop->iterator(), var_completion);
+ DCHECK(block->statements()->length() == 2);
+
+ maybe_close = factory->NewBlock(nullptr, 1, false, nopos);
+ maybe_close->statements()->Add(factory->NewIfStatement(
+ condition, factory->NewEmptyStatement(nopos), block, nopos), zone);
+ }
+
+ // try { #try_block }
+ // catch(e) {
+ // #set_completion_throw;
+ // throw e;
+ // }
+ Statement* try_catch;
+ {
+ Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+ Variable* catch_variable = catch_scope->DeclareLocal(
+ avfactory->dot_catch_string(), VAR, kCreatedInitialized,
+ Variable::NORMAL);
+
+ Statement* rethrow;
+ {
+ Expression* proxy = factory->NewVariableProxy(catch_variable);
+ rethrow = factory->NewExpressionStatement(
+ factory->NewThrow(proxy, nopos), nopos);
+ }
+
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(loop, zone);
+
+ Block* catch_block = factory->NewBlock(nullptr, 2, false, nopos);
+ catch_block->statements()->Add(set_completion_throw, zone);
+ catch_block->statements()->Add(rethrow, zone);
+
+ try_catch = factory->NewTryCatchStatement(
+ try_block, catch_scope, catch_variable, catch_block, nopos);
+ }
+
+ // try { #try_catch } finally { #maybe_close }
+ Statement* try_finally;
+ {
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(try_catch, zone);
+
+ try_finally =
+ factory->NewTryFinallyStatement(try_block, maybe_close, nopos);
+ }
+
+ // #initialize_completion;
+ // #try_finally;
+ Statement* final_loop;
+ {
+ Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(initialize_completion, zone);
+ block->statements()->Add(try_finally, zone);
+ final_loop = block;
+ }
+
+ // {{completion = BODY_ABORTED;}}
+ Statement* set_completion_break;
+ {
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
+
+ Block* block = factory->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory->NewExpressionStatement(assignment, nopos), zone);
+ set_completion_break = block;
+ }
+
+ // {{completion = BODY_COMPLETED;}}
+ Statement* set_completion_normal;
+ {
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_COMPLETED, nopos),
+ nopos);
+
+ Block* block = factory->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory->NewExpressionStatement(assignment, nopos), zone);
+ set_completion_normal = block;
+ }
+
+ // { #set_completion_break; #loop-body; #set_completion_normal }
+ Block* new_body = factory->NewBlock(nullptr, 2, false, nopos);
+ new_body->statements()->Add(set_completion_break, zone);
+ new_body->statements()->Add(loop->body(), zone);
+ new_body->statements()->Add(set_completion_normal, zone);
+
+ loop->set_body(new_body);
+ return final_loop;
}