v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
preparser.cc
Go to the documentation of this file.
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
6
7#include <cmath>
8
9#include "src/base/logging.h"
10#include "src/common/globals.h"
16#include "src/strings/unicode.h"
18#include "src/utils/utils.h"
20
21namespace v8 {
22namespace internal {
23
24namespace {
25
26PreParserIdentifier GetIdentifierHelper(Scanner* scanner,
27 const AstRawString* string,
28 AstValueFactory* avf) {
29 // These symbols require slightly different treatement:
30 // - regular keywords (async, 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::kAsync:
36 case Token::kPrivateName:
38 default:
39 break;
40 }
41 if (string == avf->constructor_string()) {
43 }
44 if (scanner->literal_contains_escapes()) {
46 }
47 if (string == avf->eval_string()) {
49 }
50 if (string == avf->arguments_string()) {
52 }
54}
55
56} // namespace
57
60 PreParserIdentifier symbol =
61 GetIdentifierHelper(scanner(), result, ast_value_factory());
63 symbol.string_ = result;
64 return symbol;
65}
66
70#ifdef DEBUG
71 scope->set_is_being_lazily_parsed(true);
72#endif
73
74 // ModuleDeclarationInstantiation for Source Text Module Records creates a
75 // new Module Environment Record whose outer lexical environment record is
76 // the global scope.
77 if (flags().is_module()) scope = NewModuleScope(scope);
78
79 FunctionState top_scope(&function_state_, &scope_, scope);
81 int start_position = peek_position();
83 ParseStatementList(&body, Token::kEos);
85 original_scope_ = nullptr;
87 if (is_strict(language_mode())) {
88 CheckStrictOctalLiteral(start_position, scanner()->location().end_pos);
89 }
90 return kPreParseSuccess;
91}
92
96
100
102 const AstRawString* function_name, FunctionKind kind,
103 FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope,
104 int* use_counts, ProducedPreparseData** produced_preparse_data) {
105 DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
106 use_counts_ = use_counts;
107#ifdef DEBUG
108 function_scope->set_is_being_lazily_parsed(true);
109#endif
110
111 PreParserFormalParameters formals(function_scope);
112
113 // In the preparser, we use the function literal ids to count how many
114 // FunctionLiterals were encountered. The PreParser doesn't actually persist
115 // FunctionLiterals, so there IDs don't matter.
116 ResetInfoId();
117
118 // The caller passes the function_scope which is not yet inserted into the
119 // scope stack. All scopes above the function_scope are ignored by the
120 // PreParser.
123 FunctionState function_state(&function_state_, &scope_, function_scope);
124
125 // Start collecting data for a new function which might contain skippable
126 // functions.
127 PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);
128
129 if (IsArrowFunction(kind)) {
130 formals.is_simple = function_scope->has_simple_parameters();
131 } else {
132 preparse_data_builder_scope.Start(function_scope);
133
134 // Parse non-arrow function parameters. For arrow functions, the parameters
135 // have already been parsed.
136 ParameterDeclarationParsingScope formals_scope(this);
137 // We return kPreParseSuccess in failure cases too - errors are retrieved
138 // separately by Parser::SkipLazyFunctionBody.
139 ParseFormalParameterList(&formals);
140 if (formals_scope.has_duplicate()) formals.set_has_duplicate();
141 if (!formals.is_simple) {
143 }
144
145 Expect(Token::kRightParen);
146 int formals_end_position = scanner()->location().end_pos;
147
148 CheckArityRestrictions(formals.arity, kind, formals.has_rest,
149 function_scope->start_position(),
150 formals_end_position);
151 }
152
153 Expect(Token::kLeftBrace);
154 DeclarationScope* inner_scope = function_scope;
155
156 if (!formals.is_simple) {
157 inner_scope = NewVarblockScope();
158 inner_scope->set_start_position(position());
159 }
160
161 {
162 BlockState block_state(&scope_, inner_scope);
164 }
165
166 bool allow_duplicate_parameters = false;
168
169 if (!has_error()) {
170 if (formals.is_simple) {
171 if (is_sloppy(function_scope->language_mode())) {
172 function_scope->HoistSloppyBlockFunctions(nullptr);
173 }
174
175 allow_duplicate_parameters =
176 is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind);
177 } else {
178 if (is_sloppy(inner_scope->language_mode())) {
179 inner_scope->HoistSloppyBlockFunctions(nullptr);
180 }
181
182 SetLanguageMode(function_scope, inner_scope->language_mode());
183 inner_scope->set_end_position(scanner()->peek_location().end_pos);
184 if (inner_scope->FinalizeBlockScope() != nullptr) {
185 const AstRawString* conflict = inner_scope->FindVariableDeclaredIn(
187 if (conflict != nullptr)
188 ReportVarRedeclarationIn(conflict, inner_scope);
189 }
190 }
191 }
192
193 use_counts_ = nullptr;
194
195 if (stack_overflow()) {
197 } else if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
199 } else if (has_error()) {
200 DCHECK(pending_error_handler()->has_pending_error());
201 } else {
202 DCHECK_EQ(Token::kRightBrace, scanner()->peek());
203
204 if (!IsArrowFunction(kind)) {
205 // Validate parameter names. We can do this only after parsing the
206 // function, since the function can declare itself strict.
208 allow_duplicate_parameters);
209 if (has_error()) {
210 if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
212 } else {
213 return kPreParseSuccess;
214 }
215 }
216
217 // Declare arguments after parsing the function since lexical
218 // 'arguments' masks the arguments object. Declare arguments before
219 // declaring the function var since the arguments object masks 'function
220 // arguments'.
221 function_scope->DeclareArguments(ast_value_factory());
222
223 DeclareFunctionNameVar(function_name, function_syntax_kind,
224 function_scope);
225
227 *produced_preparse_data =
229 }
230 }
231
232 if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
234 }
235
236 if (is_strict(function_scope->language_mode())) {
237 int end_pos = scanner()->location().end_pos;
238 CheckStrictOctalLiteral(function_scope->start_position(), end_pos);
239 }
240 }
241
242 DCHECK(!pending_error_handler()->has_error_unidentifiable_by_preparser());
243 return kPreParseSuccess;
244}
245
246// Preparsing checks a JavaScript program and emits preparse-data that helps
247// a later parsing to be faster.
248// See preparser-data.h for the data.
249
250// The PreParser checks that the syntax follows the grammar for JavaScript,
251// and collects some information about the program along the way.
252// The grammar check is only performed in order to understand the program
253// sufficiently to deduce some information about it, that can be used
254// to speed up later parsing. Finding errors is not the goal of pre-parsing,
255// rather it is to speed up properly written and correct programs.
256// That means that contextual checks (like a label being declared where
257// it is used) are generally omitted.
258
260 Identifier function_name, Scanner::Location function_name_location,
261 FunctionNameValidity function_name_validity, FunctionKind kind,
262 int function_token_pos, FunctionSyntaxKind function_syntax_kind,
263 LanguageMode language_mode,
264 ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
265 FunctionParsingScope function_parsing_scope(this);
266 // Wrapped functions are not parsed in the preparser.
267 DCHECK_NULL(arguments_for_wrapped_function);
268 DCHECK_NE(FunctionSyntaxKind::kWrapped, function_syntax_kind);
269 // Function ::
270 // '(' FormalParameterList? ')' '{' FunctionBody '}'
272 RuntimeCallCounterId::kPreParseWithVariableResolution,
273 RuntimeCallStats::kThreadSpecific);
274
275 base::ElapsedTimer timer;
276 if (V8_UNLIKELY(v8_flags.log_function_events)) timer.Start();
277
278 DeclarationScope* function_scope = NewFunctionScope(kind);
279 function_scope->SetLanguageMode(language_mode);
280 int func_id = GetNextInfoId();
281 bool skippable_function = false;
282
283 // Start collecting data for a new function which might contain skippable
284 // functions.
285 {
286 PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);
287 skippable_function = !function_state_->next_function_is_likely_called() &&
288 preparse_data_builder_ != nullptr;
289 if (skippable_function) {
290 preparse_data_builder_scope.Start(function_scope);
291 }
292
293 FunctionState function_state(&function_state_, &scope_, function_scope);
294
295 Expect(Token::kLeftParen);
296 int start_position = position();
297 function_scope->set_start_position(start_position);
298 PreParserFormalParameters formals(function_scope);
299 {
300 ParameterDeclarationParsingScope formals_scope(this);
301 ParseFormalParameterList(&formals);
302 if (formals_scope.has_duplicate()) formals.set_has_duplicate();
303 }
304 Expect(Token::kRightParen);
305 int formals_end_position = scanner()->location().end_pos;
306
307 CheckArityRestrictions(formals.arity, kind, formals.has_rest,
308 start_position, formals_end_position);
309
310 Expect(Token::kLeftBrace);
311
312 // Parse function body.
314 int pos = function_token_pos == kNoSourcePosition ? peek_position()
315 : function_token_pos;
316 AcceptINScope scope(this, true);
317 ParseFunctionBody(&body, function_name, pos, formals, kind,
318 function_syntax_kind, FunctionBodyType::kBlock);
319
320 // Parsing the body may change the language mode in our scope.
321 language_mode = function_scope->language_mode();
322
323 // Validate name and parameter names. We can do this only after parsing the
324 // function, since the function can declare itself strict.
325 CheckFunctionName(language_mode, function_name, function_name_validity,
326 function_name_location);
327
329 CheckStrictOctalLiteral(start_position, end_position());
330 }
331 if (skippable_function) {
332 preparse_data_builder_scope.SetSkippableFunction(
333 function_scope, formals.function_length, GetLastInfoId() - func_id);
334 }
335 }
336
337 if (V8_UNLIKELY(v8_flags.log_function_events)) {
338 double ms = timer.Elapsed().InMillisecondsF();
339 const char* event_name = "preparse-resolution";
340 // We might not always get a function name here. However, it can be easily
341 // reconstructed from the script id and the byte range in the log processor.
342 const char* name = "";
343 size_t name_byte_length = 0;
344 bool is_one_byte = true;
345 const AstRawString* string = function_name.string_;
346 if (string != nullptr) {
347 name = reinterpret_cast<const char*>(string->raw_data());
348 name_byte_length = string->byte_length();
349 is_one_byte = string->is_one_byte();
350 }
352 event_name, flags().script_id(), ms, function_scope->start_position(),
353 function_scope->end_position(), name, name_byte_length, is_one_byte);
354 }
355
356 return Expression::Default();
357}
358
360 PreParserFormalParameters* formals) {
362 ParseStatementList(&body, Token::kRightBrace);
363
364 // Position right after terminal '}'.
365 DCHECK_IMPLIES(!has_error(), scanner()->peek() == Token::kRightBrace);
366 int body_end = scanner()->peek_location().end_pos;
367 DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
368 log_.LogFunction(body_end, formals->num_parameters(),
369 formals->function_length, GetLastInfoId());
370}
371
373 const PreParserFormalParameters& parameters) {
374 DCHECK(!parameters.is_simple);
375 DCHECK(scope()->is_function_scope());
376 if (scope()->AsDeclarationScope()->sloppy_eval_can_extend_vars() &&
377 preparse_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 (preparse_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.)
386 } else {
387 // Lazy parsing started at the current function; it cannot contain
388 // skippable functions.
390 }
391 }
392
394}
395
397 const AstRawString* other) {
398 return identifier.string_ == other;
399}
400
401} // namespace internal
402} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
SourcePosition pos
void HoistSloppyBlockFunctions(AstNodeFactory *factory)
Definition scopes.cc:581
void DeclareArguments(AstValueFactory *ast_value_factory)
Definition scopes.cc:760
bool has_simple_parameters() const
Definition scopes.h:1076
V8_INLINE void ParseStatementList(StatementListT *body, Token::Value end_token)
void ParseFormalParameterList(FormalParametersT *parameters)
void CheckConflictingVarDeclarations(DeclarationScope *scope)
void ValidateFormalParameters(LanguageMode language_mode, const FormalParametersT &parameters, bool allow_duplicates)
void CheckStrictOctalLiteral(int beg_pos, int end_pos)
DeclarationScope * NewFunctionScope(FunctionKind kind, Zone *parse_zone=nullptr) const
void CheckFunctionName(LanguageMode language_mode, IdentifierT function_name, FunctionNameValidity function_name_validity, const Scanner::Location &function_name_loc)
void Expect(Token::Value token)
DeclarationScope * NewScriptScope(REPLMode repl_mode) const
internal::V8FileLogger * v8_file_logger_
V8_INLINE Token::Value peek()
void CheckArityRestrictions(int param_count, FunctionKind function_type, bool has_rest, int formals_start_pos, int formals_end_pos)
const UnoptimizedCompileFlags & flags() const
AstValueFactory * ast_value_factory() const
void ParseFunctionBody(StatementListT *body, IdentifierT function_name, int pos, const FormalParametersT &parameters, FunctionKind kind, FunctionSyntaxKind function_syntax_kind, FunctionBodyType body_type)
DeclarationScope * NewVarblockScope() const
ModuleScope * NewModuleScope(DeclarationScope *parent) const
std::vector< void * > * pointer_buffer()
typename v8::internal::ParameterDeclarationParsingScope< Types > ParameterDeclarationParsingScope
static PreParserBlock Default()
Definition preparser.h:448
static PreParserExpression Default()
Definition preparser.h:92
void ValidateStrictMode(PreParser *preparser) const
Definition preparser.cc:97
void ValidateDuplicate(PreParser *preparser) const
Definition preparser.cc:93
static PreParserIdentifier Eval()
Definition preparser.h:38
static PreParserIdentifier Arguments()
Definition preparser.h:41
static PreParserIdentifier Async()
Definition preparser.h:47
const AstRawString * string_
Definition preparser.h:76
static PreParserIdentifier PrivateName()
Definition preparser.h:50
static PreParserIdentifier Default()
Definition preparser.h:32
static PreParserIdentifier Constructor()
Definition preparser.h:44
void LogFunction(int end, int num_parameters, int function_length, int num_inner_infos)
V8_INLINE void ReportVarRedeclarationIn(const AstRawString *name, Scope *scope)
Definition preparser.h:1049
V8_INLINE void DeclareFunctionNameVar(const AstRawString *function_name, FunctionSyntaxKind function_syntax_kind, DeclarationScope *function_scope)
Definition preparser.h:1074
PreParserIdentifier GetIdentifier() const
Definition preparser.cc:58
PreParserBlock BuildParameterInitializationBlock(const PreParserFormalParameters &parameters)
Definition preparser.cc:372
bool IdentifierEquals(const PreParserIdentifier &identifier, const AstRawString *other)
Definition preparser.cc:396
V8_EXPORT_PRIVATE PreParseResult PreParseProgram()
Definition preparser.cc:67
PreParseResult PreParseFunction(const AstRawString *function_name, FunctionKind kind, FunctionSyntaxKind function_syntax_kind, DeclarationScope *function_scope, int *use_counts, ProducedPreparseData **produced_preparser_scope_data)
Definition preparser.cc:101
PreparseDataBuilder * preparse_data_builder_
Definition preparser.h:1628
V8_INLINE void ReportUnidentifiableError()
Definition preparser.h:1389
V8_INLINE void SetLanguageMode(Scope *scope, LanguageMode mode)
Definition preparser.h:988
PreParserLogger log_
Definition preparser.h:1626
Expression ParseFunctionLiteral(Identifier 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)
Definition preparser.cc:259
void ParseStatementListAndLogFunction(PreParserFormalParameters *formals)
Definition preparser.cc:359
PendingCompilationErrorHandler * pending_error_handler()
Definition preparser.h:945
void SetSkippableFunction(DeclarationScope *function_scope, int function_length, int num_inner_functions)
void Start(DeclarationScope *function_scope)
PreparseDataBuilder * parent() const
static ProducedPreparseData * For(PreparseDataBuilder *builder, Zone *zone)
const AstRawString * CurrentSymbol(AstValueFactory *ast_value_factory) const
Definition scanner.cc:1110
const Location & location() const
Definition scanner.h:298
const Location & peek_location() const
Definition scanner.h:328
void SetLanguageMode(LanguageMode language_mode)
Definition scopes.h:288
void set_end_position(int statement_pos)
Definition scopes.h:343
ScopeType scope_type() const
Definition scopes.h:474
const AstRawString * FindVariableDeclaredIn(Scope *scope, VariableMode mode_limit)
Definition scopes.cc:1331
void set_start_position(int statement_pos)
Definition scopes.h:339
Scope * FinalizeBlockScope()
Definition scopes.cc:847
int end_position() const
Definition scopes.h:342
LanguageMode language_mode() const
Definition scopes.h:477
int start_position() const
Definition scopes.h:338
void FunctionEvent(const char *reason, int script_id, double time_delta_ms, int start_position, int end_position, Tagged< String > function_name)
Definition log.cc:1830
ZoneVector< RpoNumber > & result
bool IsArrowFunction(FunctionKind kind)
bool is_sloppy(LanguageMode language_mode)
Definition globals.h:773
constexpr int kNoSourcePosition
Definition globals.h:850
bool IsConciseMethod(FunctionKind kind)
bool is_strict(LanguageMode language_mode)
Definition globals.h:777
V8_EXPORT_PRIVATE FlagValues v8_flags
#define RCS_SCOPE(...)
#define DCHECK_NULL(val)
Definition logging.h:491
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
Symbol identifier
#define V8_UNLIKELY(condition)
Definition v8config.h:660