• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/parsing/preparser.h"
6 
7 #include <cmath>
8 
9 #include "src/base/logging.h"
10 #include "src/common/globals.h"
11 #include "src/logging/runtime-call-stats-scope.h"
12 #include "src/numbers/conversions-inl.h"
13 #include "src/numbers/conversions.h"
14 #include "src/parsing/parser-base.h"
15 #include "src/parsing/preparse-data.h"
16 #include "src/strings/unicode.h"
17 #include "src/utils/allocation.h"
18 #include "src/utils/utils.h"
19 #include "src/zone/zone-list-inl.h"
20 
21 namespace v8 {
22 namespace internal {
23 
24 namespace {
25 
GetIdentifierHelper(Scanner * scanner,const AstRawString * string,AstValueFactory * avf)26 PreParserIdentifier GetIdentifierHelper(Scanner* scanner,
27                                         const AstRawString* string,
28                                         AstValueFactory* avf) {
29   // These symbols require slightly different treatement:
30   // - regular keywords (async, await, etc.; treated in 1st switch.)
31   // - 'contextual' keywords (and may contain escaped; treated in 2nd switch.)
32   // - 'contextual' keywords, but may not be escaped (3rd switch).
33   switch (scanner->current_token()) {
34     case Token::AWAIT:
35       return PreParserIdentifier::Await();
36     case Token::ASYNC:
37       return PreParserIdentifier::Async();
38     case Token::PRIVATE_NAME:
39       return PreParserIdentifier::PrivateName();
40     default:
41       break;
42   }
43   if (string == avf->constructor_string()) {
44     return PreParserIdentifier::Constructor();
45   }
46   if (string == avf->name_string()) {
47     return PreParserIdentifier::Name();
48   }
49   if (scanner->literal_contains_escapes()) {
50     return PreParserIdentifier::Default();
51   }
52   if (string == avf->eval_string()) {
53     return PreParserIdentifier::Eval();
54   }
55   if (string == avf->arguments_string()) {
56     return PreParserIdentifier::Arguments();
57   }
58   return PreParserIdentifier::Default();
59 }
60 
61 }  // namespace
62 
GetIdentifier() const63 PreParserIdentifier PreParser::GetIdentifier() const {
64   const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
65   PreParserIdentifier symbol =
66       GetIdentifierHelper(scanner(), result, ast_value_factory());
67   DCHECK_NOT_NULL(result);
68   symbol.string_ = result;
69   return symbol;
70 }
71 
PreParseProgram()72 PreParser::PreParseResult PreParser::PreParseProgram() {
73   DCHECK_NULL(scope_);
74   DeclarationScope* scope = NewScriptScope(REPLMode::kNo);
75 #ifdef DEBUG
76   scope->set_is_being_lazily_parsed(true);
77 #endif
78 
79   // ModuleDeclarationInstantiation for Source Text Module Records creates a
80   // new Module Environment Record whose outer lexical environment record is
81   // the global scope.
82   if (flags().is_module()) scope = NewModuleScope(scope);
83 
84   FunctionState top_scope(&function_state_, &scope_, scope);
85   original_scope_ = scope_;
86   int start_position = peek_position();
87   PreParserScopedStatementList body(pointer_buffer());
88   ParseStatementList(&body, Token::EOS);
89   CheckConflictingVarDeclarations(scope);
90   original_scope_ = nullptr;
91   if (stack_overflow()) return kPreParseStackOverflow;
92   if (is_strict(language_mode())) {
93     CheckStrictOctalLiteral(start_position, scanner()->location().end_pos);
94   }
95   return kPreParseSuccess;
96 }
97 
ValidateDuplicate(PreParser * preparser) const98 void PreParserFormalParameters::ValidateDuplicate(PreParser* preparser) const {
99   if (has_duplicate_) preparser->ReportUnidentifiableError();
100 }
101 
ValidateStrictMode(PreParser * preparser) const102 void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const {
103   if (strict_parameter_error_) preparser->ReportUnidentifiableError();
104 }
105 
PreParseFunction(const AstRawString * function_name,FunctionKind kind,FunctionSyntaxKind function_syntax_kind,DeclarationScope * function_scope,int * use_counts,ProducedPreparseData ** produced_preparse_data)106 PreParser::PreParseResult PreParser::PreParseFunction(
107     const AstRawString* function_name, FunctionKind kind,
108     FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope,
109     int* use_counts, ProducedPreparseData** produced_preparse_data) {
110   DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
111   use_counts_ = use_counts;
112 #ifdef DEBUG
113   function_scope->set_is_being_lazily_parsed(true);
114 #endif
115 
116   PreParserFormalParameters formals(function_scope);
117 
118   // In the preparser, we use the function literal ids to count how many
119   // FunctionLiterals were encountered. The PreParser doesn't actually persist
120   // FunctionLiterals, so there IDs don't matter.
121   ResetFunctionLiteralId();
122 
123   // The caller passes the function_scope which is not yet inserted into the
124   // scope stack. All scopes above the function_scope are ignored by the
125   // PreParser.
126   DCHECK_NULL(function_state_);
127   DCHECK_NULL(scope_);
128   FunctionState function_state(&function_state_, &scope_, function_scope);
129 
130   // Start collecting data for a new function which might contain skippable
131   // functions.
132   PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);
133 
134   if (IsArrowFunction(kind)) {
135     formals.is_simple = function_scope->has_simple_parameters();
136   } else {
137     preparse_data_builder_scope.Start(function_scope);
138 
139     // Parse non-arrow function parameters. For arrow functions, the parameters
140     // have already been parsed.
141     ParameterDeclarationParsingScope formals_scope(this);
142     // We return kPreParseSuccess in failure cases too - errors are retrieved
143     // separately by Parser::SkipLazyFunctionBody.
144     ParseFormalParameterList(&formals);
145     if (formals_scope.has_duplicate()) formals.set_has_duplicate();
146     if (!formals.is_simple) {
147       BuildParameterInitializationBlock(formals);
148     }
149 
150     Expect(Token::RPAREN);
151     int formals_end_position = scanner()->location().end_pos;
152 
153     CheckArityRestrictions(formals.arity, kind, formals.has_rest,
154                            function_scope->start_position(),
155                            formals_end_position);
156   }
157 
158   Expect(Token::LBRACE);
159   DeclarationScope* inner_scope = function_scope;
160 
161   if (!formals.is_simple) {
162     inner_scope = NewVarblockScope();
163     inner_scope->set_start_position(position());
164   }
165 
166   {
167     BlockState block_state(&scope_, inner_scope);
168     ParseStatementListAndLogFunction(&formals);
169   }
170 
171   bool allow_duplicate_parameters = false;
172   CheckConflictingVarDeclarations(inner_scope);
173 
174   if (!has_error()) {
175     if (formals.is_simple) {
176       if (is_sloppy(function_scope->language_mode())) {
177         function_scope->HoistSloppyBlockFunctions(nullptr);
178       }
179 
180       allow_duplicate_parameters =
181           is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind);
182     } else {
183       if (is_sloppy(inner_scope->language_mode())) {
184         inner_scope->HoistSloppyBlockFunctions(nullptr);
185       }
186 
187       SetLanguageMode(function_scope, inner_scope->language_mode());
188       inner_scope->set_end_position(scanner()->peek_location().end_pos);
189       if (inner_scope->FinalizeBlockScope() != nullptr) {
190         const AstRawString* conflict = inner_scope->FindVariableDeclaredIn(
191             function_scope, VariableMode::kLastLexicalVariableMode);
192         if (conflict != nullptr)
193           ReportVarRedeclarationIn(conflict, inner_scope);
194       }
195     }
196   }
197 
198   use_counts_ = nullptr;
199 
200   if (stack_overflow()) {
201     return kPreParseStackOverflow;
202   } else if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
203     return kPreParseNotIdentifiableError;
204   } else if (has_error()) {
205     DCHECK(pending_error_handler()->has_pending_error());
206   } else {
207     DCHECK_EQ(Token::RBRACE, scanner()->peek());
208 
209     if (!IsArrowFunction(kind)) {
210       // Validate parameter names. We can do this only after parsing the
211       // function, since the function can declare itself strict.
212       ValidateFormalParameters(language_mode(), formals,
213                                allow_duplicate_parameters);
214       if (has_error()) {
215         if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
216           return kPreParseNotIdentifiableError;
217         } else {
218           return kPreParseSuccess;
219         }
220       }
221 
222       // Declare arguments after parsing the function since lexical
223       // 'arguments' masks the arguments object. Declare arguments before
224       // declaring the function var since the arguments object masks 'function
225       // arguments'.
226       function_scope->DeclareArguments(ast_value_factory());
227 
228       DeclareFunctionNameVar(function_name, function_syntax_kind,
229                              function_scope);
230 
231       if (preparse_data_builder_->HasData()) {
232         *produced_preparse_data =
233             ProducedPreparseData::For(preparse_data_builder_, main_zone());
234       }
235     }
236 
237     if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
238       return kPreParseNotIdentifiableError;
239     }
240 
241     if (is_strict(function_scope->language_mode())) {
242       int end_pos = scanner()->location().end_pos;
243       CheckStrictOctalLiteral(function_scope->start_position(), end_pos);
244     }
245   }
246 
247   DCHECK(!pending_error_handler()->has_error_unidentifiable_by_preparser());
248   return kPreParseSuccess;
249 }
250 
251 // Preparsing checks a JavaScript program and emits preparse-data that helps
252 // a later parsing to be faster.
253 // See preparser-data.h for the data.
254 
255 // The PreParser checks that the syntax follows the grammar for JavaScript,
256 // and collects some information about the program along the way.
257 // The grammar check is only performed in order to understand the program
258 // sufficiently to deduce some information about it, that can be used
259 // to speed up later parsing. Finding errors is not the goal of pre-parsing,
260 // rather it is to speed up properly written and correct programs.
261 // That means that contextual checks (like a label being declared where
262 // it is used) are generally omitted.
263 
ParseFunctionLiteral(Identifier function_name,Scanner::Location function_name_location,FunctionNameValidity function_name_validity,FunctionKind kind,int function_token_pos,FunctionSyntaxKind function_syntax_kind,LanguageMode language_mode,ZonePtrList<const AstRawString> * arguments_for_wrapped_function)264 PreParser::Expression PreParser::ParseFunctionLiteral(
265     Identifier function_name, Scanner::Location function_name_location,
266     FunctionNameValidity function_name_validity, FunctionKind kind,
267     int function_token_pos, FunctionSyntaxKind function_syntax_kind,
268     LanguageMode language_mode,
269     ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
270   FunctionParsingScope function_parsing_scope(this);
271   // Wrapped functions are not parsed in the preparser.
272   DCHECK_NULL(arguments_for_wrapped_function);
273   DCHECK_NE(FunctionSyntaxKind::kWrapped, function_syntax_kind);
274   // Function ::
275   //   '(' FormalParameterList? ')' '{' FunctionBody '}'
276   RCS_SCOPE(runtime_call_stats_,
277             RuntimeCallCounterId::kPreParseWithVariableResolution,
278             RuntimeCallStats::kThreadSpecific);
279 
280   base::ElapsedTimer timer;
281   if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
282 
283   DeclarationScope* function_scope = NewFunctionScope(kind);
284   function_scope->SetLanguageMode(language_mode);
285   int func_id = GetNextFunctionLiteralId();
286   bool skippable_function = false;
287 
288   // Start collecting data for a new function which might contain skippable
289   // functions.
290   {
291     PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);
292     skippable_function = !function_state_->next_function_is_likely_called() &&
293                          preparse_data_builder_ != nullptr;
294     if (skippable_function) {
295       preparse_data_builder_scope.Start(function_scope);
296     }
297 
298     FunctionState function_state(&function_state_, &scope_, function_scope);
299 
300     Expect(Token::LPAREN);
301     int start_position = position();
302     function_scope->set_start_position(start_position);
303     PreParserFormalParameters formals(function_scope);
304     {
305       ParameterDeclarationParsingScope formals_scope(this);
306       ParseFormalParameterList(&formals);
307       if (formals_scope.has_duplicate()) formals.set_has_duplicate();
308     }
309     Expect(Token::RPAREN);
310     int formals_end_position = scanner()->location().end_pos;
311 
312     CheckArityRestrictions(formals.arity, kind, formals.has_rest,
313                            start_position, formals_end_position);
314 
315     Expect(Token::LBRACE);
316 
317     // Parse function body.
318     PreParserScopedStatementList body(pointer_buffer());
319     int pos = function_token_pos == kNoSourcePosition ? peek_position()
320                                                       : function_token_pos;
321     AcceptINScope scope(this, true);
322     ParseFunctionBody(&body, function_name, pos, formals, kind,
323                       function_syntax_kind, FunctionBodyType::kBlock);
324 
325     // Parsing the body may change the language mode in our scope.
326     language_mode = function_scope->language_mode();
327 
328     // Validate name and parameter names. We can do this only after parsing the
329     // function, since the function can declare itself strict.
330     CheckFunctionName(language_mode, function_name, function_name_validity,
331                       function_name_location);
332 
333     if (is_strict(language_mode)) {
334       CheckStrictOctalLiteral(start_position, end_position());
335     }
336     if (skippable_function) {
337       preparse_data_builder_scope.SetSkippableFunction(
338           function_scope, formals.function_length,
339           GetLastFunctionLiteralId() - func_id);
340     }
341   }
342 
343   if (V8_UNLIKELY(FLAG_log_function_events)) {
344     double ms = timer.Elapsed().InMillisecondsF();
345     const char* event_name = "preparse-resolution";
346     // We might not always get a function name here. However, it can be easily
347     // reconstructed from the script id and the byte range in the log processor.
348     const char* name = "";
349     size_t name_byte_length = 0;
350     bool is_one_byte = true;
351     const AstRawString* string = function_name.string_;
352     if (string != nullptr) {
353       name = reinterpret_cast<const char*>(string->raw_data());
354       name_byte_length = string->byte_length();
355       is_one_byte = string->is_one_byte();
356     }
357     logger_->FunctionEvent(
358         event_name, flags().script_id(), ms, function_scope->start_position(),
359         function_scope->end_position(), name, name_byte_length, is_one_byte);
360   }
361 
362   return Expression::Default();
363 }
364 
ParseStatementListAndLogFunction(PreParserFormalParameters * formals)365 void PreParser::ParseStatementListAndLogFunction(
366     PreParserFormalParameters* formals) {
367   PreParserScopedStatementList body(pointer_buffer());
368   ParseStatementList(&body, Token::RBRACE);
369 
370   // Position right after terminal '}'.
371   DCHECK_IMPLIES(!has_error(), scanner()->peek() == Token::RBRACE);
372   int body_end = scanner()->peek_location().end_pos;
373   DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
374   log_.LogFunction(body_end, formals->num_parameters(),
375                    formals->function_length, GetLastFunctionLiteralId());
376 }
377 
BuildParameterInitializationBlock(const PreParserFormalParameters & parameters)378 PreParserBlock PreParser::BuildParameterInitializationBlock(
379     const PreParserFormalParameters& parameters) {
380   DCHECK(!parameters.is_simple);
381   DCHECK(scope()->is_function_scope());
382   if (scope()->AsDeclarationScope()->sloppy_eval_can_extend_vars() &&
383       preparse_data_builder_ != nullptr) {
384     // We cannot replicate the Scope structure constructed by the Parser,
385     // because we've lost information whether each individual parameter was
386     // simple or not. Give up trying to produce data to skip inner functions.
387     if (preparse_data_builder_->parent() != nullptr) {
388       // Lazy parsing started before the current function; the function which
389       // cannot contain skippable functions is the parent function. (Its inner
390       // functions cannot either; they are implicitly bailed out.)
391       preparse_data_builder_->parent()->Bailout();
392     } else {
393       // Lazy parsing started at the current function; it cannot contain
394       // skippable functions.
395       preparse_data_builder_->Bailout();
396     }
397   }
398 
399   return PreParserBlock::Default();
400 }
401 
IdentifierEquals(const PreParserIdentifier & identifier,const AstRawString * other)402 bool PreParser::IdentifierEquals(const PreParserIdentifier& identifier,
403                                  const AstRawString* other) {
404   return identifier.string_ == other;
405 }
406 
407 }  // namespace internal
408 }  // namespace v8
409