• 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/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