LCOV - code coverage report
Current view: top level - src/parsing - preparser.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 108 116 93.1 %
Date: 2017-04-26 Functions: 8 8 100.0 %

          Line data    Source code
       1             : // Copyright 2011 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <cmath>
       6             : 
       7             : #include "src/allocation.h"
       8             : #include "src/base/logging.h"
       9             : #include "src/conversions-inl.h"
      10             : #include "src/conversions.h"
      11             : #include "src/globals.h"
      12             : #include "src/list.h"
      13             : #include "src/parsing/duplicate-finder.h"
      14             : #include "src/parsing/parser-base.h"
      15             : #include "src/parsing/preparse-data-format.h"
      16             : #include "src/parsing/preparse-data.h"
      17             : #include "src/parsing/preparsed-scope-data.h"
      18             : #include "src/parsing/preparser.h"
      19             : #include "src/unicode.h"
      20             : #include "src/utils.h"
      21             : 
      22             : namespace v8 {
      23             : namespace internal {
      24             : 
      25             : // ----------------------------------------------------------------------------
      26             : // The CHECK_OK macro is a convenient macro to enforce error
      27             : // handling for functions that may fail (by returning !*ok).
      28             : //
      29             : // CAUTION: This macro appends extra statements after a call,
      30             : // thus it must never be used where only a single statement
      31             : // is correct (e.g. an if statement branch w/o braces)!
      32             : 
      33             : #define CHECK_OK_VALUE(x) ok); \
      34             :   if (!*ok) return x;          \
      35             :   ((void)0
      36             : #define DUMMY )  // to make indentation work
      37             : #undef DUMMY
      38             : 
      39             : #define CHECK_OK CHECK_OK_VALUE(Expression::Default())
      40             : #define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
      41             : 
      42             : namespace {
      43             : 
      44    66206535 : PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
      45             :   // These symbols require slightly different treatement:
      46             :   // - regular keywords (enum, await, etc.; treated in 1st switch.)
      47             :   // - 'contextual' keywords (and may contain escaped; treated in 2nd switch.)
      48             :   // - 'contextual' keywords, but may not be escaped (3rd switch).
      49    33144495 :   switch (scanner->current_token()) {
      50             :     case Token::ENUM:
      51             :       return PreParserIdentifier::Enum();
      52             :     case Token::AWAIT:
      53             :       return PreParserIdentifier::Await();
      54             :     case Token::FUTURE_STRICT_RESERVED_WORD:
      55             :       return PreParserIdentifier::FutureStrictReserved();
      56             :     case Token::LET:
      57             :       return PreParserIdentifier::Let();
      58             :     case Token::STATIC:
      59             :       return PreParserIdentifier::Static();
      60             :     case Token::YIELD:
      61             :       return PreParserIdentifier::Yield();
      62             :     case Token::ASYNC:
      63             :       return PreParserIdentifier::Async();
      64             :     default:
      65             :       break;
      66             :   }
      67    33062040 :   switch (scanner->current_contextual_token()) {
      68             :     case Token::PROTOTYPE:
      69             :       return PreParserIdentifier::Prototype();
      70             :     case Token::CONSTRUCTOR:
      71             :       return PreParserIdentifier::Constructor();
      72             :     case Token::NAME:
      73             :       return PreParserIdentifier::Name();
      74             :     default:
      75             :       break;
      76             :   }
      77    32730672 :   if (scanner->literal_contains_escapes())
      78             :     return PreParserIdentifier::Default();
      79    32727074 :   switch (scanner->current_contextual_token()) {
      80             :     case Token::EVAL:
      81             :       return PreParserIdentifier::Eval();
      82             :     case Token::ARGUMENTS:
      83             :       return PreParserIdentifier::Arguments();
      84             :     case Token::UNDEFINED:
      85             :       return PreParserIdentifier::Undefined();
      86             :     default:
      87             :       break;
      88             :   }
      89             :   return PreParserIdentifier::Default();
      90             : }
      91             : 
      92             : }  // unnamed namespace
      93             : 
      94    33144495 : PreParserIdentifier PreParser::GetSymbol() const {
      95    43910640 :   PreParserIdentifier symbol = GetSymbolHelper(scanner());
      96    33144494 :   if (track_unresolved_variables_) {
      97    10766145 :     const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
      98             :     DCHECK_NOT_NULL(result);
      99             :     symbol.string_ = result;
     100             :   }
     101    33144494 :   return symbol;
     102             : }
     103             : 
     104      480923 : PreParser::PreParseResult PreParser::PreParseProgram(bool is_module,
     105             :                                                      int* use_counts) {
     106             :   DCHECK_NULL(scope_);
     107      480923 :   use_counts_ = use_counts;
     108     1724005 :   DeclarationScope* scope = NewScriptScope();
     109             : #ifdef DEBUG
     110             :   scope->set_is_being_lazily_parsed(true);
     111             : #endif
     112             : 
     113             :   // ModuleDeclarationInstantiation for Source Text Module Records creates a
     114             :   // new Module Environment Record whose outer lexical environment record is
     115             :   // the global scope.
     116      480923 :   if (is_module) scope = NewModuleScope(scope);
     117             : 
     118      480923 :   FunctionState top_scope(&function_state_, &scope_, scope);
     119      480923 :   original_scope_ = scope_;
     120      480923 :   bool ok = true;
     121             :   int start_position = scanner()->peek_location().beg_pos;
     122      480923 :   parsing_module_ = is_module;
     123             :   PreParserStatementList body;
     124             :   ParseStatementList(body, Token::EOS, &ok);
     125      480923 :   original_scope_ = nullptr;
     126      480923 :   use_counts_ = nullptr;
     127      480923 :   if (stack_overflow()) return kPreParseStackOverflow;
     128      480917 :   if (!ok) {
     129      215596 :     ReportUnexpectedToken(scanner()->current_token());
     130      265321 :   } else if (is_strict(language_mode())) {
     131       65640 :     CheckStrictOctalLiteral(start_position, scanner()->location().end_pos, &ok);
     132             :   }
     133             :   return kPreParseSuccess;
     134             : }
     135             : 
     136     1434068 : PreParser::PreParseResult PreParser::PreParseFunction(
     137             :     FunctionKind kind, DeclarationScope* function_scope, bool parsing_module,
     138             :     bool is_inner_function, bool may_abort, int* use_counts) {
     139             :   DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
     140     1434068 :   parsing_module_ = parsing_module;
     141     1434068 :   use_counts_ = use_counts;
     142             :   DCHECK(!track_unresolved_variables_);
     143     1434068 :   track_unresolved_variables_ = is_inner_function;
     144             : #ifdef DEBUG
     145             :   function_scope->set_is_being_lazily_parsed(true);
     146             : #endif
     147             : 
     148             :   // In the preparser, we use the function literal ids to count how many
     149             :   // FunctionLiterals were encountered. The PreParser doesn't actually persist
     150             :   // FunctionLiterals, so there IDs don't matter.
     151     3726226 :   ResetFunctionLiteralId();
     152             : 
     153             :   // The caller passes the function_scope which is not yet inserted into the
     154             :   // scope stack. All scopes above the function_scope are ignored by the
     155             :   // PreParser.
     156             :   DCHECK_NULL(function_state_);
     157             :   DCHECK_NULL(scope_);
     158     1434068 :   FunctionState function_state(&function_state_, &scope_, function_scope);
     159             :   // This indirection is needed so that we can use the CHECK_OK macros.
     160     1434068 :   bool ok_holder = true;
     161             :   bool* ok = &ok_holder;
     162             : 
     163             :   PreParserFormalParameters formals(function_scope);
     164             :   DuplicateFinder duplicate_finder;
     165             :   std::unique_ptr<ExpressionClassifier> formals_classifier;
     166             : 
     167             :   // Parse non-arrow function parameters. For arrow functions, the parameters
     168             :   // have already been parsed.
     169     1434068 :   if (!IsArrowFunction(kind)) {
     170     1402868 :     formals_classifier.reset(new ExpressionClassifier(this, &duplicate_finder));
     171             :     // We return kPreParseSuccess in failure cases too - errors are retrieved
     172             :     // separately by Parser::SkipLazyFunctionBody.
     173     1402869 :     ParseFormalParameterList(&formals, CHECK_OK_VALUE(kPreParseSuccess));
     174     1392318 :     Expect(Token::RPAREN, CHECK_OK_VALUE(kPreParseSuccess));
     175             :     int formals_end_position = scanner()->location().end_pos;
     176             : 
     177             :     CheckArityRestrictions(
     178             :         formals.arity, kind, formals.has_rest, function_scope->start_position(),
     179     1666116 :         formals_end_position, CHECK_OK_VALUE(kPreParseSuccess));
     180             :   }
     181             : 
     182     1422385 :   Expect(Token::LBRACE, CHECK_OK_VALUE(kPreParseSuccess));
     183             :   DeclarationScope* inner_scope = function_scope;
     184             :   LazyParsingResult result;
     185             : 
     186     1422338 :   if (!formals.is_simple) {
     187       15606 :     inner_scope = NewVarblockScope();
     188             :     inner_scope->set_start_position(scanner()->location().beg_pos);
     189             :   }
     190             : 
     191             :   {
     192             :     BlockState block_state(&scope_, inner_scope);
     193     1422338 :     result = ParseStatementListAndLogFunction(&formals, may_abort, ok);
     194             :   }
     195             : 
     196     1422338 :   if (!formals.is_simple) {
     197             :     BuildParameterInitializationBlock(formals, ok);
     198             : 
     199       15606 :     if (is_sloppy(inner_scope->language_mode())) {
     200       12449 :       inner_scope->HoistSloppyBlockFunctions(nullptr);
     201             :     }
     202             : 
     203             :     SetLanguageMode(function_scope, inner_scope->language_mode());
     204             :     inner_scope->set_end_position(scanner()->peek_location().end_pos);
     205       15606 :     inner_scope->FinalizeBlockScope();
     206             :   } else {
     207     1406732 :     if (is_sloppy(function_scope->language_mode())) {
     208     1112089 :       function_scope->HoistSloppyBlockFunctions(nullptr);
     209             :     }
     210             :   }
     211             : 
     212     1422338 :   if (!IsArrowFunction(kind) && track_unresolved_variables_) {
     213             :     // Declare arguments after parsing the function since lexical 'arguments'
     214             :     // masks the arguments object. Declare arguments before declaring the
     215             :     // function var since the arguments object masks 'function arguments'.
     216      532607 :     function_scope->DeclareArguments(ast_value_factory());
     217             : 
     218      547408 :     if (FLAG_experimental_preparser_scope_analysis &&
     219       14801 :         preparsed_scope_data_ != nullptr) {
     220             :       // We're not going to skip this function, but it might contain skippable
     221             :       // functions inside it.
     222             :       preparsed_scope_data_->AddFunction(
     223             :           scope()->start_position(),
     224             :           PreParseData::FunctionData(
     225             :               scanner()->peek_location().end_pos, scope()->num_parameters(),
     226             :               GetLastFunctionLiteralId(), scope()->language_mode(),
     227       44403 :               scope()->AsDeclarationScope()->uses_super_property()));
     228             :     }
     229             :   }
     230             : 
     231     1422338 :   use_counts_ = nullptr;
     232     1422338 :   track_unresolved_variables_ = false;
     233             : 
     234     1422338 :   if (result == kLazyParsingAborted) {
     235             :     return kPreParseAbort;
     236     1422286 :   } else if (stack_overflow()) {
     237             :     return kPreParseStackOverflow;
     238     1422234 :   } else if (!*ok) {
     239             :     DCHECK(pending_error_handler_->has_pending_error());
     240             :   } else {
     241             :     DCHECK_EQ(Token::RBRACE, scanner()->peek());
     242             : 
     243     1386477 :     if (!IsArrowFunction(kind)) {
     244             :       // Validate parameter names. We can do this only after parsing the
     245             :       // function, since the function can declare itself strict.
     246             :       const bool allow_duplicate_parameters =
     247     2428345 :           is_sloppy(function_scope->language_mode()) && formals.is_simple &&
     248             :           !IsConciseMethod(kind);
     249             :       ValidateFormalParameters(function_scope->language_mode(),
     250             :                                allow_duplicate_parameters,
     251     2715696 :                                CHECK_OK_VALUE(kPreParseSuccess));
     252             :     }
     253             : 
     254     1384339 :     if (is_strict(function_scope->language_mode())) {
     255             :       int end_pos = scanner()->location().end_pos;
     256      274619 :       CheckStrictOctalLiteral(function_scope->start_position(), end_pos, ok);
     257             :     }
     258             :   }
     259             :   return kPreParseSuccess;
     260             : }
     261             : 
     262             : 
     263             : // Preparsing checks a JavaScript program and emits preparse-data that helps
     264             : // a later parsing to be faster.
     265             : // See preparser-data.h for the data.
     266             : 
     267             : // The PreParser checks that the syntax follows the grammar for JavaScript,
     268             : // and collects some information about the program along the way.
     269             : // The grammar check is only performed in order to understand the program
     270             : // sufficiently to deduce some information about it, that can be used
     271             : // to speed up later parsing. Finding errors is not the goal of pre-parsing,
     272             : // rather it is to speed up properly written and correct programs.
     273             : // That means that contextual checks (like a label being declared where
     274             : // it is used) are generally omitted.
     275             : 
     276      385764 : PreParser::Expression PreParser::ParseFunctionLiteral(
     277             :     Identifier function_name, Scanner::Location function_name_location,
     278             :     FunctionNameValidity function_name_validity, FunctionKind kind,
     279             :     int function_token_pos, FunctionLiteral::FunctionType function_type,
     280             :     LanguageMode language_mode, bool* ok) {
     281             :   // Function ::
     282             :   //   '(' FormalParameterList? ')' '{' FunctionBody '}'
     283             :   const RuntimeCallStats::CounterId counters[2][2] = {
     284             :       {&RuntimeCallStats::PreParseBackgroundNoVariableResolution,
     285             :        &RuntimeCallStats::PreParseNoVariableResolution},
     286             :       {&RuntimeCallStats::PreParseBackgroundWithVariableResolution,
     287      385764 :        &RuntimeCallStats::PreParseWithVariableResolution}};
     288             :   RuntimeCallTimerScope runtime_timer(
     289             :       runtime_call_stats_,
     290      385764 :       counters[track_unresolved_variables_][parsing_on_main_thread_]);
     291             : 
     292             :   bool is_top_level =
     293     1503977 :       scope()->AllowsLazyParsingWithoutUnresolvedVariables(original_scope_);
     294             : 
     295      385764 :   DeclarationScope* function_scope = NewFunctionScope(kind);
     296           0 :   function_scope->SetLanguageMode(language_mode);
     297      385764 :   FunctionState function_state(&function_state_, &scope_, function_scope);
     298             :   DuplicateFinder duplicate_finder;
     299      385764 :   ExpressionClassifier formals_classifier(this, &duplicate_finder);
     300             :   int func_id = GetNextFunctionLiteralId();
     301             : 
     302      385764 :   Expect(Token::LPAREN, CHECK_OK);
     303             :   int start_position = scanner()->location().beg_pos;
     304             :   function_scope->set_start_position(start_position);
     305             :   PreParserFormalParameters formals(function_scope);
     306      382552 :   ParseFormalParameterList(&formals, CHECK_OK);
     307      359428 :   Expect(Token::RPAREN, CHECK_OK);
     308             :   int formals_end_position = scanner()->location().end_pos;
     309             : 
     310             :   CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position,
     311      357830 :                          formals_end_position, CHECK_OK);
     312             : 
     313      356633 :   Expect(Token::LBRACE, CHECK_OK);
     314             : 
     315             :   // Parse function body.
     316             :   PreParserStatementList body;
     317             :   int pos = function_token_pos == kNoSourcePosition ? peek_position()
     318      356297 :                                                     : function_token_pos;
     319             :   ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
     320      356297 :                     CHECK_OK);
     321             : 
     322             :   // Parsing the body may change the language mode in our scope.
     323             :   language_mode = function_scope->language_mode();
     324             : 
     325      293966 :   if (is_sloppy(language_mode)) {
     326      199393 :     function_scope->HoistSloppyBlockFunctions(nullptr);
     327             :   }
     328             : 
     329             :   // Validate name and parameter names. We can do this only after parsing the
     330             :   // function, since the function can declare itself strict.
     331             :   CheckFunctionName(language_mode, function_name, function_name_validity,
     332      293966 :                     function_name_location, CHECK_OK);
     333             :   const bool allow_duplicate_parameters =
     334      479324 :       is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
     335      292062 :   ValidateFormalParameters(language_mode, allow_duplicate_parameters, CHECK_OK);
     336             : 
     337             :   int end_position = scanner()->location().end_pos;
     338      289311 :   if (is_strict(language_mode)) {
     339       91019 :     CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
     340             :   }
     341             : 
     342      289230 :   if (FLAG_use_parse_tasks && is_top_level && preparse_data_) {
     343             :     preparse_data_->AddFunctionData(
     344             :         start_position, PreParseData::FunctionData(
     345             :                             end_position, formals.num_parameters(),
     346             :                             GetLastFunctionLiteralId() - func_id, language_mode,
     347           0 :                             function_scope->uses_super_property()));
     348             :     // TODO(wiktorg) spin-off a parse task
     349           0 :     if (FLAG_trace_parse_tasks) {
     350             :       PrintF("Saved function at %d to %d with:\n", start_position,
     351           0 :              end_position);
     352           0 :       PrintF("\t- %d params\n", formals.num_parameters());
     353           0 :       PrintF("\t- %d function length\n", formals.function_length);
     354           0 :       PrintF("\t- %d inner-funcs\n", GetLastFunctionLiteralId() - func_id);
     355             :     }
     356             :   }
     357             : 
     358      289230 :   if (FLAG_experimental_preparser_scope_analysis &&
     359       10656 :       track_unresolved_variables_ && preparsed_scope_data_ != nullptr) {
     360             :     preparsed_scope_data_->AddSkippableFunction(
     361             :         start_position,
     362             :         PreParseData::FunctionData(
     363             :             end_position, scope()->num_parameters(),
     364             :             GetLastFunctionLiteralId() - func_id, scope()->language_mode(),
     365       31968 :             scope()->AsDeclarationScope()->uses_super_property()));
     366             :   }
     367      289230 :   if (FLAG_trace_preparse) {
     368             :     PrintF("  [%s]: %i-%i\n",
     369             :            track_unresolved_variables_ ? "Preparse resolution"
     370             :                                        : "Preparse no-resolution",
     371           0 :            function_scope->start_position(), function_scope->end_position());
     372             :   }
     373             : 
     374             :   return Expression::Default();
     375             : }
     376             : 
     377     1422338 : PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
     378             :     PreParserFormalParameters* formals, bool may_abort, bool* ok) {
     379             :   PreParserStatementList body;
     380             :   LazyParsingResult result = ParseStatementList(
     381     2808815 :       body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
     382     1386529 :   if (result == kLazyParsingAborted) return result;
     383             : 
     384             :   // Position right after terminal '}'.
     385             :   DCHECK_EQ(Token::RBRACE, scanner()->peek());
     386             :   int body_end = scanner()->peek_location().end_pos;
     387             :   DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
     388             :   log_.LogFunction(body_end, formals->num_parameters(),
     389     1386477 :                    GetLastFunctionLiteralId());
     390     1386477 :   return kLazyParsingComplete;
     391             : }
     392             : 
     393    28362984 : PreParserExpression PreParser::ExpressionFromIdentifier(
     394    28362984 :     PreParserIdentifier name, int start_position, InferName infer) {
     395             :   VariableProxy* proxy = nullptr;
     396    28362984 :   if (track_unresolved_variables_) {
     397    55736367 :     AstNodeFactory factory(ast_value_factory());
     398             :     // Setting the Zone is necessary because zone_ might be the temp Zone, and
     399             :     // AstValueFactory doesn't know about it.
     400             :     factory.set_zone(zone());
     401             :     DCHECK_NOT_NULL(name.string_);
     402             :     proxy = scope()->NewUnresolved(&factory, name.string_, start_position,
     403    18248922 :                                    NORMAL_VARIABLE);
     404             :   }
     405    28362984 :   return PreParserExpression::FromIdentifier(name, proxy, zone());
     406             : }
     407             : 
     408     4405135 : void PreParser::DeclareAndInitializeVariables(
     409             :     PreParserStatement block,
     410             :     const DeclarationDescriptor* declaration_descriptor,
     411             :     const DeclarationParsingResult::Declaration* declaration,
     412             :     ZoneList<const AstRawString*>* names, bool* ok) {
     413     4405135 :   if (declaration->pattern.variables_ != nullptr) {
     414             :     DCHECK(FLAG_lazy_inner_functions);
     415             :     DCHECK(track_unresolved_variables_);
     416     2203134 :     for (auto variable : *(declaration->pattern.variables_)) {
     417      736460 :       declaration_descriptor->scope->RemoveUnresolved(variable);
     418             :       Variable* var = scope()->DeclareVariableName(
     419     1484094 :           variable->raw_name(), declaration_descriptor->mode);
     420      736460 :       if (FLAG_experimental_preparser_scope_analysis) {
     421       11783 :         MarkLoopVariableAsAssigned(declaration_descriptor->scope, var);
     422             :         // This is only necessary if there is an initializer, but we don't have
     423             :         // that information here.  Consequently, the preparser sometimes says
     424             :         // maybe-assigned where the parser (correctly) says never-assigned.
     425             :       }
     426      736460 :       if (names) {
     427             :         names->Add(variable->raw_name(), zone());
     428             :       }
     429             :     }
     430             :   }
     431     4405135 : }
     432             : 
     433             : #undef CHECK_OK
     434             : #undef CHECK_OK_CUSTOM
     435             : 
     436             : 
     437             : }  // namespace internal
     438             : }  // namespace v8

Generated by: LCOV version 1.10