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