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/list.h"
13 #include "src/parsing/duplicate-finder.h"
14 #include "src/parsing/parser-base.h"
15 #include "src/parsing/preparse-data-format.h"
16 #include "src/parsing/preparse-data.h"
17 #include "src/parsing/preparser.h"
18 #include "src/unicode.h"
19 #include "src/utils.h"
20
21 namespace v8 {
22 namespace internal {
23
24 // ----------------------------------------------------------------------------
25 // The CHECK_OK macro is a convenient macro to enforce error
26 // handling for functions that may fail (by returning !*ok).
27 //
28 // CAUTION: This macro appends extra statements after a call,
29 // thus it must never be used where only a single statement
30 // is correct (e.g. an if statement branch w/o braces)!
31
32 #define CHECK_OK_VALUE(x) ok); \
33 if (!*ok) return x; \
34 ((void)0
35 #define DUMMY ) // to make indentation work
36 #undef DUMMY
37
38 #define CHECK_OK CHECK_OK_VALUE(Expression::Default())
39 #define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
40
41 namespace {
42
GetSymbolHelper(Scanner * scanner)43 PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
44 switch (scanner->current_token()) {
45 case Token::ENUM:
46 return PreParserIdentifier::Enum();
47 case Token::AWAIT:
48 return PreParserIdentifier::Await();
49 case Token::FUTURE_STRICT_RESERVED_WORD:
50 return PreParserIdentifier::FutureStrictReserved();
51 case Token::LET:
52 return PreParserIdentifier::Let();
53 case Token::STATIC:
54 return PreParserIdentifier::Static();
55 case Token::YIELD:
56 return PreParserIdentifier::Yield();
57 case Token::ASYNC:
58 return PreParserIdentifier::Async();
59 default:
60 if (scanner->UnescapedLiteralMatches("eval", 4))
61 return PreParserIdentifier::Eval();
62 if (scanner->UnescapedLiteralMatches("arguments", 9))
63 return PreParserIdentifier::Arguments();
64 if (scanner->UnescapedLiteralMatches("undefined", 9))
65 return PreParserIdentifier::Undefined();
66 if (scanner->LiteralMatches("prototype", 9))
67 return PreParserIdentifier::Prototype();
68 if (scanner->LiteralMatches("constructor", 11))
69 return PreParserIdentifier::Constructor();
70 if (scanner->LiteralMatches("name", 4))
71 return PreParserIdentifier::Name();
72 return PreParserIdentifier::Default();
73 }
74 }
75
76 } // unnamed namespace
77
GetSymbol() const78 PreParserIdentifier PreParser::GetSymbol() const {
79 PreParserIdentifier symbol = GetSymbolHelper(scanner());
80 if (track_unresolved_variables_) {
81 const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
82 DCHECK_NOT_NULL(result);
83 symbol.string_ = result;
84 }
85 return symbol;
86 }
87
PreParseFunction(FunctionKind kind,DeclarationScope * function_scope,bool parsing_module,bool is_inner_function,bool may_abort,int * use_counts)88 PreParser::PreParseResult PreParser::PreParseFunction(
89 FunctionKind kind, DeclarationScope* function_scope, bool parsing_module,
90 bool is_inner_function, bool may_abort, int* use_counts) {
91 DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
92 parsing_module_ = parsing_module;
93 use_counts_ = use_counts;
94 DCHECK(!track_unresolved_variables_);
95 track_unresolved_variables_ = is_inner_function;
96 #ifdef DEBUG
97 function_scope->set_is_being_lazily_parsed(true);
98 #endif
99
100 // In the preparser, we use the function literal ids to count how many
101 // FunctionLiterals were encountered. The PreParser doesn't actually persist
102 // FunctionLiterals, so there IDs don't matter.
103 ResetFunctionLiteralId();
104
105 // The caller passes the function_scope which is not yet inserted into the
106 // scope stack. All scopes above the function_scope are ignored by the
107 // PreParser.
108 DCHECK_NULL(function_state_);
109 DCHECK_NULL(scope_);
110 FunctionState function_state(&function_state_, &scope_, function_scope);
111 // This indirection is needed so that we can use the CHECK_OK macros.
112 bool ok_holder = true;
113 bool* ok = &ok_holder;
114
115 PreParserFormalParameters formals(function_scope);
116 bool has_duplicate_parameters = false;
117 DuplicateFinder duplicate_finder;
118 std::unique_ptr<ExpressionClassifier> formals_classifier;
119
120 // Parse non-arrow function parameters. For arrow functions, the parameters
121 // have already been parsed.
122 if (!IsArrowFunction(kind)) {
123 formals_classifier.reset(new ExpressionClassifier(this, &duplicate_finder));
124 // We return kPreParseSuccess in failure cases too - errors are retrieved
125 // separately by Parser::SkipLazyFunctionBody.
126 ParseFormalParameterList(&formals, CHECK_OK_VALUE(kPreParseSuccess));
127 Expect(Token::RPAREN, CHECK_OK_VALUE(kPreParseSuccess));
128 int formals_end_position = scanner()->location().end_pos;
129
130 CheckArityRestrictions(
131 formals.arity, kind, formals.has_rest, function_scope->start_position(),
132 formals_end_position, CHECK_OK_VALUE(kPreParseSuccess));
133 has_duplicate_parameters =
134 !classifier()->is_valid_formal_parameter_list_without_duplicates();
135 }
136
137 Expect(Token::LBRACE, CHECK_OK_VALUE(kPreParseSuccess));
138 DeclarationScope* inner_scope = function_scope;
139 LazyParsingResult result;
140
141 if (!formals.is_simple) {
142 inner_scope = NewVarblockScope();
143 inner_scope->set_start_position(scanner()->location().beg_pos);
144 }
145
146 {
147 BlockState block_state(&scope_, inner_scope);
148 result = ParseStatementListAndLogFunction(
149 &formals, has_duplicate_parameters, may_abort, ok);
150 }
151
152 if (!formals.is_simple) {
153 BuildParameterInitializationBlock(formals, ok);
154
155 if (is_sloppy(inner_scope->language_mode())) {
156 inner_scope->HoistSloppyBlockFunctions(nullptr);
157 }
158
159 SetLanguageMode(function_scope, inner_scope->language_mode());
160 inner_scope->set_end_position(scanner()->peek_location().end_pos);
161 inner_scope->FinalizeBlockScope();
162 } else {
163 if (is_sloppy(function_scope->language_mode())) {
164 function_scope->HoistSloppyBlockFunctions(nullptr);
165 }
166 }
167
168 if (!IsArrowFunction(kind) && track_unresolved_variables_) {
169 // Declare arguments after parsing the function since lexical 'arguments'
170 // masks the arguments object. Declare arguments before declaring the
171 // function var since the arguments object masks 'function arguments'.
172 function_scope->DeclareArguments(ast_value_factory());
173 }
174
175 use_counts_ = nullptr;
176 track_unresolved_variables_ = false;
177
178 if (result == kLazyParsingAborted) {
179 return kPreParseAbort;
180 } else if (stack_overflow()) {
181 return kPreParseStackOverflow;
182 } else if (!*ok) {
183 DCHECK(pending_error_handler_->has_pending_error());
184 } else {
185 DCHECK_EQ(Token::RBRACE, scanner()->peek());
186
187 if (!IsArrowFunction(kind)) {
188 // Validate parameter names. We can do this only after parsing the
189 // function, since the function can declare itself strict.
190 const bool allow_duplicate_parameters =
191 is_sloppy(function_scope->language_mode()) && formals.is_simple &&
192 !IsConciseMethod(kind);
193 ValidateFormalParameters(function_scope->language_mode(),
194 allow_duplicate_parameters,
195 CHECK_OK_VALUE(kPreParseSuccess));
196 }
197
198 if (is_strict(function_scope->language_mode())) {
199 int end_pos = scanner()->location().end_pos;
200 CheckStrictOctalLiteral(function_scope->start_position(), end_pos, ok);
201 }
202 }
203 return kPreParseSuccess;
204 }
205
206
207 // Preparsing checks a JavaScript program and emits preparse-data that helps
208 // a later parsing to be faster.
209 // See preparser-data.h for the data.
210
211 // The PreParser checks that the syntax follows the grammar for JavaScript,
212 // and collects some information about the program along the way.
213 // The grammar check is only performed in order to understand the program
214 // sufficiently to deduce some information about it, that can be used
215 // to speed up later parsing. Finding errors is not the goal of pre-parsing,
216 // rather it is to speed up properly written and correct programs.
217 // That means that contextual checks (like a label being declared where
218 // it is used) are generally omitted.
219
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,bool * ok)220 PreParser::Expression PreParser::ParseFunctionLiteral(
221 Identifier function_name, Scanner::Location function_name_location,
222 FunctionNameValidity function_name_validity, FunctionKind kind,
223 int function_token_pos, FunctionLiteral::FunctionType function_type,
224 LanguageMode language_mode, bool* ok) {
225 // Function ::
226 // '(' FormalParameterList? ')' '{' FunctionBody '}'
227 const RuntimeCallStats::CounterId counters[2][2] = {
228 {&RuntimeCallStats::PreParseBackgroundNoVariableResolution,
229 &RuntimeCallStats::PreParseNoVariableResolution},
230 {&RuntimeCallStats::PreParseBackgroundWithVariableResolution,
231 &RuntimeCallStats::PreParseWithVariableResolution}};
232 RuntimeCallTimerScope runtime_timer(
233 runtime_call_stats_,
234 counters[track_unresolved_variables_][parsing_on_main_thread_]);
235
236 DeclarationScope* function_scope = NewFunctionScope(kind);
237 function_scope->SetLanguageMode(language_mode);
238 FunctionState function_state(&function_state_, &scope_, function_scope);
239 DuplicateFinder duplicate_finder;
240 ExpressionClassifier formals_classifier(this, &duplicate_finder);
241 GetNextFunctionLiteralId();
242
243 Expect(Token::LPAREN, CHECK_OK);
244 int start_position = scanner()->location().beg_pos;
245 function_scope->set_start_position(start_position);
246 PreParserFormalParameters formals(function_scope);
247 ParseFormalParameterList(&formals, CHECK_OK);
248 Expect(Token::RPAREN, CHECK_OK);
249 int formals_end_position = scanner()->location().end_pos;
250
251 CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position,
252 formals_end_position, CHECK_OK);
253
254 Expect(Token::LBRACE, CHECK_OK);
255
256 // Parse function body.
257 PreParserStatementList body;
258 int pos = function_token_pos == kNoSourcePosition ? peek_position()
259 : function_token_pos;
260 ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
261 CHECK_OK);
262
263 // Parsing the body may change the language mode in our scope.
264 language_mode = function_scope->language_mode();
265
266 if (is_sloppy(language_mode)) {
267 function_scope->HoistSloppyBlockFunctions(nullptr);
268 }
269
270 // Validate name and parameter names. We can do this only after parsing the
271 // function, since the function can declare itself strict.
272 CheckFunctionName(language_mode, function_name, function_name_validity,
273 function_name_location, CHECK_OK);
274 const bool allow_duplicate_parameters =
275 is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
276 ValidateFormalParameters(language_mode, allow_duplicate_parameters, CHECK_OK);
277
278 int end_position = scanner()->location().end_pos;
279 if (is_strict(language_mode)) {
280 CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
281 }
282
283 if (FLAG_trace_preparse) {
284 PrintF(" [%s]: %i-%i\n",
285 track_unresolved_variables_ ? "Preparse resolution"
286 : "Preparse no-resolution",
287 function_scope->start_position(), function_scope->end_position());
288 }
289
290 return Expression::Default();
291 }
292
ParseStatementListAndLogFunction(PreParserFormalParameters * formals,bool has_duplicate_parameters,bool may_abort,bool * ok)293 PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
294 PreParserFormalParameters* formals, bool has_duplicate_parameters,
295 bool may_abort, bool* ok) {
296 PreParserStatementList body;
297 LazyParsingResult result = ParseStatementList(
298 body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
299 if (result == kLazyParsingAborted) return result;
300
301 // Position right after terminal '}'.
302 DCHECK_EQ(Token::RBRACE, scanner()->peek());
303 int body_end = scanner()->peek_location().end_pos;
304 DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
305 log_.LogFunction(body_end, formals->num_parameters(),
306 formals->function_length, has_duplicate_parameters,
307 function_state_->expected_property_count(),
308 GetLastFunctionLiteralId());
309 return kLazyParsingComplete;
310 }
311
ExpressionFromIdentifier(PreParserIdentifier name,int start_position,InferName infer)312 PreParserExpression PreParser::ExpressionFromIdentifier(
313 PreParserIdentifier name, int start_position, InferName infer) {
314 VariableProxy* proxy = nullptr;
315 if (track_unresolved_variables_) {
316 AstNodeFactory factory(ast_value_factory());
317 // Setting the Zone is necessary because zone_ might be the temp Zone, and
318 // AstValueFactory doesn't know about it.
319 factory.set_zone(zone());
320 DCHECK_NOT_NULL(name.string_);
321 proxy = scope()->NewUnresolved(&factory, name.string_, start_position,
322 NORMAL_VARIABLE);
323 }
324 return PreParserExpression::FromIdentifier(name, proxy, zone());
325 }
326
DeclareAndInitializeVariables(PreParserStatement block,const DeclarationDescriptor * declaration_descriptor,const DeclarationParsingResult::Declaration * declaration,ZoneList<const AstRawString * > * names,bool * ok)327 void PreParser::DeclareAndInitializeVariables(
328 PreParserStatement block,
329 const DeclarationDescriptor* declaration_descriptor,
330 const DeclarationParsingResult::Declaration* declaration,
331 ZoneList<const AstRawString*>* names, bool* ok) {
332 if (declaration->pattern.variables_ != nullptr) {
333 DCHECK(FLAG_lazy_inner_functions);
334 DCHECK(track_unresolved_variables_);
335 for (auto variable : *(declaration->pattern.variables_)) {
336 declaration_descriptor->scope->RemoveUnresolved(variable);
337 Variable* var = scope()->DeclareVariableName(
338 variable->raw_name(), declaration_descriptor->mode);
339 if (FLAG_preparser_scope_analysis) {
340 MarkLoopVariableAsAssigned(declaration_descriptor->scope, var);
341 // This is only necessary if there is an initializer, but we don't have
342 // that information here. Consequently, the preparser sometimes says
343 // maybe-assigned where the parser (correctly) says never-assigned.
344 }
345 if (names) {
346 names->Add(variable->raw_name(), zone());
347 }
348 }
349 }
350 }
351
352 #undef CHECK_OK
353 #undef CHECK_OK_CUSTOM
354
355
356 } // namespace internal
357 } // namespace v8
358