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

Side by Side Diff: src/parsing/parser.cc

Issue 1928203002: [es8] More spec compliant syntactic tail calls implementation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/parsing/parser.h" 5 #include "src/parsing/parser.h"
6 6
7 #include "src/api.h" 7 #include "src/api.h"
8 #include "src/ast/ast.h" 8 #include "src/ast/ast.h"
9 #include "src/ast/ast-expression-rewriter.h" 9 #include "src/ast/ast-expression-rewriter.h"
10 #include "src/ast/ast-expression-visitor.h" 10 #include "src/ast/ast-expression-visitor.h"
(...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 const AstRawString* name, Scanner::Location class_name_location, 758 const AstRawString* name, Scanner::Location class_name_location,
759 bool name_is_strict_reserved, int pos, bool* ok) { 759 bool name_is_strict_reserved, int pos, bool* ok) {
760 return parser_->ParseClassLiteral(name, class_name_location, 760 return parser_->ParseClassLiteral(name, class_name_location,
761 name_is_strict_reserved, pos, ok); 761 name_is_strict_reserved, pos, ok);
762 } 762 }
763 763
764 void ParserTraits::MarkTailPosition(Expression* expression) { 764 void ParserTraits::MarkTailPosition(Expression* expression) {
765 expression->MarkTail(); 765 expression->MarkTail();
766 } 766 }
767 767
768 void ParserTraits::MarkCollectedTailCallExpressions() {
769 parser_->MarkCollectedTailCallExpressions();
770 }
771
768 Parser::Parser(ParseInfo* info) 772 Parser::Parser(ParseInfo* info)
769 : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(), 773 : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(),
770 info->extension(), info->ast_value_factory(), 774 info->extension(), info->ast_value_factory(),
771 NULL, this), 775 NULL, this),
772 scanner_(info->unicode_cache()), 776 scanner_(info->unicode_cache()),
773 reusable_preparser_(NULL), 777 reusable_preparser_(NULL),
774 original_scope_(NULL), 778 original_scope_(NULL),
775 target_stack_(NULL), 779 target_stack_(NULL),
776 compile_options_(info->compile_options()), 780 compile_options_(info->compile_options()),
777 cached_parse_data_(NULL), 781 cached_parse_data_(NULL),
(...skipping 1801 matching lines...) Expand 10 before | Expand all | Expand 10 after
2579 // 'return' Expression? ';' 2583 // 'return' Expression? ';'
2580 2584
2581 // Consume the return token. It is necessary to do that before 2585 // Consume the return token. It is necessary to do that before
2582 // reporting any errors on it, because of the way errors are 2586 // reporting any errors on it, because of the way errors are
2583 // reported (underlining). 2587 // reported (underlining).
2584 Expect(Token::RETURN, CHECK_OK); 2588 Expect(Token::RETURN, CHECK_OK);
2585 Scanner::Location loc = scanner()->location(); 2589 Scanner::Location loc = scanner()->location();
2586 function_state_->set_return_location(loc); 2590 function_state_->set_return_location(loc);
2587 2591
2588 Token::Value tok = peek(); 2592 Token::Value tok = peek();
2589 int tail_call_position = -1;
2590 if (FLAG_harmony_explicit_tailcalls && tok == Token::CONTINUE) {
2591 Consume(Token::CONTINUE);
2592 tail_call_position = position();
2593 tok = peek();
2594 }
2595
2596 Statement* result; 2593 Statement* result;
2597 Expression* return_value; 2594 Expression* return_value;
2598 if (scanner()->HasAnyLineTerminatorBeforeNext() || 2595 if (scanner()->HasAnyLineTerminatorBeforeNext() ||
2599 tok == Token::SEMICOLON || 2596 tok == Token::SEMICOLON ||
2600 tok == Token::RBRACE || 2597 tok == Token::RBRACE ||
2601 tok == Token::EOS) { 2598 tok == Token::EOS) {
2602 if (IsSubclassConstructor(function_state_->kind())) { 2599 if (IsSubclassConstructor(function_state_->kind())) {
2603 return_value = ThisExpression(scope_, factory(), loc.beg_pos); 2600 return_value = ThisExpression(scope_, factory(), loc.beg_pos);
2604 } else { 2601 } else {
2605 return_value = GetLiteralUndefined(position()); 2602 return_value = GetLiteralUndefined(position());
2606 } 2603 }
2607 } else { 2604 } else {
2608 int pos = peek_position(); 2605 int pos = peek_position();
2609 return_value = ParseExpression(true, CHECK_OK);
2610 2606
2611 if (IsSubclassConstructor(function_state_->kind())) { 2607 if (IsSubclassConstructor(function_state_->kind())) {
2608 // Because of the return code rewriting that happens in case of a subclass
2609 // constructor we don't want to accept tail calls, therefore we don't set
2610 // ReturnExprScope to kInsideValidReturnStatement here.
2611 return_value = ParseExpression(true, CHECK_OK);
2612
2612 // For subclass constructors we need to return this in case of undefined 2613 // For subclass constructors we need to return this in case of undefined
2613 // return a Smi (transformed into an exception in the ConstructStub) 2614 // return a Smi (transformed into an exception in the ConstructStub)
2614 // for a non object. 2615 // for a non object.
2615 // 2616 //
2616 // return expr; 2617 // return expr;
2617 // 2618 //
2618 // Is rewritten as: 2619 // Is rewritten as:
2619 // 2620 //
2620 // return (temp = expr) === undefined ? this : 2621 // return (temp = expr) === undefined ? this :
2621 // %_IsJSReceiver(temp) ? temp : 1; 2622 // %_IsJSReceiver(temp) ? temp : 1;
(...skipping 18 matching lines...) Expand all
2640 2641
2641 // temp === undefined 2642 // temp === undefined
2642 Expression* is_undefined = factory()->NewCompareOperation( 2643 Expression* is_undefined = factory()->NewCompareOperation(
2643 Token::EQ_STRICT, assign, 2644 Token::EQ_STRICT, assign,
2644 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), pos); 2645 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), pos);
2645 2646
2646 // is_undefined ? this : is_object_conditional 2647 // is_undefined ? this : is_object_conditional
2647 return_value = factory()->NewConditional( 2648 return_value = factory()->NewConditional(
2648 is_undefined, ThisExpression(scope_, factory(), pos), 2649 is_undefined, ThisExpression(scope_, factory(), pos),
2649 is_object_conditional, pos); 2650 is_object_conditional, pos);
2650 } 2651 } else {
2652 ReturnExprScope maybe_allow_tail_calls(
2653 function_state_, ReturnExprContext::kInsideValidReturnStatement);
2654 return_value = ParseExpression(true, CHECK_OK);
2651 2655
2652 // TODO(ishell): update chapter number. 2656 if (allow_tailcalls() && !is_sloppy(language_mode())) {
2653 // ES8 XX.YY.ZZ 2657 // ES6 14.6.1 Static Semantics: IsInTailPosition
2654 if (tail_call_position >= 0) { 2658 Scanner::Location loc(pos, pos + 1);
2655 ReturnExprContext return_expr_context = 2659 function_state_->AddExpressionInTailPosition(return_value, loc);
2656 function_state_->return_expr_context();
2657 if (return_expr_context != ReturnExprContext::kNormal) {
2658 ReportIllegalTailCallAt(tail_call_position, return_expr_context);
2659 *ok = false;
2660 return NULL;
2661 } 2660 }
2662 function_state_->AddExpressionInTailPosition(return_value,
2663 tail_call_position);
2664
2665 } else if (allow_tailcalls() && !is_sloppy(language_mode())) {
2666 // ES6 14.6.1 Static Semantics: IsInTailPosition
2667 function_state_->AddExpressionInTailPosition(return_value, pos);
2668 } 2661 }
2669 } 2662 }
2670 ExpectSemicolon(CHECK_OK); 2663 ExpectSemicolon(CHECK_OK);
2671 2664
2672 if (is_generator()) { 2665 if (is_generator()) {
2673 return_value = BuildIteratorResult(return_value, true); 2666 return_value = BuildIteratorResult(return_value, true);
2674 } 2667 }
2675 2668
2676 result = factory()->NewReturnStatement(return_value, loc.beg_pos); 2669 result = factory()->NewReturnStatement(return_value, loc.beg_pos);
2677 2670
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
2870 Token::Value tok = peek(); 2863 Token::Value tok = peek();
2871 if (tok != Token::CATCH && tok != Token::FINALLY) { 2864 if (tok != Token::CATCH && tok != Token::FINALLY) {
2872 ReportMessage(MessageTemplate::kNoCatchOrFinally); 2865 ReportMessage(MessageTemplate::kNoCatchOrFinally);
2873 *ok = false; 2866 *ok = false;
2874 return NULL; 2867 return NULL;
2875 } 2868 }
2876 2869
2877 Scope* catch_scope = NULL; 2870 Scope* catch_scope = NULL;
2878 Variable* catch_variable = NULL; 2871 Variable* catch_variable = NULL;
2879 Block* catch_block = NULL; 2872 Block* catch_block = NULL;
2880 List<TailCallExpression> expressions_in_tail_position_in_catch_block; 2873 TailCallExpressionList tail_call_expressions_in_catch_block(zone());
2881 if (tok == Token::CATCH) { 2874 if (tok == Token::CATCH) {
2882 Consume(Token::CATCH); 2875 Consume(Token::CATCH);
2883 2876
2884 Expect(Token::LPAREN, CHECK_OK); 2877 Expect(Token::LPAREN, CHECK_OK);
2885 catch_scope = NewScope(scope_, CATCH_SCOPE); 2878 catch_scope = NewScope(scope_, CATCH_SCOPE);
2886 catch_scope->set_start_position(scanner()->location().beg_pos); 2879 catch_scope->set_start_position(scanner()->location().beg_pos);
2887 2880
2888 ExpressionClassifier pattern_classifier(this); 2881 ExpressionClassifier pattern_classifier(this);
2889 Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK); 2882 Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
2890 ValidateBindingPattern(&pattern_classifier, CHECK_OK); 2883 ValidateBindingPattern(&pattern_classifier, CHECK_OK);
2891 2884
2892 const AstRawString* name = ast_value_factory()->dot_catch_string(); 2885 const AstRawString* name = ast_value_factory()->dot_catch_string();
2893 bool is_simple = pattern->IsVariableProxy(); 2886 bool is_simple = pattern->IsVariableProxy();
2894 if (is_simple) { 2887 if (is_simple) {
2895 auto proxy = pattern->AsVariableProxy(); 2888 auto proxy = pattern->AsVariableProxy();
2896 scope_->RemoveUnresolved(proxy); 2889 scope_->RemoveUnresolved(proxy);
2897 name = proxy->raw_name(); 2890 name = proxy->raw_name();
2898 } 2891 }
2899 2892
2900 catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized, 2893 catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
2901 Variable::NORMAL); 2894 Variable::NORMAL);
2902 2895
2903 Expect(Token::RPAREN, CHECK_OK); 2896 Expect(Token::RPAREN, CHECK_OK);
2904 2897
2905 { 2898 {
2906 CollectExpressionsInTailPositionToListScope 2899 CollectExpressionsInTailPositionToListScope
2907 collect_expressions_in_tail_position_scope( 2900 collect_tail_call_expressions_scope(
2908 function_state_, &expressions_in_tail_position_in_catch_block); 2901 function_state_, &tail_call_expressions_in_catch_block);
2909 BlockState block_state(&scope_, catch_scope); 2902 BlockState block_state(&scope_, catch_scope);
2910 2903
2911 // TODO(adamk): Make a version of ParseBlock that takes a scope and 2904 // TODO(adamk): Make a version of ParseBlock that takes a scope and
2912 // a block. 2905 // a block.
2913 catch_block = 2906 catch_block =
2914 factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition); 2907 factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
2915 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); 2908 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
2916 2909
2917 block_scope->set_start_position(scanner()->location().beg_pos); 2910 block_scope->set_start_position(scanner()->location().beg_pos);
2918 { 2911 {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
2978 catch_block, RelocInfo::kNoPosition); 2971 catch_block, RelocInfo::kNoPosition);
2979 try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); 2972 try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
2980 try_block->statements()->Add(statement, zone()); 2973 try_block->statements()->Add(statement, zone());
2981 catch_block = NULL; // Clear to indicate it's been handled. 2974 catch_block = NULL; // Clear to indicate it's been handled.
2982 } 2975 }
2983 2976
2984 TryStatement* result = NULL; 2977 TryStatement* result = NULL;
2985 if (catch_block != NULL) { 2978 if (catch_block != NULL) {
2986 // For a try-catch construct append return expressions from the catch block 2979 // For a try-catch construct append return expressions from the catch block
2987 // to the list of return expressions. 2980 // to the list of return expressions.
2988 function_state_->expressions_in_tail_position().AddAll( 2981 function_state_->tail_call_expressions().Append(
2989 expressions_in_tail_position_in_catch_block); 2982 tail_call_expressions_in_catch_block);
2990 2983
2991 DCHECK(finally_block == NULL); 2984 DCHECK(finally_block == NULL);
2992 DCHECK(catch_scope != NULL && catch_variable != NULL); 2985 DCHECK(catch_scope != NULL && catch_variable != NULL);
2993 result = factory()->NewTryCatchStatement(try_block, catch_scope, 2986 result = factory()->NewTryCatchStatement(try_block, catch_scope,
2994 catch_variable, catch_block, pos); 2987 catch_variable, catch_block, pos);
2995 } else { 2988 } else {
2996 if (FLAG_harmony_explicit_tailcalls && 2989 if (FLAG_harmony_explicit_tailcalls &&
2997 expressions_in_tail_position_in_catch_block.length() > 0) { 2990 !tail_call_expressions_in_catch_block.is_empty()) {
2998 // TODO(ishell): update chapter number. 2991 // TODO(ishell): update chapter number.
2999 // ES8 XX.YY.ZZ 2992 // ES8 XX.YY.ZZ
3000 int pos = expressions_in_tail_position_in_catch_block[0].pos; 2993 ReportMessageAt(tail_call_expressions_in_catch_block.location(),
3001 ReportMessageAt(Scanner::Location(pos, pos + 1), 2994 MessageTemplate::kUnexpectedTailCallInCatchBlock);
3002 MessageTemplate::kTailCallInCatchBlock);
3003 *ok = false; 2995 *ok = false;
3004 return NULL; 2996 return NULL;
3005 } 2997 }
3006 DCHECK(finally_block != NULL); 2998 DCHECK(finally_block != NULL);
3007 result = factory()->NewTryFinallyStatement(try_block, finally_block, pos); 2999 result = factory()->NewTryFinallyStatement(try_block, finally_block, pos);
3008 } 3000 }
3009 3001
3010 return result; 3002 return result;
3011 } 3003 }
3012 3004
(...skipping 1563 matching lines...) Expand 10 before | Expand all | Expand 10 after
4576 4568
4577 VariableProxy* fproxy = factory()->NewVariableProxy(fvar); 4569 VariableProxy* fproxy = factory()->NewVariableProxy(fvar);
4578 result->Set(kFunctionNameAssignmentIndex, 4570 result->Set(kFunctionNameAssignmentIndex,
4579 factory()->NewExpressionStatement( 4571 factory()->NewExpressionStatement(
4580 factory()->NewAssignment(Token::INIT, fproxy, 4572 factory()->NewAssignment(Token::INIT, fproxy,
4581 factory()->NewThisFunction(pos), 4573 factory()->NewThisFunction(pos),
4582 RelocInfo::kNoPosition), 4574 RelocInfo::kNoPosition),
4583 RelocInfo::kNoPosition)); 4575 RelocInfo::kNoPosition));
4584 } 4576 }
4585 4577
4586 // ES6 14.6.1 Static Semantics: IsInTailPosition 4578 MarkCollectedTailCallExpressions();
4587 // Mark collected return expressions that are in tail call position.
4588 const List<TailCallExpression>& expressions_in_tail_position =
4589 function_state_->expressions_in_tail_position();
4590 for (int i = 0; i < expressions_in_tail_position.length(); ++i) {
4591 MarkTailPosition(expressions_in_tail_position[i].expression);
4592 }
4593 return result; 4579 return result;
4594 } 4580 }
4595 4581
4596 4582
4597 PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( 4583 PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
4598 SingletonLogger* logger, Scanner::BookmarkScope* bookmark) { 4584 SingletonLogger* logger, Scanner::BookmarkScope* bookmark) {
4599 // This function may be called on a background thread too; record only the 4585 // This function may be called on a background thread too; record only the
4600 // main thread preparse times. 4586 // main thread preparse times.
4601 if (pre_parse_timer_ != NULL) { 4587 if (pre_parse_timer_ != NULL) {
4602 pre_parse_timer_->Start(); 4588 pre_parse_timer_->Start();
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
4656 proxy = NewUnresolved(name, CONST); 4642 proxy = NewUnresolved(name, CONST);
4657 Declaration* declaration = 4643 Declaration* declaration =
4658 factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos); 4644 factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
4659 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); 4645 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
4660 } 4646 }
4661 4647
4662 Expression* extends = NULL; 4648 Expression* extends = NULL;
4663 if (Check(Token::EXTENDS)) { 4649 if (Check(Token::EXTENDS)) {
4664 block_scope->set_start_position(scanner()->location().end_pos); 4650 block_scope->set_start_position(scanner()->location().end_pos);
4665 ExpressionClassifier classifier(this); 4651 ExpressionClassifier classifier(this);
4666 extends = ParseLeftHandSideExpression(&classifier, CHECK_OK); 4652 extends =
4653 ParseLeftHandSideExpression(kDontAcceptTCE, &classifier, CHECK_OK);
4667 RewriteNonPattern(&classifier, CHECK_OK); 4654 RewriteNonPattern(&classifier, CHECK_OK);
4668 } else { 4655 } else {
4669 block_scope->set_start_position(scanner()->location().end_pos); 4656 block_scope->set_start_position(scanner()->location().end_pos);
4670 } 4657 }
4671 4658
4672 4659
4673 ClassLiteralChecker checker(this); 4660 ClassLiteralChecker checker(this);
4674 ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone()); 4661 ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone());
4675 FunctionLiteral* constructor = NULL; 4662 FunctionLiteral* constructor = NULL;
4676 bool has_seen_constructor = false; 4663 bool has_seen_constructor = false;
(...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after
5295 ++use_counts_[feature]; 5282 ++use_counts_[feature];
5296 scope->SetLanguageMode(mode); 5283 scope->SetLanguageMode(mode);
5297 } 5284 }
5298 5285
5299 5286
5300 void Parser::RaiseLanguageMode(LanguageMode mode) { 5287 void Parser::RaiseLanguageMode(LanguageMode mode) {
5301 LanguageMode old = scope_->language_mode(); 5288 LanguageMode old = scope_->language_mode();
5302 SetLanguageMode(scope_, old > mode ? old : mode); 5289 SetLanguageMode(scope_, old > mode ? old : mode);
5303 } 5290 }
5304 5291
5292 void Parser::MarkCollectedTailCallExpressions() {
5293 const ZoneList<Expression*>& tail_call_expressions =
5294 function_state_->tail_call_expressions().expressions();
5295 for (int i = 0; i < tail_call_expressions.length(); ++i) {
5296 Expression* expression = tail_call_expressions[i];
5297 // If only FLAG_harmony_explicit_tailcalls is enabled then expression
5298 // must be a Call expression.
5299 DCHECK(FLAG_harmony_tailcalls || !FLAG_harmony_explicit_tailcalls ||
5300 expression->IsCall());
5301 MarkTailPosition(expression);
5302 }
5303 }
5305 5304
5306 void ParserTraits::RewriteDestructuringAssignments() { 5305 void ParserTraits::RewriteDestructuringAssignments() {
5307 parser_->RewriteDestructuringAssignments(); 5306 parser_->RewriteDestructuringAssignments();
5308 } 5307 }
5309 5308
5310 Expression* ParserTraits::RewriteExponentiation(Expression* left, 5309 Expression* ParserTraits::RewriteExponentiation(Expression* left,
5311 Expression* right, int pos) { 5310 Expression* right, int pos) {
5312 return parser_->RewriteExponentiation(left, right, pos); 5311 return parser_->RewriteExponentiation(left, right, pos);
5313 } 5312 }
5314 5313
(...skipping 1493 matching lines...) Expand 10 before | Expand all | Expand 10 after
6808 try_block, target); 6807 try_block, target);
6809 final_loop = target; 6808 final_loop = target;
6810 } 6809 }
6811 6810
6812 return final_loop; 6811 return final_loop;
6813 } 6812 }
6814 6813
6815 6814
6816 } // namespace internal 6815 } // namespace internal
6817 } // namespace v8 6816 } // namespace v8
OLDNEW
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | src/parsing/parser-base.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698