• 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 <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/parsing/duplicate-finder.h"
13 #include "src/parsing/parser-base.h"
14 #include "src/parsing/preparsed-scope-data.h"
15 #include "src/parsing/preparser.h"
16 #include "src/unicode.h"
17 #include "src/utils.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 // ----------------------------------------------------------------------------
23 // The CHECK_OK macro is a convenient macro to enforce error
24 // handling for functions that may fail (by returning !*ok).
25 //
26 // CAUTION: This macro appends extra statements after a call,
27 // thus it must never be used where only a single statement
28 // is correct (e.g. an if statement branch w/o braces)!
29 
30 #define CHECK_OK_VALUE(x) ok); \
31   if (!*ok) return x;          \
32   ((void)0
33 #define DUMMY )  // to make indentation work
34 #undef DUMMY
35 
36 #define CHECK_OK CHECK_OK_VALUE(Expression::Default())
37 #define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
38 
39 namespace {
40 
GetSymbolHelper(Scanner * scanner)41 PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
42   // These symbols require slightly different treatement:
43   // - regular keywords (async, await, etc.; treated in 1st switch.)
44   // - 'contextual' keywords (and may contain escaped; treated in 2nd switch.)
45   // - 'contextual' keywords, but may not be escaped (3rd switch).
46   switch (scanner->current_token()) {
47     case Token::AWAIT:
48       return PreParserIdentifier::Await();
49     case Token::ASYNC:
50       return PreParserIdentifier::Async();
51     case Token::PRIVATE_NAME:
52       return PreParserIdentifier::PrivateName();
53     default:
54       break;
55   }
56   switch (scanner->current_contextual_token()) {
57     case Token::CONSTRUCTOR:
58       return PreParserIdentifier::Constructor();
59     case Token::NAME:
60       return PreParserIdentifier::Name();
61     default:
62       break;
63   }
64   if (scanner->literal_contains_escapes()) {
65     return PreParserIdentifier::Default();
66   }
67   switch (scanner->current_contextual_token()) {
68     case Token::EVAL:
69       return PreParserIdentifier::Eval();
70     case Token::ARGUMENTS:
71       return PreParserIdentifier::Arguments();
72     default:
73       break;
74   }
75   return PreParserIdentifier::Default();
76 }
77 
78 }  // unnamed namespace
79 
GetSymbol() const80 PreParserIdentifier PreParser::GetSymbol() const {
81   PreParserIdentifier symbol = GetSymbolHelper(scanner());
82   if (track_unresolved_variables_) {
83     const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
84     DCHECK_NOT_NULL(result);
85     symbol.string_ = result;
86   }
87   return symbol;
88 }
89 
PreParseProgram()90 PreParser::PreParseResult PreParser::PreParseProgram() {
91   DCHECK_NULL(scope_);
92   DeclarationScope* scope = NewScriptScope();
93 #ifdef DEBUG
94   scope->set_is_being_lazily_parsed(true);
95 #endif
96 
97   // ModuleDeclarationInstantiation for Source Text Module Records creates a
98   // new Module Environment Record whose outer lexical environment record is
99   // the global scope.
100   if (parsing_module_) scope = NewModuleScope(scope);
101 
102   FunctionState top_scope(&function_state_, &scope_, scope);
103   original_scope_ = scope_;
104   bool ok = true;
105   int start_position = scanner()->peek_location().beg_pos;
106   PreParserStatementList body;
107   ParseStatementList(body, Token::EOS, &ok);
108   original_scope_ = nullptr;
109   if (stack_overflow()) return kPreParseStackOverflow;
110   if (!ok) {
111     ReportUnexpectedToken(scanner()->current_token());
112   } else if (is_strict(language_mode())) {
113     CheckStrictOctalLiteral(start_position, scanner()->location().end_pos, &ok);
114   }
115   return kPreParseSuccess;
116 }
117 
PreParseFunction(const AstRawString * function_name,FunctionKind kind,FunctionLiteral::FunctionType function_type,DeclarationScope * function_scope,bool is_inner_function,bool may_abort,int * use_counts,ProducedPreParsedScopeData ** produced_preparsed_scope_data,int script_id)118 PreParser::PreParseResult PreParser::PreParseFunction(
119     const AstRawString* function_name, FunctionKind kind,
120     FunctionLiteral::FunctionType function_type,
121     DeclarationScope* function_scope, bool is_inner_function, bool may_abort,
122     int* use_counts, ProducedPreParsedScopeData** produced_preparsed_scope_data,
123     int script_id) {
124   DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
125   use_counts_ = use_counts;
126   DCHECK(!track_unresolved_variables_);
127   track_unresolved_variables_ = is_inner_function;
128   set_script_id(script_id);
129 #ifdef DEBUG
130   function_scope->set_is_being_lazily_parsed(true);
131 #endif
132 
133   // Start collecting data for a new function which might contain skippable
134   // functions.
135   std::unique_ptr<ProducedPreParsedScopeData::DataGatheringScope>
136       produced_preparsed_scope_data_scope;
137   if (FLAG_preparser_scope_analysis && !IsArrowFunction(kind)) {
138     track_unresolved_variables_ = true;
139     produced_preparsed_scope_data_scope.reset(
140         new ProducedPreParsedScopeData::DataGatheringScope(function_scope,
141                                                            this));
142   }
143 
144   // In the preparser, we use the function literal ids to count how many
145   // FunctionLiterals were encountered. The PreParser doesn't actually persist
146   // FunctionLiterals, so there IDs don't matter.
147   ResetFunctionLiteralId();
148 
149   // The caller passes the function_scope which is not yet inserted into the
150   // scope stack. All scopes above the function_scope are ignored by the
151   // PreParser.
152   DCHECK_NULL(function_state_);
153   DCHECK_NULL(scope_);
154   FunctionState function_state(&function_state_, &scope_, function_scope);
155   // This indirection is needed so that we can use the CHECK_OK macros.
156   bool ok_holder = true;
157   bool* ok = &ok_holder;
158 
159   PreParserFormalParameters formals(function_scope);
160   DuplicateFinder duplicate_finder;
161   std::unique_ptr<ExpressionClassifier> formals_classifier;
162 
163   // Parse non-arrow function parameters. For arrow functions, the parameters
164   // have already been parsed.
165   if (!IsArrowFunction(kind)) {
166     formals_classifier.reset(new ExpressionClassifier(this, &duplicate_finder));
167     // We return kPreParseSuccess in failure cases too - errors are retrieved
168     // separately by Parser::SkipLazyFunctionBody.
169     ParseFormalParameterList(&formals, CHECK_OK_VALUE(kPreParseSuccess));
170     Expect(Token::RPAREN, CHECK_OK_VALUE(kPreParseSuccess));
171     int formals_end_position = scanner()->location().end_pos;
172 
173     CheckArityRestrictions(
174         formals.arity, kind, formals.has_rest, function_scope->start_position(),
175         formals_end_position, CHECK_OK_VALUE(kPreParseSuccess));
176   }
177 
178   Expect(Token::LBRACE, CHECK_OK_VALUE(kPreParseSuccess));
179   DeclarationScope* inner_scope = function_scope;
180   LazyParsingResult result;
181 
182   if (!formals.is_simple) {
183     inner_scope = NewVarblockScope();
184     inner_scope->set_start_position(scanner()->location().beg_pos);
185   }
186 
187   {
188     BlockState block_state(&scope_, inner_scope);
189     result = ParseStatementListAndLogFunction(&formals, may_abort, ok);
190   }
191 
192   if (!formals.is_simple) {
193     BuildParameterInitializationBlock(formals, ok);
194 
195     if (is_sloppy(inner_scope->language_mode())) {
196       inner_scope->HoistSloppyBlockFunctions(nullptr);
197     }
198 
199     SetLanguageMode(function_scope, inner_scope->language_mode());
200     inner_scope->set_end_position(scanner()->peek_location().end_pos);
201     inner_scope->FinalizeBlockScope();
202   } else {
203     if (is_sloppy(function_scope->language_mode())) {
204       function_scope->HoistSloppyBlockFunctions(nullptr);
205     }
206   }
207 
208   if (!IsArrowFunction(kind) && track_unresolved_variables_ &&
209       result == kLazyParsingComplete) {
210     // Declare arguments after parsing the function since lexical 'arguments'
211     // masks the arguments object. Declare arguments before declaring the
212     // function var since the arguments object masks 'function arguments'.
213     function_scope->DeclareArguments(ast_value_factory());
214 
215     DeclareFunctionNameVar(function_name, function_type, function_scope);
216   }
217 
218   use_counts_ = nullptr;
219   track_unresolved_variables_ = false;
220 
221   if (result == kLazyParsingAborted) {
222     return kPreParseAbort;
223   } else if (stack_overflow()) {
224     return kPreParseStackOverflow;
225   } else if (!*ok) {
226     DCHECK(pending_error_handler()->has_pending_error());
227   } else {
228     DCHECK_EQ(Token::RBRACE, scanner()->peek());
229 
230     if (!IsArrowFunction(kind)) {
231       // Validate parameter names. We can do this only after parsing the
232       // function, since the function can declare itself strict.
233       const bool allow_duplicate_parameters =
234           is_sloppy(function_scope->language_mode()) && formals.is_simple &&
235           !IsConciseMethod(kind);
236       ValidateFormalParameters(function_scope->language_mode(),
237                                allow_duplicate_parameters,
238                                CHECK_OK_VALUE(kPreParseSuccess));
239 
240       *produced_preparsed_scope_data = produced_preparsed_scope_data_;
241     }
242 
243     if (is_strict(function_scope->language_mode())) {
244       int end_pos = scanner()->location().end_pos;
245       CheckStrictOctalLiteral(function_scope->start_position(), end_pos, ok);
246     }
247   }
248   return kPreParseSuccess;
249 }
250 
251 
252 // Preparsing checks a JavaScript program and emits preparse-data that helps
253 // a later parsing to be faster.
254 // See preparser-data.h for the data.
255 
256 // The PreParser checks that the syntax follows the grammar for JavaScript,
257 // and collects some information about the program along the way.
258 // The grammar check is only performed in order to understand the program
259 // sufficiently to deduce some information about it, that can be used
260 // to speed up later parsing. Finding errors is not the goal of pre-parsing,
261 // rather it is to speed up properly written and correct programs.
262 // That means that contextual checks (like a label being declared where
263 // it is used) are generally omitted.
264 
ParseFunctionLiteral(Identifier function_name,Scanner::Location function_name_location,FunctionNameValidity function_name_validity,FunctionKind kind,int function_token_pos,FunctionLiteral::FunctionType function_type,LanguageMode language_mode,ZonePtrList<const AstRawString> * arguments_for_wrapped_function,bool * ok)265 PreParser::Expression PreParser::ParseFunctionLiteral(
266     Identifier function_name, Scanner::Location function_name_location,
267     FunctionNameValidity function_name_validity, FunctionKind kind,
268     int function_token_pos, FunctionLiteral::FunctionType function_type,
269     LanguageMode language_mode,
270     ZonePtrList<const AstRawString>* arguments_for_wrapped_function, bool* ok) {
271   // Wrapped functions are not parsed in the preparser.
272   DCHECK_NULL(arguments_for_wrapped_function);
273   DCHECK_NE(FunctionLiteral::kWrapped, function_type);
274   // Function ::
275   //   '(' FormalParameterList? ')' '{' FunctionBody '}'
276   const RuntimeCallCounterId counters[2][2] = {
277       {RuntimeCallCounterId::kPreParseBackgroundNoVariableResolution,
278        RuntimeCallCounterId::kPreParseNoVariableResolution},
279       {RuntimeCallCounterId::kPreParseBackgroundWithVariableResolution,
280        RuntimeCallCounterId::kPreParseWithVariableResolution}};
281   RuntimeCallTimerScope runtime_timer(
282       runtime_call_stats_,
283       counters[track_unresolved_variables_][parsing_on_main_thread_]);
284 
285   base::ElapsedTimer timer;
286   if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
287 
288   DeclarationScope* function_scope = NewFunctionScope(kind);
289   function_scope->SetLanguageMode(language_mode);
290 
291   // Start collecting data for a new function which might contain skippable
292   // functions.
293   std::unique_ptr<ProducedPreParsedScopeData::DataGatheringScope>
294       produced_preparsed_scope_data_scope;
295   if (!function_state_->next_function_is_likely_called() &&
296       produced_preparsed_scope_data_ != nullptr) {
297     DCHECK(FLAG_preparser_scope_analysis);
298     DCHECK(track_unresolved_variables_);
299     produced_preparsed_scope_data_scope.reset(
300         new ProducedPreParsedScopeData::DataGatheringScope(function_scope,
301                                                            this));
302   }
303 
304   FunctionState function_state(&function_state_, &scope_, function_scope);
305   DuplicateFinder duplicate_finder;
306   ExpressionClassifier formals_classifier(this, &duplicate_finder);
307   int func_id = GetNextFunctionLiteralId();
308 
309   Expect(Token::LPAREN, CHECK_OK);
310   int start_position = scanner()->location().beg_pos;
311   function_scope->set_start_position(start_position);
312   PreParserFormalParameters formals(function_scope);
313   ParseFormalParameterList(&formals, CHECK_OK);
314   Expect(Token::RPAREN, CHECK_OK);
315   int formals_end_position = scanner()->location().end_pos;
316 
317   CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position,
318                          formals_end_position, CHECK_OK);
319 
320   Expect(Token::LBRACE, CHECK_OK);
321 
322   // Parse function body.
323   PreParserStatementList body;
324   int pos = function_token_pos == kNoSourcePosition ? peek_position()
325                                                     : function_token_pos;
326   ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
327                     CHECK_OK);
328 
329   // Parsing the body may change the language mode in our scope.
330   language_mode = function_scope->language_mode();
331 
332   if (is_sloppy(language_mode)) {
333     function_scope->HoistSloppyBlockFunctions(nullptr);
334   }
335 
336   // Validate name and parameter names. We can do this only after parsing the
337   // function, since the function can declare itself strict.
338   CheckFunctionName(language_mode, function_name, function_name_validity,
339                     function_name_location, CHECK_OK);
340   const bool allow_duplicate_parameters =
341       is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
342   ValidateFormalParameters(language_mode, allow_duplicate_parameters, CHECK_OK);
343 
344   int end_position = scanner()->location().end_pos;
345   if (is_strict(language_mode)) {
346     CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
347   }
348 
349   if (produced_preparsed_scope_data_scope) {
350     produced_preparsed_scope_data_scope->MarkFunctionAsSkippable(
351         end_position, GetLastFunctionLiteralId() - func_id);
352   }
353   if (V8_UNLIKELY(FLAG_log_function_events)) {
354     double ms = timer.Elapsed().InMillisecondsF();
355     const char* event_name = track_unresolved_variables_
356                                  ? "preparse-resolution"
357                                  : "preparse-no-resolution";
358     // We might not always get a function name here. However, it can be easily
359     // reconstructed from the script id and the byte range in the log processor.
360     const char* name = "";
361     size_t name_byte_length = 0;
362     const AstRawString* string = function_name.string_;
363     if (string != nullptr) {
364       name = reinterpret_cast<const char*>(string->raw_data());
365       name_byte_length = string->byte_length();
366     }
367     logger_->FunctionEvent(
368         event_name, script_id(), ms, function_scope->start_position(),
369         function_scope->end_position(), name, name_byte_length);
370   }
371 
372   return Expression::Default();
373 }
374 
ParseStatementListAndLogFunction(PreParserFormalParameters * formals,bool may_abort,bool * ok)375 PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
376     PreParserFormalParameters* formals, bool may_abort, bool* ok) {
377   PreParserStatementList body;
378   LazyParsingResult result = ParseStatementList(
379       body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
380   if (result == kLazyParsingAborted) return result;
381 
382   // Position right after terminal '}'.
383   DCHECK_EQ(Token::RBRACE, scanner()->peek());
384   int body_end = scanner()->peek_location().end_pos;
385   DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
386   log_.LogFunction(body_end, formals->num_parameters(),
387                    GetLastFunctionLiteralId());
388   return kLazyParsingComplete;
389 }
390 
BuildParameterInitializationBlock(const PreParserFormalParameters & parameters,bool * ok)391 PreParserStatement PreParser::BuildParameterInitializationBlock(
392     const PreParserFormalParameters& parameters, bool* ok) {
393   DCHECK(!parameters.is_simple);
394   DCHECK(scope()->is_function_scope());
395   if (FLAG_preparser_scope_analysis &&
396       scope()->AsDeclarationScope()->calls_sloppy_eval() &&
397       produced_preparsed_scope_data_ != nullptr) {
398     // We cannot replicate the Scope structure constructed by the Parser,
399     // because we've lost information whether each individual parameter was
400     // simple or not. Give up trying to produce data to skip inner functions.
401     if (produced_preparsed_scope_data_->parent() != nullptr) {
402       // Lazy parsing started before the current function; the function which
403       // cannot contain skippable functions is the parent function. (Its inner
404       // functions cannot either; they are implicitly bailed out.)
405       produced_preparsed_scope_data_->parent()->Bailout();
406     } else {
407       // Lazy parsing started at the current function; it cannot contain
408       // skippable functions.
409       produced_preparsed_scope_data_->Bailout();
410     }
411   }
412 
413   return PreParserStatement::Default();
414 }
415 
ExpressionFromIdentifier(const PreParserIdentifier & name,int start_position,InferName infer)416 PreParserExpression PreParser::ExpressionFromIdentifier(
417     const PreParserIdentifier& name, int start_position, InferName infer) {
418   VariableProxy* proxy = nullptr;
419   if (track_unresolved_variables_) {
420     DCHECK_NOT_NULL(name.string_);
421     proxy = scope()->NewUnresolved(factory()->ast_node_factory(), name.string_,
422                                    start_position, NORMAL_VARIABLE);
423   }
424   return PreParserExpression::FromIdentifier(name, proxy, zone());
425 }
426 
DeclareAndInitializeVariables(PreParserStatement block,const DeclarationDescriptor * declaration_descriptor,const DeclarationParsingResult::Declaration * declaration,ZonePtrList<const AstRawString> * names,bool * ok)427 void PreParser::DeclareAndInitializeVariables(
428     PreParserStatement block,
429     const DeclarationDescriptor* declaration_descriptor,
430     const DeclarationParsingResult::Declaration* declaration,
431     ZonePtrList<const AstRawString>* names, bool* ok) {
432   if (declaration->pattern.variables_ != nullptr) {
433     DCHECK(FLAG_lazy_inner_functions);
434     DCHECK(track_unresolved_variables_);
435     for (auto variable : *(declaration->pattern.variables_)) {
436       declaration_descriptor->scope->RemoveUnresolved(variable);
437       Variable* var = scope()->DeclareVariableName(
438           variable->raw_name(), declaration_descriptor->mode);
439       if (FLAG_preparser_scope_analysis) {
440         MarkLoopVariableAsAssigned(declaration_descriptor->scope, var,
441                                    declaration_descriptor->declaration_kind);
442         // This is only necessary if there is an initializer, but we don't have
443         // that information here.  Consequently, the preparser sometimes says
444         // maybe-assigned where the parser (correctly) says never-assigned.
445       }
446       if (names) {
447         names->Add(variable->raw_name(), zone());
448       }
449     }
450   }
451 }
452 
453 #undef CHECK_OK
454 #undef CHECK_OK_CUSTOM
455 
456 
457 }  // namespace internal
458 }  // namespace v8
459