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