From 7d7629562fa74a819e9d25abbb004e9ee6ccb65b Mon Sep 17 00:00:00 2001 From: "wingo@igalia.com" Date: Wed, 6 Aug 2014 12:05:39 +0000 Subject: [PATCH] Rewind additional parser state when reinterpreting arrow arguments The new ParserCheckpoint mechanism resets some state, notably the bailout ID counter but also some statement counters (only applicable once we get "do" expressions) when we decide to reinterpret a comma expression as arrow function arguments. R=rossberg@chromium.org, marja@chromium.org BUG=v8:3475 LOG=N Review URL: https://codereview.chromium.org/443903003 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22925 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/parser.h | 15 +++++++++++++++ src/preparser.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/parser.h b/src/parser.h index fd24e8d4e9..e3cee84097 100644 --- a/src/parser.h +++ b/src/parser.h @@ -355,6 +355,21 @@ class ParserTraits { typedef Variable GeneratorVariable; typedef v8::internal::Zone Zone; + class Checkpoint BASE_EMBEDDED { + public: + template + explicit Checkpoint(Parser* parser) { + isolate_ = parser->zone()->isolate(); + saved_ast_node_id_ = isolate_->ast_node_id(); + } + + void Restore() { isolate_->set_ast_node_id(saved_ast_node_id_); } + + private: + Isolate* isolate_; + int saved_ast_node_id_; + }; + typedef v8::internal::AstProperties AstProperties; typedef Vector ParameterIdentifierVector; diff --git a/src/preparser.h b/src/preparser.h index 517403d347..b00cbbbd47 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -114,6 +114,8 @@ class ParserBase : public Traits { } protected: + friend class Traits::Type::Checkpoint; + enum AllowEvalOrArgumentsAsIdentifier { kAllowEvalOrArguments, kDontAllowEvalOrArguments @@ -124,6 +126,8 @@ class ParserBase : public Traits { PARSE_EAGERLY }; + class ParserCheckpoint; + // --------------------------------------------------------------------------- // FunctionState and BlockState together implement the parser's scope stack. // The parser's current scope is in scope_. BlockState and FunctionState @@ -219,6 +223,38 @@ class ParserBase : public Traits { typename Traits::Type::Factory factory_; friend class ParserTraits; + friend class ParserCheckpoint; + }; + + // Annoyingly, arrow functions first parse as comma expressions, then when we + // see the => we have to go back and reinterpret the arguments as being formal + // parameters. To do so we need to reset some of the parser state back to + // what it was before the arguments were first seen. + class ParserCheckpoint : public Traits::Type::Checkpoint { + public: + template + explicit ParserCheckpoint(Parser* parser) + : Traits::Type::Checkpoint(parser) { + function_state_ = parser->function_state_; + next_materialized_literal_index_ = + function_state_->next_materialized_literal_index_; + next_handler_index_ = function_state_->next_handler_index_; + expected_property_count_ = function_state_->expected_property_count_; + } + + void Restore() { + Traits::Type::Checkpoint::Restore(); + function_state_->next_materialized_literal_index_ = + next_materialized_literal_index_; + function_state_->next_handler_index_ = next_handler_index_; + function_state_->expected_property_count_ = expected_property_count_; + } + + private: + FunctionState* function_state_; + int next_materialized_literal_index_; + int next_handler_index_; + int expected_property_count_; }; class ParsingModeScope BASE_EMBEDDED { @@ -1034,6 +1070,13 @@ class PreParserTraits { typedef PreParserScope Scope; typedef PreParserScope ScopePtr; + class Checkpoint BASE_EMBEDDED { + public: + template + explicit Checkpoint(Parser* parser) {} + void Restore() {} + }; + // PreParser doesn't need to store generator variables. typedef void GeneratorVariable; // No interaction with Zones. @@ -2006,10 +2049,12 @@ ParserBase::ParseAssignmentExpression(bool accept_IN, bool* ok) { } if (fni_ != NULL) fni_->Enter(); + ParserCheckpoint checkpoint(this); ExpressionT expression = this->ParseConditionalExpression(accept_IN, CHECK_OK); if (allow_arrow_functions() && peek() == Token::ARROW) { + checkpoint.Restore(); expression = this->ParseArrowFunctionLiteral(lhs_location.beg_pos, expression, CHECK_OK); return expression;