diff options
author | Michaël Zasso <targos@protonmail.com> | 2016-05-27 16:37:42 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2016-06-29 09:04:28 +0200 |
commit | 2cc29517966de7257a2f1b34c58c77225a21e05d (patch) | |
tree | 210bd177df2f06eec16e1e22edafdbcbffe66f8a /deps/v8/src/parsing/parser.cc | |
parent | bbf3838c70aaec1dd296fa75ae334fd1c7866df3 (diff) | |
download | android-node-v8-2cc29517966de7257a2f1b34c58c77225a21e05d.tar.gz android-node-v8-2cc29517966de7257a2f1b34c58c77225a21e05d.tar.bz2 android-node-v8-2cc29517966de7257a2f1b34c58c77225a21e05d.zip |
deps: update V8 to 5.1.281.69
Pick up the latest branch-head for V8 5.1. This branch brings in
improved language support and performance improvements. For full
details: http://v8project.blogspot.com/2016/04/v8-release-51.html
* Picks up the latest branch head for 5.1 [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/+/dc81244
[2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/c8c8665
PR-URL: https://github.com/nodejs/node/pull/7016
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/parsing/parser.cc')
-rw-r--r-- | deps/v8/src/parsing/parser.cc | 1243 |
1 files changed, 615 insertions, 628 deletions
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 968e8ed4ff..c9897cdd92 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -439,6 +439,14 @@ bool ParserTraits::ShortcutNumericLiteralBinaryExpression( *x = factory->NewNumberLiteral(value, pos, has_dot); return true; } + case Token::EXP: { + double value = Pow(x_val, y_val); + int int_value = static_cast<int>(value); + *x = factory->NewNumberLiteral( + int_value == value && value != -0.0 ? int_value : value, pos, + has_dot); + return true; + } default: break; } @@ -491,6 +499,20 @@ Expression* ParserTraits::BuildUnaryExpression(Expression* expression, return factory->NewUnaryOperation(op, expression, pos); } +Expression* ParserTraits::BuildIteratorResult(Expression* value, bool done) { + int pos = RelocInfo::kNoPosition; + AstNodeFactory* factory = parser_->factory(); + Zone* zone = parser_->zone(); + + if (value == nullptr) value = factory->NewUndefinedLiteral(pos); + + auto args = new (zone) ZoneList<Expression*>(2, zone); + args->Add(value, zone); + args->Add(factory->NewBooleanLiteral(done, pos), zone); + + return factory->NewCallRuntime(Runtime::kInlineCreateIterResultObject, args, + pos); +} Expression* ParserTraits::NewThrowReferenceError( MessageTemplate::Template message, int pos) { @@ -734,14 +756,17 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral( function_token_position, type, language_mode, ok); } - ClassLiteral* ParserTraits::ParseClassLiteral( - const AstRawString* name, Scanner::Location class_name_location, - bool name_is_strict_reserved, int pos, bool* ok) { - return parser_->ParseClassLiteral(name, class_name_location, + Type::ExpressionClassifier* classifier, const AstRawString* name, + Scanner::Location class_name_location, bool name_is_strict_reserved, + int pos, bool* ok) { + return parser_->ParseClassLiteral(classifier, name, class_name_location, name_is_strict_reserved, pos, ok); } +void ParserTraits::MarkTailPosition(Expression* expression) { + expression->MarkTail(); +} Parser::Parser(ParseInfo* info) : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(), @@ -762,18 +787,18 @@ Parser::Parser(ParseInfo* info) DCHECK(!info->script().is_null() || info->source_stream() != NULL); set_allow_lazy(info->allow_lazy_parsing()); set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); + set_allow_tailcalls(FLAG_harmony_tailcalls && !info->is_native() && + info->isolate()->is_tail_call_elimination_enabled()); set_allow_harmony_sloppy(FLAG_harmony_sloppy); set_allow_harmony_sloppy_function(FLAG_harmony_sloppy_function); set_allow_harmony_sloppy_let(FLAG_harmony_sloppy_let); - set_allow_harmony_default_parameters(FLAG_harmony_default_parameters); - set_allow_harmony_destructuring_bind(FLAG_harmony_destructuring_bind); - set_allow_harmony_destructuring_assignment( - FLAG_harmony_destructuring_assignment); - set_allow_strong_mode(FLAG_strong_mode); - 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); + set_allow_harmony_restrictive_declarations( + FLAG_harmony_restrictive_declarations); + set_allow_harmony_exponentiation_operator( + FLAG_harmony_exponentiation_operator); for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; @@ -901,7 +926,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { kNormalFunction, &function_factory); // Don't count the mode in the use counters--give the program a chance - // to enable script/module-wide strict/strong mode below. + // to enable script/module-wide strict mode below. scope_->SetLanguageMode(info->language_mode()); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); bool ok = true; @@ -926,8 +951,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { // unchanged if the property already exists. InsertSloppyBlockFunctionVarBindings(scope, &ok); } - if (ok && (is_strict(language_mode()) || allow_harmony_sloppy() || - allow_harmony_destructuring_bind())) { + if (ok) { CheckConflictingVarDeclarations(scope_, &ok); } @@ -1154,28 +1178,7 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token, } Scanner::Location token_loc = scanner()->peek_location(); - Scanner::Location old_this_loc = function_state_->this_location(); - Scanner::Location old_super_loc = function_state_->super_location(); Statement* stat = ParseStatementListItem(CHECK_OK); - - if (is_strong(language_mode()) && scope_->is_function_scope() && - IsClassConstructor(function_state_->kind())) { - Scanner::Location this_loc = function_state_->this_location(); - Scanner::Location super_loc = function_state_->super_location(); - if (this_loc.beg_pos != old_this_loc.beg_pos && - this_loc.beg_pos != token_loc.beg_pos) { - ReportMessageAt(this_loc, MessageTemplate::kStrongConstructorThis); - *ok = false; - return nullptr; - } - if (super_loc.beg_pos != old_super_loc.beg_pos && - super_loc.beg_pos != token_loc.beg_pos) { - ReportMessageAt(super_loc, MessageTemplate::kStrongConstructorSuper); - *ok = false; - return nullptr; - } - } - if (stat == NULL || stat->IsEmpty()) { directive_prologue = false; // End of directive prologue. continue; @@ -1189,43 +1192,21 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token, if ((e_stat = stat->AsExpressionStatement()) != NULL && (literal = e_stat->expression()->AsLiteral()) != NULL && literal->raw_value()->IsString()) { - // Check "use strict" directive (ES5 14.1), "use asm" directive, and - // "use strong" directive (experimental). + // Check "use strict" directive (ES5 14.1), "use asm" directive. bool use_strict_found = literal->raw_value()->AsString() == ast_value_factory()->use_strict_string() && token_loc.end_pos - token_loc.beg_pos == ast_value_factory()->use_strict_string()->length() + 2; - bool use_strong_found = - allow_strong_mode() && - literal->raw_value()->AsString() == - ast_value_factory()->use_strong_string() && - token_loc.end_pos - token_loc.beg_pos == - ast_value_factory()->use_strong_string()->length() + 2; - if (use_strict_found || use_strong_found) { - // Strong mode implies strict mode. If there are several "use strict" - // / "use strong" directives, do the strict mode changes only once. + if (use_strict_found) { if (is_sloppy(scope_->language_mode())) { RaiseLanguageMode(STRICT); } - if (use_strong_found) { - RaiseLanguageMode(STRONG); - if (IsClassConstructor(function_state_->kind())) { - // "use strong" cannot occur in a class constructor body, to avoid - // unintuitive strong class object semantics. - ParserTraits::ReportMessageAt( - token_loc, MessageTemplate::kStrongConstructorDirective); - *ok = false; - return nullptr; - } - } if (!scope_->HasSimpleParameters()) { // TC39 deemed "use strict" directives to be an error when occurring // in the body of a function with non-simple parameter list, on // 29/7/2015. https://goo.gl/ueA7Ln - // - // In V8, this also applies to "use strong " directives. const AstRawString* string = literal->raw_value()->AsString(); ParserTraits::ReportMessageAt( token_loc, MessageTemplate::kIllegalLanguageModeDirective, @@ -1294,7 +1275,7 @@ Statement* Parser::ParseStatementListItem(bool* ok) { default: break; } - return ParseStatement(NULL, ok); + return ParseStatement(NULL, kAllowLabelledFunctionStatement, ok); } @@ -1445,10 +1426,6 @@ ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) { *ok = false; ReportMessage(MessageTemplate::kStrictEvalArguments); return NULL; - } else if (is_strong(language_mode()) && IsUndefined(local_name)) { - *ok = false; - ReportMessage(MessageTemplate::kStrongUndefined); - return NULL; } VariableProxy* proxy = NewUnresolved(local_name, IMPORT); ImportDeclaration* declaration = @@ -1594,9 +1571,9 @@ Statement* Parser::ParseExportDefault(bool* ok) { 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); + default_export = ParseClassLiteral(nullptr, default_string, + Scanner::Location::invalid(), false, + position(), CHECK_OK); result = factory()->NewEmptyStatement(RelocInfo::kNoPosition); } else { result = ParseClassDeclaration(&names, CHECK_OK); @@ -1748,8 +1725,8 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { return result; } - Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, + AllowLabelledFunctionStatement allow_function, bool* ok) { // Statement :: // EmptyStatement @@ -1759,12 +1736,12 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, Next(); return factory()->NewEmptyStatement(RelocInfo::kNoPosition); } - return ParseSubStatement(labels, ok); + return ParseSubStatement(labels, allow_function, ok); } - -Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels, - bool* ok) { +Statement* Parser::ParseSubStatement( + ZoneList<const AstRawString*>* labels, + AllowLabelledFunctionStatement allow_function, bool* ok) { // Statement :: // Block // VariableStatement @@ -1793,12 +1770,6 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels, return ParseBlock(labels, ok); case Token::SEMICOLON: - if (is_strong(language_mode())) { - ReportMessageAt(scanner()->peek_location(), - MessageTemplate::kStrongEmpty); - *ok = false; - return NULL; - } Next(); return factory()->NewEmptyStatement(RelocInfo::kNoPosition); @@ -1839,26 +1810,18 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels, case Token::SWITCH: return ParseSwitchStatement(labels, ok); - case Token::FUNCTION: { - // FunctionDeclaration is only allowed in the context of SourceElements - // (Ecma 262 5th Edition, clause 14): - // SourceElement: - // Statement - // FunctionDeclaration - // Common language extension is to allow function declaration in place - // of any statement. This language extension is disabled in strict mode. - // - // In Harmony mode, this case also handles the extension: - // Statement: - // GeneratorDeclaration - if (is_strict(language_mode())) { - ReportMessageAt(scanner()->peek_location(), - MessageTemplate::kStrictFunction); - *ok = false; - return NULL; - } - return ParseFunctionDeclaration(NULL, ok); - } + case Token::FUNCTION: + // FunctionDeclaration only allowed as a StatementListItem, not in + // an arbitrary Statement position. Exceptions such as + // ES#sec-functiondeclarations-in-ifstatement-statement-clauses + // are handled by calling ParseScopedStatement rather than + // ParseSubStatement directly. + ReportMessageAt(scanner()->peek_location(), + is_strict(language_mode()) + ? MessageTemplate::kStrictFunction + : MessageTemplate::kSloppyFunction); + *ok = false; + return nullptr; case Token::DEBUGGER: return ParseDebuggerStatement(ok); @@ -1866,17 +1829,8 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels, case Token::VAR: return ParseVariableStatement(kStatement, NULL, ok); - case Token::CONST: - // In ES6 CONST is not allowed as a Statement, only as a - // LexicalDeclaration, however we continue to allow it in sloppy mode for - // backwards compatibility. - if (is_sloppy(language_mode()) && allow_legacy_const()) { - return ParseVariableStatement(kStatement, NULL, ok); - } - - // Fall through. default: - return ParseExpressionOrLabelledStatement(labels, ok); + return ParseExpressionOrLabelledStatement(labels, allow_function, ok); } } @@ -1958,13 +1912,6 @@ Variable* Parser::Declare(Declaration* declaration, } var = declaration_scope->DeclareLocal( 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 @@ -2160,12 +2107,10 @@ Statement* Parser::ParseFunctionDeclaration( // In ES6, a function behaves as a lexical binding, except in // a script scope, or the initial scope of eval or another function. VariableMode mode = - is_strong(language_mode()) - ? CONST - : (is_strict(language_mode()) || allow_harmony_sloppy_function()) && - !scope_->is_declaration_scope() - ? LET - : VAR; + (is_strict(language_mode()) || allow_harmony_sloppy_function()) && + !scope_->is_declaration_scope() + ? LET + : VAR; VariableProxy* proxy = NewUnresolved(name, mode); Declaration* declaration = factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos); @@ -2211,13 +2156,12 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, bool is_strict_reserved = false; const AstRawString* name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); - ClassLiteral* value = ParseClassLiteral(name, scanner()->location(), + ClassLiteral* value = ParseClassLiteral(nullptr, name, scanner()->location(), is_strict_reserved, pos, CHECK_OK); - VariableMode mode = is_strong(language_mode()) ? CONST : LET; - VariableProxy* proxy = NewUnresolved(name, mode); + VariableProxy* proxy = NewUnresolved(name, LET); Declaration* declaration = - factory()->NewVariableDeclaration(proxy, mode, scope_, pos); + factory()->NewVariableDeclaration(proxy, LET, scope_, pos); Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); proxy->var()->set_initializer_position(position()); Assignment* assignment = @@ -2337,23 +2281,12 @@ Block* Parser::ParseVariableDeclarations( } if (peek() == Token::VAR) { - if (is_strong(language_mode())) { - Scanner::Location location = scanner()->peek_location(); - ReportMessageAt(location, MessageTemplate::kStrongVar); - *ok = false; - return nullptr; - } Consume(Token::VAR); } else if (peek() == Token::CONST && allow_const()) { Consume(Token::CONST); - if (is_sloppy(language_mode()) && allow_legacy_const()) { - parsing_result->descriptor.mode = CONST_LEGACY; - ++use_counts_[v8::Isolate::kLegacyConst]; - } else { - DCHECK(is_strict(language_mode()) || allow_harmony_sloppy()); - DCHECK(var_context != kStatement); - parsing_result->descriptor.mode = CONST; - } + DCHECK(is_strict(language_mode()) || allow_harmony_sloppy()); + DCHECK(var_context != kStatement); + parsing_result->descriptor.mode = CONST; } else if (peek() == Token::LET && allow_let()) { Consume(Token::LET); DCHECK(var_context != kStatement); @@ -2378,17 +2311,11 @@ Block* Parser::ParseVariableDeclarations( int decl_pos = peek_position(); { ExpressionClassifier pattern_classifier(this); - Token::Value next = peek(); pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK); ValidateBindingPattern(&pattern_classifier, CHECK_OK); if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { ValidateLetPattern(&pattern_classifier, CHECK_OK); } - if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) { - ReportUnexpectedToken(next); - *ok = false; - return nullptr; - } } Scanner::Location variable_loc = scanner()->location(); @@ -2492,9 +2419,9 @@ static bool ContainsLabel(ZoneList<const AstRawString*>* labels, return false; } - Statement* Parser::ParseExpressionOrLabelledStatement( - ZoneList<const AstRawString*>* labels, bool* ok) { + ZoneList<const AstRawString*>* labels, + AllowLabelledFunctionStatement allow_function, bool* ok) { // ExpressionStatement | LabelledStatement :: // Expression ';' // Identifier ':' Statement @@ -2513,42 +2440,6 @@ Statement* Parser::ParseExpressionOrLabelledStatement( *ok = false; return nullptr; - case Token::THIS: - if (!FLAG_strong_this) break; - // Fall through. - case Token::SUPER: - if (is_strong(language_mode()) && - IsClassConstructor(function_state_->kind())) { - bool is_this = peek() == Token::THIS; - Expression* expr; - ExpressionClassifier classifier(this); - if (is_this) { - expr = ParseStrongInitializationExpression(&classifier, CHECK_OK); - } else { - expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK); - } - RewriteNonPattern(&classifier, CHECK_OK); - switch (peek()) { - case Token::SEMICOLON: - Consume(Token::SEMICOLON); - break; - case Token::RBRACE: - case Token::EOS: - break; - default: - if (!scanner()->HasAnyLineTerminatorBeforeNext()) { - ReportMessageAt(function_state_->this_location(), - is_this - ? MessageTemplate::kStrongConstructorThis - : MessageTemplate::kStrongConstructorSuper); - *ok = false; - return nullptr; - } - } - return factory()->NewExpressionStatement(expr, pos); - } - break; - default: break; } @@ -2581,7 +2472,15 @@ Statement* Parser::ParseExpressionOrLabelledStatement( // during the scope processing. scope_->RemoveUnresolved(var); Expect(Token::COLON, CHECK_OK); - return ParseStatement(labels, ok); + // ES#sec-labelled-function-declarations Labelled Function Declarations + if (peek() == Token::FUNCTION && is_sloppy(language_mode())) { + if (allow_function == kAllowLabelledFunctionStatement) { + return ParseFunctionDeclaration(labels, ok); + } else { + return ParseScopedStatement(labels, true, ok); + } + } + return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok); } // If we have an extension, we allow a native function declaration. @@ -2621,11 +2520,11 @@ IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels, Expect(Token::LPAREN, CHECK_OK); Expression* condition = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - Statement* then_statement = ParseSubStatement(labels, CHECK_OK); + Statement* then_statement = ParseScopedStatement(labels, false, CHECK_OK); Statement* else_statement = NULL; if (peek() == Token::ELSE) { Next(); - else_statement = ParseSubStatement(labels, CHECK_OK); + else_statement = ParseScopedStatement(labels, false, CHECK_OK); } else { else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition); } @@ -2724,15 +2623,6 @@ Statement* Parser::ParseReturnStatement(bool* ok) { return_value = GetLiteralUndefined(position()); } } else { - if (is_strong(language_mode()) && - IsClassConstructor(function_state_->kind())) { - int pos = peek_position(); - ReportMessageAt(Scanner::Location(pos, pos + 1), - MessageTemplate::kStrongConstructorReturnValue); - *ok = false; - return NULL; - } - int pos = peek_position(); return_value = ParseExpression(true, CHECK_OK); @@ -2778,22 +2668,18 @@ Statement* Parser::ParseReturnStatement(bool* ok) { } // ES6 14.6.1 Static Semantics: IsInTailPosition - if (FLAG_harmony_tailcalls && !is_sloppy(language_mode())) { + if (allow_tailcalls() && !is_sloppy(language_mode())) { function_state_->AddExpressionInTailPosition(return_value); } } ExpectSemicolon(CHECK_OK); if (is_generator()) { - Expression* generator = factory()->NewVariableProxy( - function_state_->generator_object_variable()); - Expression* yield = factory()->NewYield( - generator, return_value, Yield::kFinal, loc.beg_pos); - result = factory()->NewExpressionStatement(yield, loc.beg_pos); - } else { - result = factory()->NewReturnStatement(return_value, loc.beg_pos); + return_value = BuildIteratorResult(return_value, true); } + result = factory()->NewReturnStatement(return_value, loc.beg_pos); + Scope* decl_scope = scope_->DeclarationScope(); if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) { ReportMessageAt(loc, MessageTemplate::kIllegalReturn); @@ -2822,27 +2708,11 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, Expression* expr = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - scope_->DeclarationScope()->RecordWithStatement(); Scope* with_scope = NewScope(scope_, WITH_SCOPE); - Block* body; + Statement* body; { BlockState block_state(&scope_, with_scope); with_scope->set_start_position(scanner()->peek_location().beg_pos); - - // The body of the with statement must be enclosed in an additional - // lexical scope in case the body is a FunctionDeclaration. - body = factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition); - Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); - block_scope->set_start_position(scanner()->location().beg_pos); - { - BlockState block_state(&scope_, block_scope); - Target target(&this->target_stack_, body); - Statement* stmt = ParseSubStatement(labels, CHECK_OK); - body->statements()->Add(stmt, zone()); - block_scope->set_end_position(scanner()->location().end_pos); - block_scope = block_scope->FinalizeBlockScope(); - body->set_scope(block_scope); - } - + body = ParseScopedStatement(labels, true, CHECK_OK); with_scope->set_end_position(scanner()->location().end_pos); } return factory()->NewWithStatement(with_scope, expr, body, pos); @@ -2878,13 +2748,6 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { stat = ParseStatementListItem(CHECK_OK); statements->Add(stat, zone()); } - if (is_strong(language_mode()) && stat != NULL && !stat->IsJump() && - peek() != Token::RBRACE) { - ReportMessageAt(scanner()->location(), - MessageTemplate::kStrongSwitchFallthrough); - *ok = false; - return NULL; - } return factory()->NewCaseClause(label, statements, pos); } @@ -3108,8 +2971,11 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { pattern, pattern->position(), factory()->NewVariableProxy(catch_variable)); + Block* init_block = + factory()->NewBlock(nullptr, 8, true, RelocInfo::kNoPosition); PatternRewriter::DeclareAndInitializeVariables( - catch_block, &descriptor, &decl, nullptr, CHECK_OK); + init_block, &descriptor, &decl, nullptr, CHECK_OK); + catch_block->statements()->Add(init_block, zone()); } Expect(Token::LBRACE, CHECK_OK); @@ -3183,7 +3049,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement( Target target(&this->target_stack_, loop); Expect(Token::DO, CHECK_OK); - Statement* body = ParseSubStatement(NULL, CHECK_OK); + Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); Expect(Token::WHILE, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); @@ -3213,7 +3079,7 @@ WhileStatement* Parser::ParseWhileStatement( Expect(Token::LPAREN, CHECK_OK); Expression* cond = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - Statement* body = ParseSubStatement(NULL, CHECK_OK); + Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); if (loop != NULL) loop->Initialize(cond, body); return loop; @@ -3257,76 +3123,15 @@ Expression* Parser::BuildIteratorNextResult(Expression* iterator, throw_call, pos); } - void Parser::InitializeForEachStatement(ForEachStatement* stmt, Expression* each, Expression* subject, - Statement* body, - bool is_destructuring) { - DCHECK(!is_destructuring || allow_harmony_destructuring_assignment()); + Statement* body) { ForOfStatement* for_of = stmt->AsForOfStatement(); - if (for_of != NULL) { - Variable* iterator = scope_->NewTemporary( - ast_value_factory()->dot_iterator_string()); - Variable* result = scope_->NewTemporary( - ast_value_factory()->dot_result_string()); - - Expression* assign_iterator; - Expression* next_result; - Expression* result_done; - Expression* assign_each; - - // iterator = subject[Symbol.iterator]() - // Hackily disambiguate o from o.next and o [Symbol.iterator](). - // TODO(verwaest): Come up with a better solution. - assign_iterator = factory()->NewAssignment( - Token::ASSIGN, factory()->NewVariableProxy(iterator), - GetIterator(subject, factory(), subject->position() - 2), - subject->position()); - - // !%_IsJSReceiver(result = iterator.next()) && - // %ThrowIteratorResultNotAnObject(result) - { - // result = iterator.next() - Expression* iterator_proxy = factory()->NewVariableProxy(iterator); - // Hackily disambiguate o from o.next and o [Symbol.iterator](). - // TODO(verwaest): Come up with a better solution. - next_result = BuildIteratorNextResult(iterator_proxy, result, - subject->position() - 1); - } - - // result.done - { - Expression* done_literal = factory()->NewStringLiteral( - ast_value_factory()->done_string(), RelocInfo::kNoPosition); - Expression* result_proxy = factory()->NewVariableProxy(result); - result_done = factory()->NewProperty( - result_proxy, done_literal, RelocInfo::kNoPosition); - } - - // each = result.value - { - Expression* value_literal = factory()->NewStringLiteral( - ast_value_factory()->value_string(), RelocInfo::kNoPosition); - Expression* result_proxy = factory()->NewVariableProxy(result); - Expression* result_value = factory()->NewProperty( - result_proxy, value_literal, RelocInfo::kNoPosition); - assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value, - RelocInfo::kNoPosition); - if (is_destructuring) { - assign_each = PatternRewriter::RewriteDestructuringAssignment( - this, assign_each->AsAssignment(), scope_); - } - } - - for_of->Initialize(each, subject, body, - iterator, - assign_iterator, - next_result, - result_done, - assign_each); + InitializeForOfStatement(for_of, each, subject, body, + RelocInfo::kNoPosition); } else { - if (is_destructuring) { + if (each->IsArrayLiteral() || each->IsObjectLiteral()) { Variable* temp = scope_->NewTemporary(ast_value_factory()->empty_string()); VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); @@ -3347,6 +3152,70 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, } } +void Parser::InitializeForOfStatement(ForOfStatement* for_of, Expression* each, + Expression* iterable, Statement* body, + int iterable_pos) { + Variable* iterator = + scope_->NewTemporary(ast_value_factory()->dot_iterator_string()); + Variable* result = + scope_->NewTemporary(ast_value_factory()->dot_result_string()); + + Expression* assign_iterator; + Expression* next_result; + Expression* result_done; + Expression* assign_each; + + // Hackily disambiguate o from o.next and o [Symbol.iterator](). + // TODO(verwaest): Come up with a better solution. + int get_iterator_pos = iterable_pos != RelocInfo::kNoPosition + ? iterable_pos + : iterable->position() - 2; + int next_result_pos = iterable_pos != RelocInfo::kNoPosition + ? iterable_pos + : iterable->position() - 1; + + // iterator = iterable[Symbol.iterator]() + assign_iterator = factory()->NewAssignment( + Token::ASSIGN, factory()->NewVariableProxy(iterator), + GetIterator(iterable, factory(), get_iterator_pos), iterable->position()); + + // !%_IsJSReceiver(result = iterator.next()) && + // %ThrowIteratorResultNotAnObject(result) + { + // result = iterator.next() + Expression* iterator_proxy = factory()->NewVariableProxy(iterator); + next_result = + BuildIteratorNextResult(iterator_proxy, result, next_result_pos); + } + + // result.done + { + Expression* done_literal = factory()->NewStringLiteral( + ast_value_factory()->done_string(), RelocInfo::kNoPosition); + Expression* result_proxy = factory()->NewVariableProxy(result); + result_done = factory()->NewProperty(result_proxy, done_literal, + RelocInfo::kNoPosition); + } + + // each = result.value + { + Expression* value_literal = factory()->NewStringLiteral( + ast_value_factory()->value_string(), RelocInfo::kNoPosition); + Expression* result_proxy = factory()->NewVariableProxy(result); + Expression* result_value = factory()->NewProperty( + result_proxy, value_literal, RelocInfo::kNoPosition); + assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value, + RelocInfo::kNoPosition); + if (each->IsArrayLiteral() || each->IsObjectLiteral()) { + assign_each = PatternRewriter::RewriteDestructuringAssignment( + this, assign_each->AsAssignment(), scope_); + } + } + + for_of->Initialize(each, iterable, body, iterator, assign_iterator, + next_result, result_done, assign_each); +} + Statement* Parser::DesugarLexicalBindingsInForStatement( Scope* inner_scope, VariableMode mode, ZoneList<const AstRawString*>* names, ForStatement* loop, Statement* init, Expression* cond, Statement* next, @@ -3595,6 +3464,28 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( return outer_block; } +Statement* Parser::ParseScopedStatement(ZoneList<const AstRawString*>* labels, + bool legacy, bool* ok) { + if (is_strict(language_mode()) || peek() != Token::FUNCTION || + (legacy && allow_harmony_restrictive_declarations())) { + return ParseSubStatement(labels, kDisallowLabelledFunctionStatement, ok); + } else { + if (legacy) { + ++use_counts_[v8::Isolate::kLegacyFunctionDeclaration]; + } + // Make a block around the statement for a lexical binding + // is introduced by a FunctionDeclaration. + Scope* body_scope = NewScope(scope_, BLOCK_SCOPE); + BlockState block_state(&scope_, body_scope); + Block* block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); + Statement* body = ParseFunctionDeclaration(NULL, CHECK_OK); + block->statements()->Add(body, zone()); + body_scope->set_end_position(scanner()->location().end_pos); + body_scope = body_scope->FinalizeBlockScope(); + block->set_scope(body_scope); + return block; + } +} Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok) { @@ -3617,7 +3508,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ParseVariableDeclarations(kForStatement, &parsing_result, nullptr, CHECK_OK); - ForEachStatement::VisitMode mode; + ForEachStatement::VisitMode mode = ForEachStatement::ENUMERATE; int each_beg_pos = scanner()->location().beg_pos; int each_end_pos = scanner()->location().end_pos; @@ -3706,9 +3597,11 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); { + DontCollectExpressionsInTailPositionScope no_tail_calls( + function_state_); BlockState block_state(&scope_, body_scope); - Statement* body = ParseSubStatement(NULL, CHECK_OK); + Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); auto each_initialization_block = factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); @@ -3729,8 +3622,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, 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); + InitializeForEachStatement(loop, temp_proxy, enumerable, body_block); } body_scope->set_end_position(scanner()->location().end_pos); body_scope = body_scope->FinalizeBlockScope(); @@ -3785,7 +3677,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ExpressionClassifier classifier(this); Expression* expression = ParseExpression(false, &classifier, CHECK_OK); int lhs_end_pos = scanner()->location().end_pos; - ForEachStatement::VisitMode mode; + ForEachStatement::VisitMode mode = ForEachStatement::ENUMERATE; is_let_identifier_expression = expression->IsVariableProxy() && expression->AsVariableProxy()->raw_name() == @@ -3793,9 +3685,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, bool is_for_each = CheckInOrOf(&mode, ok); if (!*ok) return nullptr; - bool is_destructuring = - is_for_each && allow_harmony_destructuring_assignment() && - (expression->IsArrayLiteral() || expression->IsObjectLiteral()); + bool is_destructuring = is_for_each && (expression->IsArrayLiteral() || + expression->IsObjectLiteral()); if (is_destructuring) { ValidateAssignmentPattern(&classifier, CHECK_OK); @@ -3825,25 +3716,10 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, Expect(Token::RPAREN, CHECK_OK); - // Make a block around the statement in case a lexical binding - // is introduced, e.g. by a FunctionDeclaration. - // This block must not use for_scope as its scope because if a - // lexical binding is introduced which overlaps with the for-in/of, - // expressions in head of the loop should actually have variables - // resolved in the outer scope. - Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE); - { - 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); - } + // For legacy compat reasons, give for loops similar treatment to + // if statements in allowing a function declaration for a body + Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); + InitializeForEachStatement(loop, expression, enumerable, body); Statement* final_loop = loop->IsForOfStatement() ? FinalizeForOfStatement( @@ -3900,7 +3776,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, } Expect(Token::RPAREN, CHECK_OK); - body = ParseSubStatement(NULL, CHECK_OK); + body = ParseScopedStatement(NULL, true, CHECK_OK); } Statement* result = NULL; @@ -4064,7 +3940,6 @@ void ParserTraits::ParseArrowFunctionFormalParameters( parser_->scope_->RemoveUnresolved(expr->AsVariableProxy()); } else if (expr->IsAssignment()) { Assignment* assignment = expr->AsAssignment(); - DCHECK(parser_->allow_harmony_default_parameters()); DCHECK(!assignment->is_compound()); initializer = assignment->value(); expr = assignment->target(); @@ -4227,7 +4102,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( if (is_generator) { // For generators, allocating variables in contexts is currently a win // because it minimizes the work needed to suspend and resume an - // activation. + // activation. The machine code produced for generators (by full-codegen) + // relies on this forced context allocation, but not in an essential way. scope_->ForceContextAllocation(); // Calling a generator returns a generator object. That object is stored @@ -4347,7 +4223,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // temp_zone is deallocated. These objects are instead allocated in a // parser-persistent zone (see parser_zone_ in AstNodeFactory). { - Zone temp_zone; + Zone temp_zone(zone()->allocator()); AstNodeFactory::BodyScope inner(factory(), &temp_zone, use_temp_zone); body = ParseEagerFunctionBody(function_name, pos, formals, kind, @@ -4365,16 +4241,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // Parsing the body may change the language mode in our scope. language_mode = scope->language_mode(); - if (is_strong(language_mode) && IsSubclassConstructor(kind)) { - if (!function_state.super_location().IsValid()) { - ReportMessageAt(function_name_location, - MessageTemplate::kStrongSuperCallMissing, - kReferenceError); - *ok = false; - return nullptr; - } - } - // Validate name and parameter names. We can do this only after parsing the // function, since the function can declare itself strict. CheckFunctionName(language_mode, function_name, function_name_validity, @@ -4391,10 +4257,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( if (is_sloppy(language_mode) && allow_harmony_sloppy_function()) { InsertSloppyBlockFunctionVarBindings(scope, CHECK_OK); } - if (is_strict(language_mode) || allow_harmony_sloppy() || - allow_harmony_destructuring_bind()) { - CheckConflictingVarDeclarations(scope, CHECK_OK); - } + CheckConflictingVarDeclarations(scope, CHECK_OK); if (body) { // If body can be inspected, rewrite queued destructuring assignments @@ -4677,15 +4540,12 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( if (IsGeneratorFunction(kind)) { // We produce: // - // try { InitialYield; ...body...; FinalYield } + // try { InitialYield; ...body...; return {value: undefined, done: true} } // 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. + // - Any return statement inside the body will have its argument wrapped + // in a "done" iterator result object. // - If the generator terminates for whatever reason, we must close it. // Hence the finally clause. @@ -4703,8 +4563,8 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( 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); + Yield* yield = + factory()->NewYield(get_proxy, assignment, RelocInfo::kNoPosition); try_block->statements()->Add( factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition), zone()); @@ -4712,15 +4572,9 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( ParseStatementList(try_block->statements(), Token::RBRACE, CHECK_OK); - 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); - try_block->statements()->Add( - factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition), - zone()); + Statement* final_return = factory()->NewReturnStatement( + BuildIteratorResult(nullptr, true), RelocInfo::kNoPosition); + try_block->statements()->Add(final_return, zone()); Block* finally_block = factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition); @@ -4801,7 +4655,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( 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(); + MarkTailPosition(expressions_in_tail_position[i]); } return result; } @@ -4825,14 +4679,13 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( #define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name()); SET_ALLOW(natives); SET_ALLOW(harmony_sloppy); + SET_ALLOW(harmony_sloppy_function); SET_ALLOW(harmony_sloppy_let); - SET_ALLOW(harmony_default_parameters); - SET_ALLOW(harmony_destructuring_bind); - SET_ALLOW(harmony_destructuring_assignment); - SET_ALLOW(strong_mode); SET_ALLOW(harmony_do_expressions); SET_ALLOW(harmony_function_name); SET_ALLOW(harmony_function_sent); + SET_ALLOW(harmony_exponentiation_operator); + SET_ALLOW(harmony_restrictive_declarations); #undef SET_ALLOW } PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( @@ -4844,8 +4697,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( return result; } - -ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, +ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier, + const AstRawString* name, Scanner::Location class_name_location, bool name_is_strict_reserved, int pos, bool* ok) { @@ -4861,11 +4714,6 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, *ok = false; return NULL; } - if (is_strong(language_mode()) && IsUndefined(name)) { - ReportMessageAt(class_name_location, MessageTemplate::kStrongUndefined); - *ok = false; - return NULL; - } Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); BlockState block_state(&scope_, block_scope); @@ -4883,9 +4731,13 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, Expression* extends = NULL; if (Check(Token::EXTENDS)) { block_scope->set_start_position(scanner()->location().end_pos); - ExpressionClassifier classifier(this); - extends = ParseLeftHandSideExpression(&classifier, CHECK_OK); - RewriteNonPattern(&classifier, CHECK_OK); + ExpressionClassifier extends_classifier(this); + extends = ParseLeftHandSideExpression(&extends_classifier, CHECK_OK); + RewriteNonPattern(&extends_classifier, CHECK_OK); + if (classifier != nullptr) { + classifier->Accumulate(&extends_classifier, + ExpressionClassifier::ExpressionProductions); + } } else { block_scope->set_start_position(scanner()->location().end_pos); } @@ -4906,12 +4758,16 @@ 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(this); + ExpressionClassifier property_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, &property_name, CHECK_OK); - RewriteNonPattern(&classifier, CHECK_OK); + &has_seen_constructor, &property_classifier, &property_name, CHECK_OK); + RewriteNonPattern(&property_classifier, CHECK_OK); + if (classifier != nullptr) { + classifier->Accumulate(&property_classifier, + ExpressionClassifier::ExpressionProductions); + } if (has_seen_constructor && constructor == NULL) { constructor = GetPropertyValue(property)->AsFunctionLiteral(); @@ -4938,8 +4794,8 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, end_pos, block_scope->language_mode()); } - // Note that we do not finalize this block scope because strong - // mode uses it as a sentinel value indicating an anonymous class. + // Note that we do not finalize this block scope because it is + // used as a sentinel value indicating an anonymous class. block_scope->set_end_position(end_pos); if (name != NULL) { @@ -4997,7 +4853,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { // Check that the expected number of arguments are being passed. if (function->nargs != -1 && function->nargs != args->length()) { - ReportMessage(MessageTemplate::kIllegalAccess); + ReportMessage(MessageTemplate::kRuntimeWrongNumArgs); *ok = false; return NULL; } @@ -5331,12 +5187,11 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(4, zone()); args->Add(factory()->NewArrayLiteral( const_cast<ZoneList<Expression*>*>(cooked_strings), - cooked_idx, is_strong(language_mode()), pos), + cooked_idx, pos), zone()); args->Add( factory()->NewArrayLiteral( - const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, - is_strong(language_mode()), pos), + const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, pos), zone()); // Ensure hash is suitable as a Smi value @@ -5425,7 +5280,6 @@ ZoneList<v8::internal::Expression*>* Parser::PrepareSpreadArguments( } int literal_index = function_state_->NextMaterializedLiteralIndex(); args->Add(factory()->NewArrayLiteral(unspread, literal_index, - is_strong(language_mode()), RelocInfo::kNoPosition), zone()); @@ -5511,8 +5365,6 @@ void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) { v8::Isolate::UseCounterFeature feature; if (is_sloppy(mode)) feature = v8::Isolate::kSloppyMode; - else if (is_strong(mode)) - feature = v8::Isolate::kStrongMode; else if (is_strict(mode)) feature = v8::Isolate::kStrictMode; else @@ -5523,8 +5375,8 @@ void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) { void Parser::RaiseLanguageMode(LanguageMode mode) { - SetLanguageMode(scope_, - static_cast<LanguageMode>(scope_->language_mode() | mode)); + LanguageMode old = scope_->language_mode(); + SetLanguageMode(scope_, old > mode ? old : mode); } @@ -5532,6 +5384,16 @@ void ParserTraits::RewriteDestructuringAssignments() { parser_->RewriteDestructuringAssignments(); } +Expression* ParserTraits::RewriteExponentiation(Expression* left, + Expression* right, int pos) { + return parser_->RewriteExponentiation(left, right, pos); +} + +Expression* ParserTraits::RewriteAssignExponentiation(Expression* left, + Expression* right, + int pos) { + return parser_->RewriteAssignExponentiation(left, right, pos); +} void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier, bool* ok) { @@ -5605,7 +5467,6 @@ void Parser::RewriteNonPattern(ExpressionClassifier* classifier, bool* ok) { void Parser::RewriteDestructuringAssignments() { - if (!allow_harmony_destructuring_assignment()) return; const auto& assignments = function_state_->destructuring_assignments_to_rewrite(); for (int i = assignments.length() - 1; i >= 0; --i) { @@ -5622,6 +5483,60 @@ void Parser::RewriteDestructuringAssignments() { } } +Expression* Parser::RewriteExponentiation(Expression* left, Expression* right, + int pos) { + ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); + args->Add(left, zone()); + args->Add(right, zone()); + return factory()->NewCallRuntime(Context::MATH_POW_METHOD_INDEX, args, pos); +} + +Expression* Parser::RewriteAssignExponentiation(Expression* left, + Expression* right, int pos) { + ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); + if (left->IsVariableProxy()) { + VariableProxy* lhs = left->AsVariableProxy(); + + Expression* result; + DCHECK_NOT_NULL(lhs->raw_name()); + result = + this->ExpressionFromIdentifier(lhs->raw_name(), lhs->position(), + lhs->end_position(), scope_, factory()); + args->Add(left, zone()); + args->Add(right, zone()); + Expression* call = + factory()->NewCallRuntime(Context::MATH_POW_METHOD_INDEX, args, pos); + return factory()->NewAssignment(Token::ASSIGN, result, call, pos); + } else if (left->IsProperty()) { + Property* prop = left->AsProperty(); + auto temp_obj = scope_->NewTemporary(ast_value_factory()->empty_string()); + auto temp_key = scope_->NewTemporary(ast_value_factory()->empty_string()); + Expression* assign_obj = factory()->NewAssignment( + Token::ASSIGN, factory()->NewVariableProxy(temp_obj), prop->obj(), + RelocInfo::kNoPosition); + Expression* assign_key = factory()->NewAssignment( + Token::ASSIGN, factory()->NewVariableProxy(temp_key), prop->key(), + RelocInfo::kNoPosition); + args->Add(factory()->NewProperty(factory()->NewVariableProxy(temp_obj), + factory()->NewVariableProxy(temp_key), + left->position()), + zone()); + args->Add(right, zone()); + Expression* call = + factory()->NewCallRuntime(Context::MATH_POW_METHOD_INDEX, args, pos); + Expression* target = factory()->NewProperty( + factory()->NewVariableProxy(temp_obj), + factory()->NewVariableProxy(temp_key), RelocInfo::kNoPosition); + Expression* assign = + factory()->NewAssignment(Token::ASSIGN, target, call, pos); + return factory()->NewBinaryOperation( + Token::COMMA, assign_obj, + factory()->NewBinaryOperation(Token::COMMA, assign_key, assign, pos), + pos); + } + UNREACHABLE(); + return nullptr; +} Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { // Array literals containing spreads are rewritten using do expressions, e.g. @@ -5673,45 +5588,6 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { 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; { @@ -5728,11 +5604,10 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { // 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()); + InitializeForOfStatement(loop->AsForOfStatement(), + factory()->NewVariableProxy(each), subject, + append_body, spread->expression_position()); + do_block->statements()->Add(loop, zone()); } } // Now, rewind the original array literal to truncate everything from the @@ -6055,9 +5930,8 @@ Expression* ParserTraits::RewriteYieldStar( 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); + BuildIteratorClose(then->statements(), var_iterator, Nothing<Variable*>(), + var_tmp); then->statements()->Add(throw_call, zone); check_throw = factory->NewIfStatement( condition, then, factory->NewEmptyStatement(nopos), nopos); @@ -6128,13 +6002,11 @@ Expression* ParserTraits::RewriteYieldStar( set_mode_return = factory->NewExpressionStatement(assignment, nopos); } - - // RawYield(output); + // Yield(output); Statement* yield_output; { Expression* output_proxy = factory->NewVariableProxy(var_output); - Yield* yield = factory->NewYield( - generator, output_proxy, Yield::kInitial, nopos); + Yield* yield = factory->NewYield(generator, output_proxy, nopos); yield_output = factory->NewExpressionStatement(yield, nopos); } @@ -6232,8 +6104,7 @@ Expression* ParserTraits::RewriteYieldStar( 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); + BuildIteratorClose(case_return, var_iterator, Just(var_input), var_output); case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone); auto case_throw = new (zone) ZoneList<Statement*>(5, zone); @@ -6311,7 +6182,8 @@ Expression* ParserTraits::RewriteYieldStar( // if (!IS_CALLABLE(C)) { // throw MakeTypeError(kCalledNonCallableInstanceOf); // } -// handler_result = %ordinary_has_instance(C, O); +// handler_result = %_GetOrdinaryHasInstance() +// handler_result = %_Call(handler_result, C, O); // } else { // handler_result = !!(%_Call(handler_result, C, O)); // } @@ -6356,8 +6228,8 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos); Expression* call = NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck, - avfactory->empty_string(), nopos); - Statement* throw_call = factory->NewExpressionStatement(call, nopos); + avfactory->empty_string(), pos); + Statement* throw_call = factory->NewExpressionStatement(call, pos); validate_C = factory->NewIfStatement(is_receiver_call, @@ -6384,7 +6256,8 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, // if (!IS_CALLABLE(C)) { // throw MakeTypeError(kCalledNonCallableInstanceOf); // } - // result = %ordinary_has_instance(C, O); + // handler_result = %_GetOrdinaryHasInstance() + // handler_result = %_Call(handler_result, C, O); // } else { // handler_result = !!%_Call(handler_result, C, O); // } @@ -6394,17 +6267,29 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result), factory->NewUndefinedLiteral(nopos), nopos); - Block* then_side = factory->NewBlock(nullptr, 2, false, nopos); + Block* then_side = factory->NewBlock(nullptr, 3, 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); + avfactory->empty_string(), pos); + Statement* validate_C = CheckCallable(var_C, throw_expr, pos); + + ZoneList<Expression*>* empty_args = + new (zone) ZoneList<Expression*>(0, zone); + Expression* ordinary_has_instance = factory->NewCallRuntime( + Runtime::kInlineGetOrdinaryHasInstance, empty_args, pos); + Expression* handler_proxy = factory->NewVariableProxy(var_handler_result); + Expression* assignment_handler = factory->NewAssignment( + Token::ASSIGN, handler_proxy, ordinary_has_instance, nopos); + Statement* assignment_get_handler = + factory->NewExpressionStatement(assignment_handler, nopos); + + ZoneList<Expression*>* 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); - CallRuntime* call = factory->NewCallRuntime( - Context::ORDINARY_HAS_INSTANCE_INDEX, args, pos); + Expression* call = + factory->NewCallRuntime(Runtime::kInlineCall, args, pos); Expression* result_proxy = factory->NewVariableProxy(var_handler_result); Expression* assignment = factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos); @@ -6412,6 +6297,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, factory->NewExpressionStatement(assignment, nopos); then_side->statements()->Add(validate_C, zone); + then_side->statements()->Add(assignment_get_handler, zone); then_side->statements()->Add(assignment_return, zone); } @@ -6455,7 +6341,8 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, return instanceof; } -Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) { +Statement* ParserTraits::CheckCallable(Variable* var, Expression* error, + int pos) { auto factory = parser_->factory(); auto avfactory = parser_->ast_value_factory(); const int nopos = RelocInfo::kNoPosition; @@ -6468,7 +6355,7 @@ Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) { Expression* condition = factory->NewCompareOperation( Token::EQ_STRICT, type_of, function_literal, nopos); - Statement* throw_call = factory->NewExpressionStatement(error, nopos); + Statement* throw_call = factory->NewExpressionStatement(error, pos); validate_var = factory->NewIfStatement( condition, factory->NewEmptyStatement(nopos), throw_call, nopos); @@ -6478,17 +6365,27 @@ Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) { void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, Variable* iterator, - Expression* input, + Maybe<Variable*> 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_NULL_OR_UNDEFINED(iteratorReturn) { + // return {value: input, done: true}; + // } + // output = %_Call(iteratorReturn, iterator, input); // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); // + // When the input variable is not given, the return statement becomes + // return {value: undefined, done: true}; + // and %_Call has only two arguments: + // output = %_Call(iteratorReturn, iterator); + // + // The reason for allowing input is that BuildIteratorClose + // can then be reused to handle the return case in yield*. + // const int nopos = RelocInfo::kNoPosition; auto factory = parser_->factory(); @@ -6510,25 +6407,36 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, get_return = factory->NewExpressionStatement(assignment, nopos); } - // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input; + // if (IS_NULL_OR_UNDEFINED(iteratorReturn) { + // return {value: input, done: true}; + // } Statement* check_return; { Expression* condition = factory->NewCompareOperation( Token::EQ, factory->NewVariableProxy(var_return), factory->NewNullLiteral(nopos), nopos); - Statement* return_input = factory->NewReturnStatement(input, nopos); + Expression* value = input.IsJust() + ? static_cast<Expression*>( + factory->NewVariableProxy(input.FromJust())) + : factory->NewUndefinedLiteral(nopos); + + Statement* return_input = + factory->NewReturnStatement(BuildIteratorResult(value, true), nopos); check_return = factory->NewIfStatement( condition, return_input, factory->NewEmptyStatement(nopos), nopos); } - // output = %_Call(iteratorReturn, iterator); + // output = %_Call(iteratorReturn, iterator, input); Statement* call_return; { auto args = new (zone) ZoneList<Expression*>(3, zone); args->Add(factory->NewVariableProxy(var_return), zone); args->Add(factory->NewVariableProxy(iterator), zone); + if (input.IsJust()) { + args->Add(factory->NewVariableProxy(input.FromJust()), zone); + } Expression* call = factory->NewCallRuntime(Runtime::kInlineCall, args, nopos); @@ -6568,9 +6476,124 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, statements->Add(validate_output, zone); } +void ParserTraits::FinalizeIteratorUse(Variable* completion, + Expression* condition, Variable* iter, + Block* iterator_use, Block* target) { + if (!FLAG_harmony_iterator_close) return; + + // + // This function adds two statements to [target], corresponding to the + // following code: + // + // completion = kNormalCompletion; + // try { + // try { + // iterator_use + // } catch(e) { + // if (completion === kAbruptCompletion) completion = kThrowCompletion; + // %ReThrow(e); + // } + // } finally { + // if (condition) { + // #BuildIteratorCloseForCompletion(iter, completion) + // } + // } + // + + const int nopos = RelocInfo::kNoPosition; + auto factory = parser_->factory(); + auto avfactory = parser_->ast_value_factory(); + auto scope = parser_->scope_; + auto zone = parser_->zone(); + + // completion = kNormalCompletion; + Statement* initialize_completion; + { + Expression* proxy = factory->NewVariableProxy(completion); + Expression* assignment = factory->NewAssignment( + Token::ASSIGN, proxy, + factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos); + initialize_completion = factory->NewExpressionStatement(assignment, nopos); + } + + // if (completion === kAbruptCompletion) completion = kThrowCompletion; + Statement* set_completion_throw; + { + Expression* condition = factory->NewCompareOperation( + Token::EQ_STRICT, factory->NewVariableProxy(completion), + factory->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos); + + Expression* proxy = factory->NewVariableProxy(completion); + Expression* assignment = factory->NewAssignment( + Token::ASSIGN, proxy, + factory->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos); + Statement* statement = factory->NewExpressionStatement(assignment, nopos); + set_completion_throw = factory->NewIfStatement( + condition, statement, factory->NewEmptyStatement(nopos), nopos); + } + + // if (condition) { + // #BuildIteratorCloseForCompletion(iter, completion) + // } + Block* maybe_close; + { + Block* block = factory->NewBlock(nullptr, 2, true, nopos); + parser_->BuildIteratorCloseForCompletion(block->statements(), iter, + completion); + DCHECK(block->statements()->length() == 2); -// Runtime encoding of different completion modes. -enum ForOfLoopBodyCompletion { BODY_COMPLETED, BODY_ABORTED, BODY_THREW }; + maybe_close = factory->NewBlock(nullptr, 1, true, nopos); + maybe_close->statements()->Add( + factory->NewIfStatement(condition, block, + factory->NewEmptyStatement(nopos), nopos), + zone); + } + + // try { #try_block } + // catch(e) { + // #set_completion_throw; + // %ReThrow(e); + // } + Statement* try_catch; + { + Scope* catch_scope = parser_->NewScope(scope, CATCH_SCOPE); + Variable* catch_variable = + catch_scope->DeclareLocal(avfactory->dot_catch_string(), VAR, + kCreatedInitialized, Variable::NORMAL); + + Statement* rethrow; + // We use %ReThrow rather than the ordinary throw because we want to + // preserve the original exception message. This is also why we create a + // TryCatchStatementForReThrow below (which does not clear the pending + // message), rather than a TryCatchStatement. + { + auto args = new (zone) ZoneList<Expression*>(1, zone); + args->Add(factory->NewVariableProxy(catch_variable), zone); + rethrow = factory->NewExpressionStatement( + factory->NewCallRuntime(Runtime::kReThrow, args, nopos), nopos); + } + + 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->NewTryCatchStatementForReThrow( + iterator_use, 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); + } + + target->statements()->Add(initialize_completion, zone); + target->statements()->Add(try_finally, zone); +} void ParserTraits::BuildIteratorCloseForCompletion( ZoneList<Statement*>* statements, Variable* iterator, @@ -6581,16 +6604,17 @@ void ParserTraits::BuildIteratorCloseForCompletion( // // let iteratorReturn = iterator.return; // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { - // let output; - // if (completion === BODY_THREW) { + // if (completion === kThrowCompletion) { // if (!IS_CALLABLE(iteratorReturn)) { // throw MakeTypeError(kReturnMethodNotCallable); // } - // try { output = %_Call(iteratorReturn, iterator) } catch (_) { } + // try { %_Call(iteratorReturn, iterator) } catch (_) { } // } else { - // output = %_Call(iteratorReturn, iterator); + // let output = %_Call(iteratorReturn, iterator); + // if (!IS_RECEIVER(output)) { + // %ThrowIterResultNotAnObject(output); + // } // } - // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); // } // @@ -6600,11 +6624,9 @@ void ParserTraits::BuildIteratorCloseForCompletion( 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. + Variable* var_return = scope->NewTemporary(avfactory->empty_string()); Statement* get_return; { Expression* iterator_proxy = factory->NewVariableProxy(iterator); @@ -6626,25 +6648,10 @@ void ParserTraits::BuildIteratorCloseForCompletion( Expression* throw_expr = NewThrowTypeError( MessageTemplate::kReturnMethodNotCallable, avfactory->empty_string(), nopos); - check_return_callable = CheckCallable(var_return, throw_expr); + check_return_callable = CheckCallable(var_return, throw_expr, nopos); } - // 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 (_) { } + // try { %_Call(iteratorReturn, iterator) } catch (_) { } Statement* try_call_return; { auto args = new (zone) ZoneList<Expression*>(2, zone); @@ -6653,12 +6660,10 @@ void ParserTraits::BuildIteratorCloseForCompletion( 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); + try_block->statements()->Add(factory->NewExpressionStatement(call, nopos), + zone); Block* catch_block = factory->NewBlock(nullptr, 0, false, nopos); @@ -6671,29 +6676,27 @@ void ParserTraits::BuildIteratorCloseForCompletion( try_block, catch_scope, catch_variable, catch_block, nopos); } - // if (completion === ABRUPT_THROW) { - // #check_return_callable; - // #try_call_return; - // } else { - // #call_return; + // let output = %_Call(iteratorReturn, iterator); + // if (!IS_RECEIVER(output)) { + // %ThrowIteratorResultNotAnObject(output); // } - Statement* call_return_carefully; + Block* validate_return; { - 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); + Variable* var_output = scope->NewTemporary(avfactory->empty_string()); + 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); - call_return_carefully = - factory->NewIfStatement(condition, then_block, call_return, 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); @@ -6711,8 +6714,32 @@ void ParserTraits::BuildIteratorCloseForCompletion( throw_call = factory->NewExpressionStatement(call, nopos); } - validate_output = factory->NewIfStatement( + Statement* check_return = factory->NewIfStatement( is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos); + + validate_return = factory->NewBlock(nullptr, 2, false, nopos); + validate_return->statements()->Add(call_return, zone); + validate_return->statements()->Add(check_return, zone); + } + + // if (completion === kThrowCompletion) { + // #check_return_callable; + // #try_call_return; + // } else { + // #validate_return; + // } + Statement* call_return_carefully; + { + Expression* condition = factory->NewCompareOperation( + Token::EQ_STRICT, factory->NewVariableProxy(completion), + factory->NewSmiLiteral(Parser::kThrowCompletion, 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, validate_return, nopos); } // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { ... } @@ -6722,12 +6749,9 @@ void ParserTraits::BuildIteratorCloseForCompletion( 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); + maybe_call_return = + factory->NewIfStatement(condition, factory->NewEmptyStatement(nopos), + call_return_carefully, nopos); } @@ -6742,25 +6766,35 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { // // This function replaces the loop with the following wrapping: // - // let completion = BODY_COMPLETED; + // let each; + // let completion = kNormalCompletion; // try { - // #loop; - // } catch(e) { - // if (completion === BODY_ABORTED) completion = BODY_THREW; - // throw e; + // try { + // #loop; + // } catch(e) { + // if (completion === kAbruptCompletion) completion = kThrowCompletion; + // %ReThrow(e); + // } // } finally { - // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) { - // #BuildIteratorClose(#iterator, completion) // See above. + // if (!(completion === kNormalCompletion || IS_UNDEFINED(#iterator))) { + // #BuildIteratorCloseForCompletion(#iterator, completion) // } // } // // where the loop's body is wrapped as follows: // // { - // {{completion = BODY_ABORTED;}} // #loop-body - // {{completion = BODY_COMPLETED;}} + // {{completion = kNormalCompletion;}} // } + // + // and the loop's assign_each is wrapped as follows + // + // do { + // {{completion = kAbruptCompletion;}} + // #assign-each + // } + // const int nopos = RelocInfo::kNoPosition; auto factory = parser_->factory(); @@ -6768,143 +6802,96 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { auto scope = parser_->scope_; auto zone = parser_->zone(); - // let completion = BODY_COMPLETED; Variable* var_completion = scope->NewTemporary(avfactory->empty_string()); - Statement* initialize_completion; + + // let each; + Variable* var_each = scope->NewTemporary(avfactory->empty_string()); + Statement* initialize_each; { - Expression* proxy = factory->NewVariableProxy(var_completion); + Expression* proxy = factory->NewVariableProxy(var_each); Expression* assignment = factory->NewAssignment( Token::ASSIGN, proxy, - factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos); - initialize_completion = + factory->NewUndefinedLiteral(nopos), nopos); + initialize_each = factory->NewExpressionStatement(assignment, nopos); } - // if (completion === BODY_ABORTED) completion = BODY_THREW; - Statement* set_completion_throw; + // !(completion === kNormalCompletion || IS_UNDEFINED(#iterator)) + Expression* closing_condition; { - Expression* condition = factory->NewCompareOperation( + Expression* lhs = 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( + factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos); + Expression* rhs = 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; + closing_condition = factory->NewUnaryOperation( + Token::NOT, factory->NewBinaryOperation(Token::OR, lhs, rhs, nopos), + nopos); } - // {{completion = BODY_ABORTED;}} - Statement* set_completion_break; + // {{completion = kNormalCompletion;}} + Statement* set_completion_normal; { Expression* proxy = factory->NewVariableProxy(var_completion); Expression* assignment = factory->NewAssignment( Token::ASSIGN, proxy, - factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos); + factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos); Block* block = factory->NewBlock(nullptr, 1, true, nopos); block->statements()->Add( factory->NewExpressionStatement(assignment, nopos), zone); - set_completion_break = block; + set_completion_normal = block; } - // {{completion = BODY_COMPLETED;}} - Statement* set_completion_normal; + // {{completion = kAbruptCompletion;}} + Statement* set_completion_abrupt; { Expression* proxy = factory->NewVariableProxy(var_completion); Expression* assignment = factory->NewAssignment( - Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_COMPLETED, nopos), - nopos); + Token::ASSIGN, proxy, + factory->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos); Block* block = factory->NewBlock(nullptr, 1, true, nopos); - block->statements()->Add( - factory->NewExpressionStatement(assignment, nopos), zone); - set_completion_normal = block; + block->statements()->Add(factory->NewExpressionStatement(assignment, nopos), + zone); + set_completion_abrupt = block; } - // { #set_completion_break; #loop-body; #set_completion_normal } + // { #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); + { + new_body->statements()->Add(loop->body(), zone); + new_body->statements()->Add(set_completion_normal, zone); + } + + // { #set_completion_abrupt; #assign-each } + Block* new_assign_each = factory->NewBlock(nullptr, 2, false, nopos); + { + new_assign_each->statements()->Add(set_completion_abrupt, zone); + new_assign_each->statements()->Add( + factory->NewExpressionStatement(loop->assign_each(), nopos), zone); + } + + // Now put things together. loop->set_body(new_body); + loop->set_assign_each( + factory->NewDoExpression(new_assign_each, var_each, nopos)); + + Statement* final_loop; + { + Block* target = factory->NewBlock(nullptr, 3, false, nopos); + target->statements()->Add(initialize_each, zone); + + Block* try_block = factory->NewBlock(nullptr, 1, false, nopos); + try_block->statements()->Add(loop, zone); + + FinalizeIteratorUse(var_completion, closing_condition, loop->iterator(), + try_block, target); + final_loop = target; + } + return final_loop; } |