v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
preparser.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include <math.h>
29 
30 #include "../include/v8stdint.h"
31 
32 #include "allocation.h"
33 #include "checks.h"
34 #include "conversions.h"
35 #include "conversions-inl.h"
36 #include "globals.h"
37 #include "hashmap.h"
38 #include "list.h"
39 #include "preparse-data-format.h"
40 #include "preparse-data.h"
41 #include "preparser.h"
42 #include "unicode.h"
43 #include "utils.h"
44 
45 namespace v8 {
46 
47 #ifdef _MSC_VER
48 // Usually defined in math.h, but not in MSVC.
49 // Abstracted to work
50 int isfinite(double value);
51 #endif
52 
53 namespace preparser {
54 
57  log_ = log;
58  // Lazy functions always have trivial outer scopes (no with/catch scopes).
59  Scope top_scope(&scope_, kTopLevelScope);
60  set_language_mode(mode);
61  Scope function_scope(&scope_, kFunctionScope);
62  ASSERT_EQ(i::Token::LBRACE, scanner_->current_token());
63  bool ok = true;
64  int start_position = scanner_->peek_location().beg_pos;
65  ParseLazyFunctionLiteralBody(&ok);
66  if (stack_overflow_) return kPreParseStackOverflow;
67  if (!ok) {
68  ReportUnexpectedToken(scanner_->current_token());
69  } else {
70  ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
71  if (!is_classic_mode()) {
72  int end_pos = scanner_->location().end_pos;
73  CheckOctalLiteral(start_position, end_pos, &ok);
74  if (ok) {
75  CheckDelayedStrictModeViolation(start_position, end_pos, &ok);
76  }
77  }
78  }
79  return kPreParseSuccess;
80 }
81 
82 
83 // Preparsing checks a JavaScript program and emits preparse-data that helps
84 // a later parsing to be faster.
85 // See preparser-data.h for the data.
86 
87 // The PreParser checks that the syntax follows the grammar for JavaScript,
88 // and collects some information about the program along the way.
89 // The grammar check is only performed in order to understand the program
90 // sufficiently to deduce some information about it, that can be used
91 // to speed up later parsing. Finding errors is not the goal of pre-parsing,
92 // rather it is to speed up properly written and correct programs.
93 // That means that contextual checks (like a label being declared where
94 // it is used) are generally omitted.
95 
96 void PreParser::ReportUnexpectedToken(i::Token::Value token) {
97  // We don't report stack overflows here, to avoid increasing the
98  // stack depth even further. Instead we report it after parsing is
99  // over, in ParseProgram.
100  if (token == i::Token::ILLEGAL && stack_overflow_) {
101  return;
102  }
103  i::Scanner::Location source_location = scanner_->location();
104 
105  // Four of the tokens are treated specially
106  switch (token) {
107  case i::Token::EOS:
108  return ReportMessageAt(source_location, "unexpected_eos", NULL);
109  case i::Token::NUMBER:
110  return ReportMessageAt(source_location, "unexpected_token_number", NULL);
111  case i::Token::STRING:
112  return ReportMessageAt(source_location, "unexpected_token_string", NULL);
113  case i::Token::IDENTIFIER:
114  return ReportMessageAt(source_location,
115  "unexpected_token_identifier", NULL);
116  case i::Token::FUTURE_RESERVED_WORD:
117  return ReportMessageAt(source_location, "unexpected_reserved", NULL);
118  case i::Token::FUTURE_STRICT_RESERVED_WORD:
119  return ReportMessageAt(source_location,
120  "unexpected_strict_reserved", NULL);
121  default:
122  const char* name = i::Token::String(token);
123  ReportMessageAt(source_location, "unexpected_token", name);
124  }
125 }
126 
127 
128 // Checks whether octal literal last seen is between beg_pos and end_pos.
129 // If so, reports an error.
130 void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
131  i::Scanner::Location octal = scanner_->octal_position();
132  if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
133  ReportMessageAt(octal, "strict_octal_literal", NULL);
134  scanner_->clear_octal_position();
135  *ok = false;
136  }
137 }
138 
139 
140 #define CHECK_OK ok); \
141  if (!*ok) return kUnknownSourceElements; \
142  ((void)0
143 #define DUMMY ) // to make indentation work
144 #undef DUMMY
145 
146 
147 PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
148  // (Ecma 262 5th Edition, clause 14):
149  // SourceElement:
150  // Statement
151  // FunctionDeclaration
152  //
153  // In harmony mode we allow additionally the following productions
154  // SourceElement:
155  // LetDeclaration
156  // ConstDeclaration
157 
158  switch (peek()) {
159  case i::Token::FUNCTION:
160  return ParseFunctionDeclaration(ok);
161  case i::Token::LET:
162  case i::Token::CONST:
163  return ParseVariableStatement(kSourceElement, ok);
164  default:
165  return ParseStatement(ok);
166  }
167 }
168 
169 
170 PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
171  bool* ok) {
172  // SourceElements ::
173  // (Statement)* <end_token>
174 
175  bool allow_directive_prologue = true;
176  while (peek() != end_token) {
177  Statement statement = ParseSourceElement(CHECK_OK);
178  if (allow_directive_prologue) {
179  if (statement.IsUseStrictLiteral()) {
180  set_language_mode(harmony_scoping_ ?
182  } else if (!statement.IsStringLiteral()) {
183  allow_directive_prologue = false;
184  }
185  }
186  }
187  return kUnknownSourceElements;
188 }
189 
190 
191 #undef CHECK_OK
192 #define CHECK_OK ok); \
193  if (!*ok) return Statement::Default(); \
194  ((void)0
195 #define DUMMY ) // to make indentation work
196 #undef DUMMY
197 
198 
199 PreParser::Statement PreParser::ParseStatement(bool* ok) {
200  // Statement ::
201  // Block
202  // VariableStatement
203  // EmptyStatement
204  // ExpressionStatement
205  // IfStatement
206  // IterationStatement
207  // ContinueStatement
208  // BreakStatement
209  // ReturnStatement
210  // WithStatement
211  // LabelledStatement
212  // SwitchStatement
213  // ThrowStatement
214  // TryStatement
215  // DebuggerStatement
216 
217  // Note: Since labels can only be used by 'break' and 'continue'
218  // statements, which themselves are only valid within blocks,
219  // iterations or 'switch' statements (i.e., BreakableStatements),
220  // labels can be simply ignored in all other cases; except for
221  // trivial labeled break statements 'label: break label' which is
222  // parsed into an empty statement.
223 
224  // Keep the source position of the statement
225  switch (peek()) {
226  case i::Token::LBRACE:
227  return ParseBlock(ok);
228 
229  case i::Token::CONST:
230  case i::Token::LET:
231  case i::Token::VAR:
232  return ParseVariableStatement(kStatement, ok);
233 
234  case i::Token::SEMICOLON:
235  Next();
236  return Statement::Default();
237 
238  case i::Token::IF:
239  return ParseIfStatement(ok);
240 
241  case i::Token::DO:
242  return ParseDoWhileStatement(ok);
243 
244  case i::Token::WHILE:
245  return ParseWhileStatement(ok);
246 
247  case i::Token::FOR:
248  return ParseForStatement(ok);
249 
250  case i::Token::CONTINUE:
251  return ParseContinueStatement(ok);
252 
253  case i::Token::BREAK:
254  return ParseBreakStatement(ok);
255 
256  case i::Token::RETURN:
257  return ParseReturnStatement(ok);
258 
259  case i::Token::WITH:
260  return ParseWithStatement(ok);
261 
262  case i::Token::SWITCH:
263  return ParseSwitchStatement(ok);
264 
265  case i::Token::THROW:
266  return ParseThrowStatement(ok);
267 
268  case i::Token::TRY:
269  return ParseTryStatement(ok);
270 
271  case i::Token::FUNCTION: {
272  i::Scanner::Location start_location = scanner_->peek_location();
273  Statement statement = ParseFunctionDeclaration(CHECK_OK);
274  i::Scanner::Location end_location = scanner_->location();
275  if (!is_classic_mode()) {
276  ReportMessageAt(start_location.beg_pos, end_location.end_pos,
277  "strict_function", NULL);
278  *ok = false;
279  return Statement::Default();
280  } else {
281  return statement;
282  }
283  }
284 
285  case i::Token::DEBUGGER:
286  return ParseDebuggerStatement(ok);
287 
288  default:
289  return ParseExpressionOrLabelledStatement(ok);
290  }
291 }
292 
293 
294 PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
295  // FunctionDeclaration ::
296  // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
297  Expect(i::Token::FUNCTION, CHECK_OK);
298 
299  Identifier identifier = ParseIdentifier(CHECK_OK);
300  i::Scanner::Location location = scanner_->location();
301 
302  Expression function_value = ParseFunctionLiteral(CHECK_OK);
303 
304  if (function_value.IsStrictFunction() &&
305  !identifier.IsValidStrictVariable()) {
306  // Strict mode violation, using either reserved word or eval/arguments
307  // as name of strict function.
308  const char* type = "strict_function_name";
309  if (identifier.IsFutureStrictReserved()) {
310  type = "strict_reserved_word";
311  }
312  ReportMessageAt(location, type, NULL);
313  *ok = false;
314  }
315  return Statement::FunctionDeclaration();
316 }
317 
318 
319 PreParser::Statement PreParser::ParseBlock(bool* ok) {
320  // Block ::
321  // '{' Statement* '}'
322 
323  // Note that a Block does not introduce a new execution scope!
324  // (ECMA-262, 3rd, 12.2)
325  //
326  Expect(i::Token::LBRACE, CHECK_OK);
327  while (peek() != i::Token::RBRACE) {
328  if (is_extended_mode()) {
329  ParseSourceElement(CHECK_OK);
330  } else {
331  ParseStatement(CHECK_OK);
332  }
333  }
334  Expect(i::Token::RBRACE, ok);
335  return Statement::Default();
336 }
337 
338 
339 PreParser::Statement PreParser::ParseVariableStatement(
340  VariableDeclarationContext var_context,
341  bool* ok) {
342  // VariableStatement ::
343  // VariableDeclarations ';'
344 
345  Statement result = ParseVariableDeclarations(var_context,
346  NULL,
347  NULL,
348  CHECK_OK);
349  ExpectSemicolon(CHECK_OK);
350  return result;
351 }
352 
353 
354 // If the variable declaration declares exactly one non-const
355 // variable, then *var is set to that variable. In all other cases,
356 // *var is untouched; in particular, it is the caller's responsibility
357 // to initialize it properly. This mechanism is also used for the parsing
358 // of 'for-in' loops.
359 PreParser::Statement PreParser::ParseVariableDeclarations(
360  VariableDeclarationContext var_context,
361  VariableDeclarationProperties* decl_props,
362  int* num_decl,
363  bool* ok) {
364  // VariableDeclarations ::
365  // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
366  //
367  // The ES6 Draft Rev3 specifies the following grammar for const declarations
368  //
369  // ConstDeclaration ::
370  // const ConstBinding (',' ConstBinding)* ';'
371  // ConstBinding ::
372  // Identifier '=' AssignmentExpression
373  //
374  // TODO(ES6):
375  // ConstBinding ::
376  // BindingPattern '=' AssignmentExpression
377  bool require_initializer = false;
378  if (peek() == i::Token::VAR) {
379  Consume(i::Token::VAR);
380  } else if (peek() == i::Token::CONST) {
381  // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
382  //
383  // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
384  //
385  // * It is a Syntax Error if the code that matches this production is not
386  // contained in extended code.
387  //
388  // However disallowing const in classic mode will break compatibility with
389  // existing pages. Therefore we keep allowing const with the old
390  // non-harmony semantics in classic mode.
391  Consume(i::Token::CONST);
392  switch (language_mode()) {
393  case i::CLASSIC_MODE:
394  break;
395  case i::STRICT_MODE: {
396  i::Scanner::Location location = scanner_->peek_location();
397  ReportMessageAt(location, "strict_const", NULL);
398  *ok = false;
399  return Statement::Default();
400  }
401  case i::EXTENDED_MODE:
402  if (var_context != kSourceElement &&
403  var_context != kForStatement) {
404  i::Scanner::Location location = scanner_->peek_location();
405  ReportMessageAt(location.beg_pos, location.end_pos,
406  "unprotected_const", NULL);
407  *ok = false;
408  return Statement::Default();
409  }
410  require_initializer = true;
411  break;
412  }
413  } else if (peek() == i::Token::LET) {
414  // ES6 Draft Rev4 section 12.2.1:
415  //
416  // LetDeclaration : let LetBindingList ;
417  //
418  // * It is a Syntax Error if the code that matches this production is not
419  // contained in extended code.
420  if (!is_extended_mode()) {
421  i::Scanner::Location location = scanner_->peek_location();
422  ReportMessageAt(location.beg_pos, location.end_pos,
423  "illegal_let", NULL);
424  *ok = false;
425  return Statement::Default();
426  }
427  Consume(i::Token::LET);
428  if (var_context != kSourceElement &&
429  var_context != kForStatement) {
430  i::Scanner::Location location = scanner_->peek_location();
431  ReportMessageAt(location.beg_pos, location.end_pos,
432  "unprotected_let", NULL);
433  *ok = false;
434  return Statement::Default();
435  }
436  } else {
437  *ok = false;
438  return Statement::Default();
439  }
440 
441  // The scope of a var/const declared variable anywhere inside a function
442  // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope
443  // of a let declared variable is the scope of the immediately enclosing
444  // block.
445  int nvars = 0; // the number of variables declared
446  do {
447  // Parse variable name.
448  if (nvars > 0) Consume(i::Token::COMMA);
449  Identifier identifier = ParseIdentifier(CHECK_OK);
450  if (!is_classic_mode() && !identifier.IsValidStrictVariable()) {
451  StrictModeIdentifierViolation(scanner_->location(),
452  "strict_var_name",
453  identifier,
454  ok);
455  return Statement::Default();
456  }
457  nvars++;
458  if (peek() == i::Token::ASSIGN || require_initializer) {
459  Expect(i::Token::ASSIGN, CHECK_OK);
460  ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
461  if (decl_props != NULL) *decl_props = kHasInitializers;
462  }
463  } while (peek() == i::Token::COMMA);
464 
465  if (num_decl != NULL) *num_decl = nvars;
466  return Statement::Default();
467 }
468 
469 
470 PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
471  // ExpressionStatement | LabelledStatement ::
472  // Expression ';'
473  // Identifier ':' Statement
474 
475  Expression expr = ParseExpression(true, CHECK_OK);
476  if (expr.IsRawIdentifier()) {
477  ASSERT(!expr.AsIdentifier().IsFutureReserved());
478  ASSERT(is_classic_mode() || !expr.AsIdentifier().IsFutureStrictReserved());
479  if (peek() == i::Token::COLON) {
480  Consume(i::Token::COLON);
481  return ParseStatement(ok);
482  }
483  // Preparsing is disabled for extensions (because the extension details
484  // aren't passed to lazily compiled functions), so we don't
485  // accept "native function" in the preparser.
486  }
487  // Parsed expression statement.
488  ExpectSemicolon(CHECK_OK);
489  return Statement::ExpressionStatement(expr);
490 }
491 
492 
493 PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
494  // IfStatement ::
495  // 'if' '(' Expression ')' Statement ('else' Statement)?
496 
497  Expect(i::Token::IF, CHECK_OK);
498  Expect(i::Token::LPAREN, CHECK_OK);
499  ParseExpression(true, CHECK_OK);
500  Expect(i::Token::RPAREN, CHECK_OK);
501  ParseStatement(CHECK_OK);
502  if (peek() == i::Token::ELSE) {
503  Next();
504  ParseStatement(CHECK_OK);
505  }
506  return Statement::Default();
507 }
508 
509 
510 PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
511  // ContinueStatement ::
512  // 'continue' [no line terminator] Identifier? ';'
513 
514  Expect(i::Token::CONTINUE, CHECK_OK);
515  i::Token::Value tok = peek();
516  if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
517  tok != i::Token::SEMICOLON &&
518  tok != i::Token::RBRACE &&
519  tok != i::Token::EOS) {
520  ParseIdentifier(CHECK_OK);
521  }
522  ExpectSemicolon(CHECK_OK);
523  return Statement::Default();
524 }
525 
526 
527 PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
528  // BreakStatement ::
529  // 'break' [no line terminator] Identifier? ';'
530 
531  Expect(i::Token::BREAK, CHECK_OK);
532  i::Token::Value tok = peek();
533  if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
534  tok != i::Token::SEMICOLON &&
535  tok != i::Token::RBRACE &&
536  tok != i::Token::EOS) {
537  ParseIdentifier(CHECK_OK);
538  }
539  ExpectSemicolon(CHECK_OK);
540  return Statement::Default();
541 }
542 
543 
544 PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
545  // ReturnStatement ::
546  // 'return' [no line terminator] Expression? ';'
547 
548  // Consume the return token. It is necessary to do the before
549  // reporting any errors on it, because of the way errors are
550  // reported (underlining).
551  Expect(i::Token::RETURN, CHECK_OK);
552 
553  // An ECMAScript program is considered syntactically incorrect if it
554  // contains a return statement that is not within the body of a
555  // function. See ECMA-262, section 12.9, page 67.
556  // This is not handled during preparsing.
557 
558  i::Token::Value tok = peek();
559  if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
560  tok != i::Token::SEMICOLON &&
561  tok != i::Token::RBRACE &&
562  tok != i::Token::EOS) {
563  ParseExpression(true, CHECK_OK);
564  }
565  ExpectSemicolon(CHECK_OK);
566  return Statement::Default();
567 }
568 
569 
570 PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
571  // WithStatement ::
572  // 'with' '(' Expression ')' Statement
573  Expect(i::Token::WITH, CHECK_OK);
574  if (!is_classic_mode()) {
575  i::Scanner::Location location = scanner_->location();
576  ReportMessageAt(location, "strict_mode_with", NULL);
577  *ok = false;
578  return Statement::Default();
579  }
580  Expect(i::Token::LPAREN, CHECK_OK);
581  ParseExpression(true, CHECK_OK);
582  Expect(i::Token::RPAREN, CHECK_OK);
583 
584  Scope::InsideWith iw(scope_);
585  ParseStatement(CHECK_OK);
586  return Statement::Default();
587 }
588 
589 
590 PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
591  // SwitchStatement ::
592  // 'switch' '(' Expression ')' '{' CaseClause* '}'
593 
594  Expect(i::Token::SWITCH, CHECK_OK);
595  Expect(i::Token::LPAREN, CHECK_OK);
596  ParseExpression(true, CHECK_OK);
597  Expect(i::Token::RPAREN, CHECK_OK);
598 
599  Expect(i::Token::LBRACE, CHECK_OK);
600  i::Token::Value token = peek();
601  while (token != i::Token::RBRACE) {
602  if (token == i::Token::CASE) {
603  Expect(i::Token::CASE, CHECK_OK);
604  ParseExpression(true, CHECK_OK);
605  Expect(i::Token::COLON, CHECK_OK);
606  } else if (token == i::Token::DEFAULT) {
607  Expect(i::Token::DEFAULT, CHECK_OK);
608  Expect(i::Token::COLON, CHECK_OK);
609  } else {
610  ParseStatement(CHECK_OK);
611  }
612  token = peek();
613  }
614  Expect(i::Token::RBRACE, ok);
615  return Statement::Default();
616 }
617 
618 
619 PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
620  // DoStatement ::
621  // 'do' Statement 'while' '(' Expression ')' ';'
622 
623  Expect(i::Token::DO, CHECK_OK);
624  ParseStatement(CHECK_OK);
625  Expect(i::Token::WHILE, CHECK_OK);
626  Expect(i::Token::LPAREN, CHECK_OK);
627  ParseExpression(true, CHECK_OK);
628  Expect(i::Token::RPAREN, ok);
629  if (peek() == i::Token::SEMICOLON) Consume(i::Token::SEMICOLON);
630  return Statement::Default();
631 }
632 
633 
634 PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
635  // WhileStatement ::
636  // 'while' '(' Expression ')' Statement
637 
638  Expect(i::Token::WHILE, CHECK_OK);
639  Expect(i::Token::LPAREN, CHECK_OK);
640  ParseExpression(true, CHECK_OK);
641  Expect(i::Token::RPAREN, CHECK_OK);
642  ParseStatement(ok);
643  return Statement::Default();
644 }
645 
646 
647 PreParser::Statement PreParser::ParseForStatement(bool* ok) {
648  // ForStatement ::
649  // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
650 
651  Expect(i::Token::FOR, CHECK_OK);
652  Expect(i::Token::LPAREN, CHECK_OK);
653  if (peek() != i::Token::SEMICOLON) {
654  if (peek() == i::Token::VAR || peek() == i::Token::CONST ||
655  peek() == i::Token::LET) {
656  bool is_let = peek() == i::Token::LET;
657  int decl_count;
658  VariableDeclarationProperties decl_props = kHasNoInitializers;
659  ParseVariableDeclarations(
660  kForStatement, &decl_props, &decl_count, CHECK_OK);
661  bool accept_IN = decl_count == 1 &&
662  !(is_let && decl_props == kHasInitializers);
663  if (peek() == i::Token::IN && accept_IN) {
664  Expect(i::Token::IN, CHECK_OK);
665  ParseExpression(true, CHECK_OK);
666  Expect(i::Token::RPAREN, CHECK_OK);
667 
668  ParseStatement(CHECK_OK);
669  return Statement::Default();
670  }
671  } else {
672  ParseExpression(false, CHECK_OK);
673  if (peek() == i::Token::IN) {
674  Expect(i::Token::IN, CHECK_OK);
675  ParseExpression(true, CHECK_OK);
676  Expect(i::Token::RPAREN, CHECK_OK);
677 
678  ParseStatement(CHECK_OK);
679  return Statement::Default();
680  }
681  }
682  }
683 
684  // Parsed initializer at this point.
685  Expect(i::Token::SEMICOLON, CHECK_OK);
686 
687  if (peek() != i::Token::SEMICOLON) {
688  ParseExpression(true, CHECK_OK);
689  }
690  Expect(i::Token::SEMICOLON, CHECK_OK);
691 
692  if (peek() != i::Token::RPAREN) {
693  ParseExpression(true, CHECK_OK);
694  }
695  Expect(i::Token::RPAREN, CHECK_OK);
696 
697  ParseStatement(ok);
698  return Statement::Default();
699 }
700 
701 
702 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
703  // ThrowStatement ::
704  // 'throw' [no line terminator] Expression ';'
705 
706  Expect(i::Token::THROW, CHECK_OK);
707  if (scanner_->HasAnyLineTerminatorBeforeNext()) {
708  i::Scanner::Location pos = scanner_->location();
709  ReportMessageAt(pos, "newline_after_throw", NULL);
710  *ok = false;
711  return Statement::Default();
712  }
713  ParseExpression(true, CHECK_OK);
714  ExpectSemicolon(ok);
715  return Statement::Default();
716 }
717 
718 
719 PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
720  // TryStatement ::
721  // 'try' Block Catch
722  // 'try' Block Finally
723  // 'try' Block Catch Finally
724  //
725  // Catch ::
726  // 'catch' '(' Identifier ')' Block
727  //
728  // Finally ::
729  // 'finally' Block
730 
731  // In preparsing, allow any number of catch/finally blocks, including zero
732  // of both.
733 
734  Expect(i::Token::TRY, CHECK_OK);
735 
736  ParseBlock(CHECK_OK);
737 
738  bool catch_or_finally_seen = false;
739  if (peek() == i::Token::CATCH) {
740  Consume(i::Token::CATCH);
741  Expect(i::Token::LPAREN, CHECK_OK);
742  Identifier id = ParseIdentifier(CHECK_OK);
743  if (!is_classic_mode() && !id.IsValidStrictVariable()) {
744  StrictModeIdentifierViolation(scanner_->location(),
745  "strict_catch_variable",
746  id,
747  ok);
748  return Statement::Default();
749  }
750  Expect(i::Token::RPAREN, CHECK_OK);
751  { Scope::InsideWith iw(scope_);
752  ParseBlock(CHECK_OK);
753  }
754  catch_or_finally_seen = true;
755  }
756  if (peek() == i::Token::FINALLY) {
757  Consume(i::Token::FINALLY);
758  ParseBlock(CHECK_OK);
759  catch_or_finally_seen = true;
760  }
761  if (!catch_or_finally_seen) {
762  *ok = false;
763  }
764  return Statement::Default();
765 }
766 
767 
768 PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
769  // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
770  // contexts this is used as a statement which invokes the debugger as if a
771  // break point is present.
772  // DebuggerStatement ::
773  // 'debugger' ';'
774 
775  Expect(i::Token::DEBUGGER, CHECK_OK);
776  ExpectSemicolon(ok);
777  return Statement::Default();
778 }
779 
780 
781 #undef CHECK_OK
782 #define CHECK_OK ok); \
783  if (!*ok) return Expression::Default(); \
784  ((void)0
785 #define DUMMY ) // to make indentation work
786 #undef DUMMY
787 
788 
789 // Precedence = 1
790 PreParser::Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
791  // Expression ::
792  // AssignmentExpression
793  // Expression ',' AssignmentExpression
794 
795  Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
796  while (peek() == i::Token::COMMA) {
797  Expect(i::Token::COMMA, CHECK_OK);
798  ParseAssignmentExpression(accept_IN, CHECK_OK);
799  result = Expression::Default();
800  }
801  return result;
802 }
803 
804 
805 // Precedence = 2
806 PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
807  bool* ok) {
808  // AssignmentExpression ::
809  // ConditionalExpression
810  // LeftHandSideExpression AssignmentOperator AssignmentExpression
811 
812  i::Scanner::Location before = scanner_->peek_location();
813  Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
814 
815  if (!i::Token::IsAssignmentOp(peek())) {
816  // Parsed conditional expression only (no assignment).
817  return expression;
818  }
819 
820  if (!is_classic_mode() &&
821  expression.IsIdentifier() &&
822  expression.AsIdentifier().IsEvalOrArguments()) {
823  i::Scanner::Location after = scanner_->location();
824  ReportMessageAt(before.beg_pos, after.end_pos,
825  "strict_lhs_assignment", NULL);
826  *ok = false;
827  return Expression::Default();
828  }
829 
830  i::Token::Value op = Next(); // Get assignment operator.
831  ParseAssignmentExpression(accept_IN, CHECK_OK);
832 
833  if ((op == i::Token::ASSIGN) && expression.IsThisProperty()) {
834  scope_->AddProperty();
835  }
836 
837  return Expression::Default();
838 }
839 
840 
841 // Precedence = 3
842 PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN,
843  bool* ok) {
844  // ConditionalExpression ::
845  // LogicalOrExpression
846  // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
847 
848  // We start using the binary expression parser for prec >= 4 only!
849  Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
850  if (peek() != i::Token::CONDITIONAL) return expression;
851  Consume(i::Token::CONDITIONAL);
852  // In parsing the first assignment expression in conditional
853  // expressions we always accept the 'in' keyword; see ECMA-262,
854  // section 11.12, page 58.
855  ParseAssignmentExpression(true, CHECK_OK);
856  Expect(i::Token::COLON, CHECK_OK);
857  ParseAssignmentExpression(accept_IN, CHECK_OK);
858  return Expression::Default();
859 }
860 
861 
862 int PreParser::Precedence(i::Token::Value tok, bool accept_IN) {
863  if (tok == i::Token::IN && !accept_IN)
864  return 0; // 0 precedence will terminate binary expression parsing
865 
866  return i::Token::Precedence(tok);
867 }
868 
869 
870 // Precedence >= 4
871 PreParser::Expression PreParser::ParseBinaryExpression(int prec,
872  bool accept_IN,
873  bool* ok) {
874  Expression result = ParseUnaryExpression(CHECK_OK);
875  for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
876  // prec1 >= 4
877  while (Precedence(peek(), accept_IN) == prec1) {
878  Next();
879  ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
880  result = Expression::Default();
881  }
882  }
883  return result;
884 }
885 
886 
887 PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
888  // UnaryExpression ::
889  // PostfixExpression
890  // 'delete' UnaryExpression
891  // 'void' UnaryExpression
892  // 'typeof' UnaryExpression
893  // '++' UnaryExpression
894  // '--' UnaryExpression
895  // '+' UnaryExpression
896  // '-' UnaryExpression
897  // '~' UnaryExpression
898  // '!' UnaryExpression
899 
900  i::Token::Value op = peek();
901  if (i::Token::IsUnaryOp(op)) {
902  op = Next();
903  ParseUnaryExpression(ok);
904  return Expression::Default();
905  } else if (i::Token::IsCountOp(op)) {
906  op = Next();
907  i::Scanner::Location before = scanner_->peek_location();
908  Expression expression = ParseUnaryExpression(CHECK_OK);
909  if (!is_classic_mode() &&
910  expression.IsIdentifier() &&
911  expression.AsIdentifier().IsEvalOrArguments()) {
912  i::Scanner::Location after = scanner_->location();
913  ReportMessageAt(before.beg_pos, after.end_pos,
914  "strict_lhs_prefix", NULL);
915  *ok = false;
916  }
917  return Expression::Default();
918  } else {
919  return ParsePostfixExpression(ok);
920  }
921 }
922 
923 
924 PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
925  // PostfixExpression ::
926  // LeftHandSideExpression ('++' | '--')?
927 
928  i::Scanner::Location before = scanner_->peek_location();
929  Expression expression = ParseLeftHandSideExpression(CHECK_OK);
930  if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
931  i::Token::IsCountOp(peek())) {
932  if (!is_classic_mode() &&
933  expression.IsIdentifier() &&
934  expression.AsIdentifier().IsEvalOrArguments()) {
935  i::Scanner::Location after = scanner_->location();
936  ReportMessageAt(before.beg_pos, after.end_pos,
937  "strict_lhs_postfix", NULL);
938  *ok = false;
939  return Expression::Default();
940  }
941  Next();
942  return Expression::Default();
943  }
944  return expression;
945 }
946 
947 
948 PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
949  // LeftHandSideExpression ::
950  // (NewExpression | MemberExpression) ...
951 
952  Expression result = Expression::Default();
953  if (peek() == i::Token::NEW) {
954  result = ParseNewExpression(CHECK_OK);
955  } else {
956  result = ParseMemberExpression(CHECK_OK);
957  }
958 
959  while (true) {
960  switch (peek()) {
961  case i::Token::LBRACK: {
962  Consume(i::Token::LBRACK);
963  ParseExpression(true, CHECK_OK);
964  Expect(i::Token::RBRACK, CHECK_OK);
965  if (result.IsThis()) {
966  result = Expression::ThisProperty();
967  } else {
968  result = Expression::Default();
969  }
970  break;
971  }
972 
973  case i::Token::LPAREN: {
974  ParseArguments(CHECK_OK);
975  result = Expression::Default();
976  break;
977  }
978 
979  case i::Token::PERIOD: {
980  Consume(i::Token::PERIOD);
981  ParseIdentifierName(CHECK_OK);
982  if (result.IsThis()) {
983  result = Expression::ThisProperty();
984  } else {
985  result = Expression::Default();
986  }
987  break;
988  }
989 
990  default:
991  return result;
992  }
993  }
994 }
995 
996 
997 PreParser::Expression PreParser::ParseNewExpression(bool* ok) {
998  // NewExpression ::
999  // ('new')+ MemberExpression
1000 
1001  // The grammar for new expressions is pretty warped. The keyword
1002  // 'new' can either be a part of the new expression (where it isn't
1003  // followed by an argument list) or a part of the member expression,
1004  // where it must be followed by an argument list. To accommodate
1005  // this, we parse the 'new' keywords greedily and keep track of how
1006  // many we have parsed. This information is then passed on to the
1007  // member expression parser, which is only allowed to match argument
1008  // lists as long as it has 'new' prefixes left
1009  unsigned new_count = 0;
1010  do {
1011  Consume(i::Token::NEW);
1012  new_count++;
1013  } while (peek() == i::Token::NEW);
1014 
1015  return ParseMemberWithNewPrefixesExpression(new_count, ok);
1016 }
1017 
1018 
1019 PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
1020  return ParseMemberWithNewPrefixesExpression(0, ok);
1021 }
1022 
1023 
1024 PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
1025  unsigned new_count, bool* ok) {
1026  // MemberExpression ::
1027  // (PrimaryExpression | FunctionLiteral)
1028  // ('[' Expression ']' | '.' Identifier | Arguments)*
1029 
1030  // Parse the initial primary or function expression.
1031  Expression result = Expression::Default();
1032  if (peek() == i::Token::FUNCTION) {
1033  Consume(i::Token::FUNCTION);
1034  Identifier identifier = Identifier::Default();
1035  if (peek_any_identifier()) {
1036  identifier = ParseIdentifier(CHECK_OK);
1037  }
1038  result = ParseFunctionLiteral(CHECK_OK);
1039  if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) {
1040  StrictModeIdentifierViolation(scanner_->location(),
1041  "strict_function_name",
1042  identifier,
1043  ok);
1044  return Expression::Default();
1045  }
1046  } else {
1047  result = ParsePrimaryExpression(CHECK_OK);
1048  }
1049 
1050  while (true) {
1051  switch (peek()) {
1052  case i::Token::LBRACK: {
1053  Consume(i::Token::LBRACK);
1054  ParseExpression(true, CHECK_OK);
1055  Expect(i::Token::RBRACK, CHECK_OK);
1056  if (result.IsThis()) {
1057  result = Expression::ThisProperty();
1058  } else {
1059  result = Expression::Default();
1060  }
1061  break;
1062  }
1063  case i::Token::PERIOD: {
1064  Consume(i::Token::PERIOD);
1065  ParseIdentifierName(CHECK_OK);
1066  if (result.IsThis()) {
1067  result = Expression::ThisProperty();
1068  } else {
1069  result = Expression::Default();
1070  }
1071  break;
1072  }
1073  case i::Token::LPAREN: {
1074  if (new_count == 0) return result;
1075  // Consume one of the new prefixes (already parsed).
1076  ParseArguments(CHECK_OK);
1077  new_count--;
1078  result = Expression::Default();
1079  break;
1080  }
1081  default:
1082  return result;
1083  }
1084  }
1085 }
1086 
1087 
1088 PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
1089  // PrimaryExpression ::
1090  // 'this'
1091  // 'null'
1092  // 'true'
1093  // 'false'
1094  // Identifier
1095  // Number
1096  // String
1097  // ArrayLiteral
1098  // ObjectLiteral
1099  // RegExpLiteral
1100  // '(' Expression ')'
1101 
1102  Expression result = Expression::Default();
1103  switch (peek()) {
1104  case i::Token::THIS: {
1105  Next();
1106  result = Expression::This();
1107  break;
1108  }
1109 
1110  case i::Token::FUTURE_RESERVED_WORD: {
1111  Next();
1112  i::Scanner::Location location = scanner_->location();
1113  ReportMessageAt(location.beg_pos, location.end_pos,
1114  "reserved_word", NULL);
1115  *ok = false;
1116  return Expression::Default();
1117  }
1118 
1119  case i::Token::FUTURE_STRICT_RESERVED_WORD:
1120  if (!is_classic_mode()) {
1121  Next();
1122  i::Scanner::Location location = scanner_->location();
1123  ReportMessageAt(location, "strict_reserved_word", NULL);
1124  *ok = false;
1125  return Expression::Default();
1126  }
1127  // FALLTHROUGH
1128  case i::Token::IDENTIFIER: {
1129  Identifier id = ParseIdentifier(CHECK_OK);
1130  result = Expression::FromIdentifier(id);
1131  break;
1132  }
1133 
1134  case i::Token::NULL_LITERAL:
1135  case i::Token::TRUE_LITERAL:
1136  case i::Token::FALSE_LITERAL:
1137  case i::Token::NUMBER: {
1138  Next();
1139  break;
1140  }
1141  case i::Token::STRING: {
1142  Next();
1143  result = GetStringSymbol();
1144  break;
1145  }
1146 
1147  case i::Token::ASSIGN_DIV:
1148  result = ParseRegExpLiteral(true, CHECK_OK);
1149  break;
1150 
1151  case i::Token::DIV:
1152  result = ParseRegExpLiteral(false, CHECK_OK);
1153  break;
1154 
1155  case i::Token::LBRACK:
1156  result = ParseArrayLiteral(CHECK_OK);
1157  break;
1158 
1159  case i::Token::LBRACE:
1160  result = ParseObjectLiteral(CHECK_OK);
1161  break;
1162 
1163  case i::Token::LPAREN:
1164  Consume(i::Token::LPAREN);
1165  parenthesized_function_ = (peek() == i::Token::FUNCTION);
1166  result = ParseExpression(true, CHECK_OK);
1167  Expect(i::Token::RPAREN, CHECK_OK);
1168  result = result.Parenthesize();
1169  break;
1170 
1171  case i::Token::MOD:
1172  result = ParseV8Intrinsic(CHECK_OK);
1173  break;
1174 
1175  default: {
1176  Next();
1177  *ok = false;
1178  return Expression::Default();
1179  }
1180  }
1181 
1182  return result;
1183 }
1184 
1185 
1186 PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
1187  // ArrayLiteral ::
1188  // '[' Expression? (',' Expression?)* ']'
1189  Expect(i::Token::LBRACK, CHECK_OK);
1190  while (peek() != i::Token::RBRACK) {
1191  if (peek() != i::Token::COMMA) {
1192  ParseAssignmentExpression(true, CHECK_OK);
1193  }
1194  if (peek() != i::Token::RBRACK) {
1195  Expect(i::Token::COMMA, CHECK_OK);
1196  }
1197  }
1198  Expect(i::Token::RBRACK, CHECK_OK);
1199 
1200  scope_->NextMaterializedLiteralIndex();
1201  return Expression::Default();
1202 }
1203 
1204 void PreParser::CheckDuplicate(DuplicateFinder* finder,
1205  i::Token::Value property,
1206  int type,
1207  bool* ok) {
1208  int old_type;
1209  if (property == i::Token::NUMBER) {
1210  old_type = finder->AddNumber(scanner_->literal_ascii_string(), type);
1211  } else if (scanner_->is_literal_ascii()) {
1212  old_type = finder->AddAsciiSymbol(scanner_->literal_ascii_string(),
1213  type);
1214  } else {
1215  old_type = finder->AddUtf16Symbol(scanner_->literal_utf16_string(), type);
1216  }
1217  if (HasConflict(old_type, type)) {
1218  if (IsDataDataConflict(old_type, type)) {
1219  // Both are data properties.
1220  if (is_classic_mode()) return;
1221  ReportMessageAt(scanner_->location(),
1222  "strict_duplicate_property", NULL);
1223  } else if (IsDataAccessorConflict(old_type, type)) {
1224  // Both a data and an accessor property with the same name.
1225  ReportMessageAt(scanner_->location(),
1226  "accessor_data_property", NULL);
1227  } else {
1228  ASSERT(IsAccessorAccessorConflict(old_type, type));
1229  // Both accessors of the same type.
1230  ReportMessageAt(scanner_->location(),
1231  "accessor_get_set", NULL);
1232  }
1233  *ok = false;
1234  }
1235 }
1236 
1237 
1238 PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
1239  // ObjectLiteral ::
1240  // '{' (
1241  // ((IdentifierName | String | Number) ':' AssignmentExpression)
1242  // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
1243  // )*[','] '}'
1244 
1245  Expect(i::Token::LBRACE, CHECK_OK);
1246  DuplicateFinder duplicate_finder(scanner_->unicode_cache());
1247  while (peek() != i::Token::RBRACE) {
1248  i::Token::Value next = peek();
1249  switch (next) {
1250  case i::Token::IDENTIFIER:
1251  case i::Token::FUTURE_RESERVED_WORD:
1252  case i::Token::FUTURE_STRICT_RESERVED_WORD: {
1253  bool is_getter = false;
1254  bool is_setter = false;
1255  ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
1256  if ((is_getter || is_setter) && peek() != i::Token::COLON) {
1257  i::Token::Value name = Next();
1258  bool is_keyword = i::Token::IsKeyword(name);
1259  if (name != i::Token::IDENTIFIER &&
1260  name != i::Token::FUTURE_RESERVED_WORD &&
1261  name != i::Token::FUTURE_STRICT_RESERVED_WORD &&
1262  name != i::Token::NUMBER &&
1263  name != i::Token::STRING &&
1264  !is_keyword) {
1265  *ok = false;
1266  return Expression::Default();
1267  }
1268  if (!is_keyword) {
1269  LogSymbol();
1270  }
1271  PropertyType type = is_getter ? kGetterProperty : kSetterProperty;
1272  CheckDuplicate(&duplicate_finder, name, type, CHECK_OK);
1273  ParseFunctionLiteral(CHECK_OK);
1274  if (peek() != i::Token::RBRACE) {
1275  Expect(i::Token::COMMA, CHECK_OK);
1276  }
1277  continue; // restart the while
1278  }
1279  CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1280  break;
1281  }
1282  case i::Token::STRING:
1283  Consume(next);
1284  CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1285  GetStringSymbol();
1286  break;
1287  case i::Token::NUMBER:
1288  Consume(next);
1289  CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1290  break;
1291  default:
1292  if (i::Token::IsKeyword(next)) {
1293  Consume(next);
1294  CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1295  } else {
1296  // Unexpected token.
1297  *ok = false;
1298  return Expression::Default();
1299  }
1300  }
1301 
1302  Expect(i::Token::COLON, CHECK_OK);
1303  ParseAssignmentExpression(true, CHECK_OK);
1304 
1305  // TODO(1240767): Consider allowing trailing comma.
1306  if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
1307  }
1308  Expect(i::Token::RBRACE, CHECK_OK);
1309 
1310  scope_->NextMaterializedLiteralIndex();
1311  return Expression::Default();
1312 }
1313 
1314 
1315 PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
1316  bool* ok) {
1317  if (!scanner_->ScanRegExpPattern(seen_equal)) {
1318  Next();
1319  ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL);
1320  *ok = false;
1321  return Expression::Default();
1322  }
1323 
1324  scope_->NextMaterializedLiteralIndex();
1325 
1326  if (!scanner_->ScanRegExpFlags()) {
1327  Next();
1328  ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL);
1329  *ok = false;
1330  return Expression::Default();
1331  }
1332  Next();
1333  return Expression::Default();
1334 }
1335 
1336 
1337 PreParser::Arguments PreParser::ParseArguments(bool* ok) {
1338  // Arguments ::
1339  // '(' (AssignmentExpression)*[','] ')'
1340 
1341  Expect(i::Token::LPAREN, ok);
1342  if (!*ok) return -1;
1343  bool done = (peek() == i::Token::RPAREN);
1344  int argc = 0;
1345  while (!done) {
1346  ParseAssignmentExpression(true, ok);
1347  if (!*ok) return -1;
1348  argc++;
1349  done = (peek() == i::Token::RPAREN);
1350  if (!done) {
1351  Expect(i::Token::COMMA, ok);
1352  if (!*ok) return -1;
1353  }
1354  }
1355  Expect(i::Token::RPAREN, ok);
1356  return argc;
1357 }
1358 
1359 
1360 PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
1361  // Function ::
1362  // '(' FormalParameterList? ')' '{' FunctionBody '}'
1363 
1364  // Parse function body.
1365  ScopeType outer_scope_type = scope_->type();
1366  bool inside_with = scope_->IsInsideWith();
1367  Scope function_scope(&scope_, kFunctionScope);
1368  // FormalParameterList ::
1369  // '(' (Identifier)*[','] ')'
1370  Expect(i::Token::LPAREN, CHECK_OK);
1371  int start_position = scanner_->location().beg_pos;
1372  bool done = (peek() == i::Token::RPAREN);
1373  DuplicateFinder duplicate_finder(scanner_->unicode_cache());
1374  while (!done) {
1375  Identifier id = ParseIdentifier(CHECK_OK);
1376  if (!id.IsValidStrictVariable()) {
1377  StrictModeIdentifierViolation(scanner_->location(),
1378  "strict_param_name",
1379  id,
1380  CHECK_OK);
1381  }
1382  int prev_value;
1383  if (scanner_->is_literal_ascii()) {
1384  prev_value =
1385  duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1);
1386  } else {
1387  prev_value =
1388  duplicate_finder.AddUtf16Symbol(scanner_->literal_utf16_string(), 1);
1389  }
1390 
1391  if (prev_value != 0) {
1392  SetStrictModeViolation(scanner_->location(),
1393  "strict_param_dupe",
1394  CHECK_OK);
1395  }
1396  done = (peek() == i::Token::RPAREN);
1397  if (!done) {
1398  Expect(i::Token::COMMA, CHECK_OK);
1399  }
1400  }
1401  Expect(i::Token::RPAREN, CHECK_OK);
1402 
1403  // Determine if the function will be lazily compiled.
1404  // Currently only happens to top-level functions.
1405  // Optimistically assume that all top-level functions are lazily compiled.
1406  bool is_lazily_compiled = (outer_scope_type == kTopLevelScope &&
1407  !inside_with && allow_lazy_ &&
1408  !parenthesized_function_);
1409  parenthesized_function_ = false;
1410 
1411  Expect(i::Token::LBRACE, CHECK_OK);
1412  if (is_lazily_compiled) {
1413  ParseLazyFunctionLiteralBody(CHECK_OK);
1414  } else {
1415  ParseSourceElements(i::Token::RBRACE, ok);
1416  }
1417  Expect(i::Token::RBRACE, CHECK_OK);
1418 
1419  if (!is_classic_mode()) {
1420  int end_position = scanner_->location().end_pos;
1421  CheckOctalLiteral(start_position, end_position, CHECK_OK);
1422  CheckDelayedStrictModeViolation(start_position, end_position, CHECK_OK);
1423  return Expression::StrictFunction();
1424  }
1425 
1426  return Expression::Default();
1427 }
1428 
1429 
1430 void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
1431  int body_start = scanner_->location().beg_pos;
1432  log_->PauseRecording();
1433  ParseSourceElements(i::Token::RBRACE, ok);
1434  log_->ResumeRecording();
1435  if (!*ok) return;
1436 
1437  // Position right after terminal '}'.
1438  ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
1439  int body_end = scanner_->peek_location().end_pos;
1440  log_->LogFunction(body_start, body_end,
1441  scope_->materialized_literal_count(),
1442  scope_->expected_properties(),
1443  language_mode());
1444 }
1445 
1446 
1447 PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
1448  // CallRuntime ::
1449  // '%' Identifier Arguments
1450  Expect(i::Token::MOD, CHECK_OK);
1451  if (!allow_natives_syntax_) {
1452  *ok = false;
1453  return Expression::Default();
1454  }
1455  ParseIdentifier(CHECK_OK);
1456  ParseArguments(ok);
1457 
1458  return Expression::Default();
1459 }
1460 
1461 #undef CHECK_OK
1462 
1463 
1464 void PreParser::ExpectSemicolon(bool* ok) {
1465  // Check for automatic semicolon insertion according to
1466  // the rules given in ECMA-262, section 7.9, page 21.
1467  i::Token::Value tok = peek();
1468  if (tok == i::Token::SEMICOLON) {
1469  Next();
1470  return;
1471  }
1472  if (scanner_->HasAnyLineTerminatorBeforeNext() ||
1473  tok == i::Token::RBRACE ||
1474  tok == i::Token::EOS) {
1475  return;
1476  }
1477  Expect(i::Token::SEMICOLON, ok);
1478 }
1479 
1480 
1481 void PreParser::LogSymbol() {
1482  int identifier_pos = scanner_->location().beg_pos;
1483  if (scanner_->is_literal_ascii()) {
1484  log_->LogAsciiSymbol(identifier_pos, scanner_->literal_ascii_string());
1485  } else {
1486  log_->LogUtf16Symbol(identifier_pos, scanner_->literal_utf16_string());
1487  }
1488 }
1489 
1490 
1491 PreParser::Expression PreParser::GetStringSymbol() {
1492  const int kUseStrictLength = 10;
1493  const char* kUseStrictChars = "use strict";
1494  LogSymbol();
1495  if (scanner_->is_literal_ascii() &&
1496  scanner_->literal_length() == kUseStrictLength &&
1497  !scanner_->literal_contains_escapes() &&
1498  !strncmp(scanner_->literal_ascii_string().start(), kUseStrictChars,
1499  kUseStrictLength)) {
1500  return Expression::UseStrictStringLiteral();
1501  }
1502  return Expression::StringLiteral();
1503 }
1504 
1505 
1506 PreParser::Identifier PreParser::GetIdentifierSymbol() {
1507  LogSymbol();
1508  if (scanner_->current_token() == i::Token::FUTURE_RESERVED_WORD) {
1509  return Identifier::FutureReserved();
1510  } else if (scanner_->current_token() ==
1511  i::Token::FUTURE_STRICT_RESERVED_WORD) {
1512  return Identifier::FutureStrictReserved();
1513  }
1514  if (scanner_->is_literal_ascii()) {
1515  // Detect strict-mode poison words.
1516  if (scanner_->literal_length() == 4 &&
1517  !strncmp(scanner_->literal_ascii_string().start(), "eval", 4)) {
1518  return Identifier::Eval();
1519  }
1520  if (scanner_->literal_length() == 9 &&
1521  !strncmp(scanner_->literal_ascii_string().start(), "arguments", 9)) {
1522  return Identifier::Arguments();
1523  }
1524  }
1525  return Identifier::Default();
1526 }
1527 
1528 
1529 PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
1530  i::Token::Value next = Next();
1531  switch (next) {
1532  case i::Token::FUTURE_RESERVED_WORD: {
1533  i::Scanner::Location location = scanner_->location();
1534  ReportMessageAt(location.beg_pos, location.end_pos,
1535  "reserved_word", NULL);
1536  *ok = false;
1537  return GetIdentifierSymbol();
1538  }
1539  case i::Token::FUTURE_STRICT_RESERVED_WORD:
1540  if (!is_classic_mode()) {
1541  i::Scanner::Location location = scanner_->location();
1542  ReportMessageAt(location.beg_pos, location.end_pos,
1543  "strict_reserved_word", NULL);
1544  *ok = false;
1545  }
1546  // FALLTHROUGH
1547  case i::Token::IDENTIFIER:
1548  return GetIdentifierSymbol();
1549  default:
1550  *ok = false;
1551  return Identifier::Default();
1552  }
1553 }
1554 
1555 
1556 void PreParser::SetStrictModeViolation(i::Scanner::Location location,
1557  const char* type,
1558  bool* ok) {
1559  if (!is_classic_mode()) {
1560  ReportMessageAt(location, type, NULL);
1561  *ok = false;
1562  return;
1563  }
1564  // Delay report in case this later turns out to be strict code
1565  // (i.e., for function names and parameters prior to a "use strict"
1566  // directive).
1567  // It's safe to overwrite an existing violation.
1568  // It's either from a function that turned out to be non-strict,
1569  // or it's in the current function (and we just need to report
1570  // one error), or it's in a unclosed nesting function that wasn't
1571  // strict (otherwise we would already be in strict mode).
1572  strict_mode_violation_location_ = location;
1573  strict_mode_violation_type_ = type;
1574 }
1575 
1576 
1577 void PreParser::CheckDelayedStrictModeViolation(int beg_pos,
1578  int end_pos,
1579  bool* ok) {
1580  i::Scanner::Location location = strict_mode_violation_location_;
1581  if (location.IsValid() &&
1582  location.beg_pos > beg_pos && location.end_pos < end_pos) {
1583  ReportMessageAt(location, strict_mode_violation_type_, NULL);
1584  *ok = false;
1585  }
1586 }
1587 
1588 
1589 void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location,
1590  const char* eval_args_type,
1591  Identifier identifier,
1592  bool* ok) {
1593  const char* type = eval_args_type;
1594  if (identifier.IsFutureReserved()) {
1595  type = "reserved_word";
1596  } else if (identifier.IsFutureStrictReserved()) {
1597  type = "strict_reserved_word";
1598  }
1599  if (!is_classic_mode()) {
1600  ReportMessageAt(location, type, NULL);
1601  *ok = false;
1602  return;
1603  }
1604  strict_mode_violation_location_ = location;
1605  strict_mode_violation_type_ = type;
1606 }
1607 
1608 
1609 PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
1610  i::Token::Value next = Next();
1611  if (i::Token::IsKeyword(next)) {
1612  int pos = scanner_->location().beg_pos;
1613  const char* keyword = i::Token::String(next);
1614  log_->LogAsciiSymbol(pos, i::Vector<const char>(keyword,
1615  i::StrLength(keyword)));
1616  return Identifier::Default();
1617  }
1618  if (next == i::Token::IDENTIFIER ||
1619  next == i::Token::FUTURE_RESERVED_WORD ||
1620  next == i::Token::FUTURE_STRICT_RESERVED_WORD) {
1621  return GetIdentifierSymbol();
1622  }
1623  *ok = false;
1624  return Identifier::Default();
1625 }
1626 
1627 #undef CHECK_OK
1628 
1629 
1630 // This function reads an identifier and determines whether or not it
1631 // is 'get' or 'set'.
1632 PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get,
1633  bool* is_set,
1634  bool* ok) {
1635  Identifier result = ParseIdentifierName(ok);
1636  if (!*ok) return Identifier::Default();
1637  if (scanner_->is_literal_ascii() &&
1638  scanner_->literal_length() == 3) {
1639  const char* token = scanner_->literal_ascii_string().start();
1640  *is_get = strncmp(token, "get", 3) == 0;
1641  *is_set = !*is_get && strncmp(token, "set", 3) == 0;
1642  }
1643  return result;
1644 }
1645 
1646 bool PreParser::peek_any_identifier() {
1647  i::Token::Value next = peek();
1648  return next == i::Token::IDENTIFIER ||
1649  next == i::Token::FUTURE_RESERVED_WORD ||
1650  next == i::Token::FUTURE_STRICT_RESERVED_WORD;
1651 }
1652 
1653 
1655  return AddSymbol(i::Vector<const byte>::cast(key), true, value);
1656 }
1657 
1659  return AddSymbol(i::Vector<const byte>::cast(key), false, value);
1660 }
1661 
1662 int DuplicateFinder::AddSymbol(i::Vector<const byte> key,
1663  bool is_ascii,
1664  int value) {
1665  uint32_t hash = Hash(key, is_ascii);
1666  byte* encoding = BackupKey(key, is_ascii);
1667  i::HashMap::Entry* entry = map_.Lookup(encoding, hash, true);
1668  int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
1669  entry->value =
1670  reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
1671  return old_value;
1672 }
1673 
1674 
1676  ASSERT(key.length() > 0);
1677  // Quick check for already being in canonical form.
1678  if (IsNumberCanonical(key)) {
1679  return AddAsciiSymbol(key, value);
1680  }
1681 
1683  double double_value = StringToDouble(unicode_constants_, key, flags, 0.0);
1684  int length;
1685  const char* string;
1686  if (!isfinite(double_value)) {
1687  string = "Infinity";
1688  length = 8; // strlen("Infinity");
1689  } else {
1690  string = DoubleToCString(double_value,
1691  i::Vector<char>(number_buffer_, kBufferSize));
1692  length = i::StrLength(string);
1693  }
1694  return AddSymbol(i::Vector<const byte>(reinterpret_cast<const byte*>(string),
1695  length), true, value);
1696 }
1697 
1698 
1699 bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) {
1700  // Test for a safe approximation of number literals that are already
1701  // in canonical form: max 15 digits, no leading zeroes, except an
1702  // integer part that is a single zero, and no trailing zeros below
1703  // the decimal point.
1704  int pos = 0;
1705  int length = number.length();
1706  if (number.length() > 15) return false;
1707  if (number[pos] == '0') {
1708  pos++;
1709  } else {
1710  while (pos < length &&
1711  static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++;
1712  }
1713  if (length == pos) return true;
1714  if (number[pos] != '.') return false;
1715  pos++;
1716  bool invalid_last_digit = true;
1717  while (pos < length) {
1718  byte digit = number[pos] - '0';
1719  if (digit > '9' - '0') return false;
1720  invalid_last_digit = (digit == 0);
1721  pos++;
1722  }
1723  return !invalid_last_digit;
1724 }
1725 
1726 
1727 uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) {
1728  // Primitive hash function, almost identical to the one used
1729  // for strings (except that it's seeded by the length and ASCII-ness).
1730  int length = key.length();
1731  uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ;
1732  for (int i = 0; i < length; i++) {
1733  uint32_t c = key[i];
1734  hash = (hash + c) * 1025;
1735  hash ^= (hash >> 6);
1736  }
1737  return hash;
1738 }
1739 
1740 
1741 bool DuplicateFinder::Match(void* first, void* second) {
1742  // Decode lengths.
1743  // Length + ASCII-bit is encoded as base 128, most significant heptet first,
1744  // with a 8th bit being non-zero while there are more heptets.
1745  // The value encodes the number of bytes following, and whether the original
1746  // was ASCII.
1747  byte* s1 = reinterpret_cast<byte*>(first);
1748  byte* s2 = reinterpret_cast<byte*>(second);
1749  uint32_t length_ascii_field = 0;
1750  byte c1;
1751  do {
1752  c1 = *s1;
1753  if (c1 != *s2) return false;
1754  length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f);
1755  s1++;
1756  s2++;
1757  } while ((c1 & 0x80) != 0);
1758  int length = static_cast<int>(length_ascii_field >> 1);
1759  return memcmp(s1, s2, length) == 0;
1760 }
1761 
1762 
1763 byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes,
1764  bool is_ascii) {
1765  uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0);
1766  backing_store_.StartSequence();
1767  // Emit ascii_length as base-128 encoded number, with the 7th bit set
1768  // on the byte of every heptet except the last, least significant, one.
1769  if (ascii_length >= (1 << 7)) {
1770  if (ascii_length >= (1 << 14)) {
1771  if (ascii_length >= (1 << 21)) {
1772  if (ascii_length >= (1 << 28)) {
1773  backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80));
1774  }
1775  backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u));
1776  }
1777  backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u));
1778  }
1779  backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u));
1780  }
1781  backing_store_.Add(static_cast<byte>(ascii_length & 0x7f));
1782 
1783  backing_store_.AddBlock(bytes);
1784  return backing_store_.EndSequence().start();
1785 }
1786 } } // v8::preparser
const SwVfpRegister s2
static int Precedence(Value tok)
Definition: token.h:282
value format" "after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false, "print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false, "print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false, "report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true, "garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true, "flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true, "use incremental marking") DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps") DEFINE_bool(trace_incremental_marking, false, "trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true, "Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false, "Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true, "use inline caching") DEFINE_bool(native_code_counters, false, "generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false, "Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true, "Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false, "Never perform compaction on full GC-testing only") DEFINE_bool(compact_code_space, true, "Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true, "Flush inline caches prior to mark compact collection and" "flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0, "Default seed for initializing random generator" "(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true, "allows verbose printing") DEFINE_bool(allow_natives_syntax, false, "allow natives syntax") DEFINE_bool(trace_sim, false, "Trace simulator execution") DEFINE_bool(check_icache, false, "Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8, "Stack alingment in bytes in simulator(4 or 8, 8 is default)") DEFINE_bool(trace_exception, false, "print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false, "preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true, "randomize hashes to avoid predictable hash collisions" "(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0, "Fixed seed to use to hash property keys(0 means random)" "(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false, "activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true, "generate optimized regexp code") DEFINE_bool(testing_bool_flag, true, "testing_bool_flag") DEFINE_int(testing_int_flag, 13, "testing_int_flag") DEFINE_float(testing_float_flag, 2.5, "float-flag") DEFINE_string(testing_string_flag, "Hello, world!", "string-flag") DEFINE_int(testing_prng_seed, 42, "Seed used for threading test randomness") DEFINE_string(testing_serialization_file, "/tmp/serdes", "file in which to serialize heap") DEFINE_bool(help, false, "Print usage message, including flags, on console") DEFINE_bool(dump_counters, false, "Dump counters on exit") DEFINE_string(map_counters, "", "Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT, "Pass all remaining arguments to the script.Alias for\"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#43"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2#define FLAG_MODE_DEFINE_DEFAULTS#1"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flag-definitions.h"1#define FLAG_FULL(ftype, ctype, nam, def, cmt)#define FLAG_READONLY(ftype, ctype, nam, def, cmt)#define DEFINE_implication(whenflag, thenflag)#define DEFINE_bool(nam, def, cmt)#define DEFINE_int(nam, def, cmt)#define DEFINE_float(nam, def, cmt)#define DEFINE_string(nam, def, cmt)#define DEFINE_args(nam, def, cmt)#define FLAG DEFINE_bool(use_strict, false,"enforce strict mode") DEFINE_bool(es5_readonly, false,"activate correct semantics for inheriting readonliness") DEFINE_bool(es52_globals, false,"activate new semantics for global var declarations") DEFINE_bool(harmony_typeof, false,"enable harmony semantics for typeof") DEFINE_bool(harmony_scoping, false,"enable harmony block scoping") DEFINE_bool(harmony_modules, false,"enable harmony modules (implies block scoping)") DEFINE_bool(harmony_proxies, false,"enable harmony proxies") DEFINE_bool(harmony_collections, false,"enable harmony collections (sets, maps, and weak maps)") DEFINE_bool(harmony, false,"enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) DEFINE_implication(harmony, harmony_proxies) DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_bool(packed_arrays, false,"optimizes arrays that have no holes") DEFINE_bool(smi_only_arrays, true,"tracks arrays with only smi values") DEFINE_bool(clever_optimizations, true,"Optimize object size, Array shift, DOM strings and string +") DEFINE_bool(unbox_double_arrays, true,"automatically unbox arrays of doubles") DEFINE_bool(string_slices, true,"use string slices") DEFINE_bool(crankshaft, true,"use crankshaft") DEFINE_string(hydrogen_filter,"","optimization filter") DEFINE_bool(use_range, true,"use hydrogen range analysis") DEFINE_bool(eliminate_dead_phis, true,"eliminate dead phis") DEFINE_bool(use_gvn, true,"use hydrogen global value numbering") DEFINE_bool(use_canonicalizing, true,"use hydrogen instruction canonicalizing") DEFINE_bool(use_inlining, true,"use function inlining") DEFINE_int(max_inlined_source_size, 600,"maximum source size in bytes considered for a single inlining") DEFINE_int(max_inlined_nodes, 196,"maximum number of AST nodes considered for a single inlining") DEFINE_int(max_inlined_nodes_cumulative, 196,"maximum cumulative number of AST nodes considered for inlining") DEFINE_bool(loop_invariant_code_motion, true,"loop invariant code motion") DEFINE_bool(collect_megamorphic_maps_from_stub_cache, true,"crankshaft harvests type feedback from stub cache") DEFINE_bool(hydrogen_stats, false,"print statistics for hydrogen") DEFINE_bool(trace_hydrogen, false,"trace generated hydrogen to file") DEFINE_string(trace_phase,"Z","trace generated IR for specified phases") DEFINE_bool(trace_inlining, false,"trace inlining decisions") DEFINE_bool(trace_alloc, false,"trace register allocator") DEFINE_bool(trace_all_uses, false,"trace all use positions") DEFINE_bool(trace_range, false,"trace range analysis") DEFINE_bool(trace_gvn, false,"trace global value numbering") DEFINE_bool(trace_representation, false,"trace representation types") DEFINE_bool(stress_pointer_maps, false,"pointer map for every instruction") DEFINE_bool(stress_environments, false,"environment for every instruction") DEFINE_int(deopt_every_n_times, 0,"deoptimize every n times a deopt point is passed") DEFINE_bool(trap_on_deopt, false,"put a break point before deoptimizing") DEFINE_bool(deoptimize_uncommon_cases, true,"deoptimize uncommon cases") DEFINE_bool(polymorphic_inlining, true,"polymorphic inlining") DEFINE_bool(use_osr, true,"use on-stack replacement") DEFINE_bool(array_bounds_checks_elimination, false,"perform array bounds checks elimination") DEFINE_bool(array_index_dehoisting, false,"perform array index dehoisting") DEFINE_bool(trace_osr, false,"trace on-stack replacement") DEFINE_int(stress_runs, 0,"number of stress runs") DEFINE_bool(optimize_closures, true,"optimize closures") DEFINE_bool(inline_construct, true,"inline constructor calls") DEFINE_bool(inline_arguments, true,"inline functions with arguments object") DEFINE_int(loop_weight, 1,"loop weight for representation inference") DEFINE_bool(optimize_for_in, true,"optimize functions containing for-in loops") DEFINE_bool(experimental_profiler, true,"enable all profiler experiments") DEFINE_bool(watch_ic_patching, false,"profiler considers IC stability") DEFINE_int(frame_count, 1,"number of stack frames inspected by the profiler") DEFINE_bool(self_optimization, false,"primitive functions trigger their own optimization") DEFINE_bool(direct_self_opt, false,"call recompile stub directly when self-optimizing") DEFINE_bool(retry_self_opt, false,"re-try self-optimization if it failed") DEFINE_bool(count_based_interrupts, false,"trigger profiler ticks based on counting instead of timing") DEFINE_bool(interrupt_at_exit, false,"insert an interrupt check at function exit") DEFINE_bool(weighted_back_edges, false,"weight back edges by jump distance for interrupt triggering") DEFINE_int(interrupt_budget, 5900,"execution budget before interrupt is triggered") DEFINE_int(type_info_threshold, 15,"percentage of ICs that must have type info to allow optimization") DEFINE_int(self_opt_count, 130,"call count before self-optimization") DEFINE_implication(experimental_profiler, watch_ic_patching) DEFINE_implication(experimental_profiler, self_optimization) DEFINE_implication(experimental_profiler, retry_self_opt) DEFINE_implication(experimental_profiler, count_based_interrupts) DEFINE_implication(experimental_profiler, interrupt_at_exit) DEFINE_implication(experimental_profiler, weighted_back_edges) DEFINE_bool(trace_opt_verbose, false,"extra verbose compilation tracing") DEFINE_implication(trace_opt_verbose, trace_opt) DEFINE_bool(debug_code, false,"generate extra code (assertions) for debugging") DEFINE_bool(code_comments, false,"emit comments in code disassembly") DEFINE_bool(enable_sse2, true,"enable use of SSE2 instructions if available") DEFINE_bool(enable_sse3, true,"enable use of SSE3 instructions if available") DEFINE_bool(enable_sse4_1, true,"enable use of SSE4.1 instructions if available") DEFINE_bool(enable_cmov, true,"enable use of CMOV instruction if available") DEFINE_bool(enable_rdtsc, true,"enable use of RDTSC instruction if available") DEFINE_bool(enable_sahf, true,"enable use of SAHF instruction if available (X64 only)") DEFINE_bool(enable_vfp3, true,"enable use of VFP3 instructions if available - this implies ""enabling ARMv7 instructions (ARM only)") DEFINE_bool(enable_armv7, true,"enable use of ARMv7 instructions if available (ARM only)") DEFINE_bool(enable_fpu, true,"enable use of MIPS FPU instructions if available (MIPS only)") DEFINE_string(expose_natives_as, NULL,"expose natives in global object") DEFINE_string(expose_debug_as, NULL,"expose debug in global object") DEFINE_bool(expose_gc, false,"expose gc extension") DEFINE_bool(expose_externalize_string, false,"expose externalize string extension") DEFINE_int(stack_trace_limit, 10,"number of stack frames to capture") DEFINE_bool(builtins_in_stack_traces, false,"show built-in functions in stack traces") DEFINE_bool(disable_native_files, false,"disable builtin natives files") DEFINE_bool(inline_new, true,"use fast inline allocation") DEFINE_bool(stack_trace_on_abort, true,"print a stack trace if an assertion failure occurs") DEFINE_bool(trace, false,"trace function calls") DEFINE_bool(mask_constants_with_cookie, true,"use random jit cookie to mask large constants") DEFINE_bool(lazy, true,"use lazy compilation") DEFINE_bool(trace_opt, false,"trace lazy optimization") DEFINE_bool(trace_opt_stats, false,"trace lazy optimization statistics") DEFINE_bool(opt, true,"use adaptive optimizations") DEFINE_bool(always_opt, false,"always try to optimize functions") DEFINE_bool(prepare_always_opt, false,"prepare for turning on always opt") DEFINE_bool(trace_deopt, false,"trace deoptimization") DEFINE_int(min_preparse_length, 1024,"minimum length for automatic enable preparsing") DEFINE_bool(always_full_compiler, false,"try to use the dedicated run-once backend for all code") DEFINE_bool(trace_bailout, false,"print reasons for falling back to using the classic V8 backend") DEFINE_bool(compilation_cache, true,"enable compilation cache") DEFINE_bool(cache_prototype_transitions, true,"cache prototype transitions") DEFINE_bool(trace_debug_json, false,"trace debugging JSON request/response") DEFINE_bool(debugger_auto_break, true,"automatically set the debug break flag when debugger commands are ""in the queue") DEFINE_bool(enable_liveedit, true,"enable liveedit experimental feature") DEFINE_bool(break_on_abort, true,"always cause a debug break before aborting") DEFINE_int(stack_size, kPointerSize *123,"default size of stack region v8 is allowed to use (in kBytes)") DEFINE_int(max_stack_trace_source_length, 300,"maximum length of function source code printed in a stack trace.") DEFINE_bool(always_inline_smi_code, false,"always inline smi code in non-opt code") DEFINE_int(max_new_space_size, 0,"max size of the new generation (in kBytes)") DEFINE_int(max_old_space_size, 0,"max size of the old generation (in Mbytes)") DEFINE_int(max_executable_size, 0,"max size of executable memory (in Mbytes)") DEFINE_bool(gc_global, false,"always perform global GCs") DEFINE_int(gc_interval,-1,"garbage collect after <n> allocations") DEFINE_bool(trace_gc, false,"print one trace line following each garbage collection") DEFINE_bool(trace_gc_nvp, false,"print one detailed trace line in name=value format ""after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false,"print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false,"print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false,"report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true,"garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true,"flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true,"use incremental marking") DEFINE_bool(incremental_marking_steps, true,"do incremental marking steps") DEFINE_bool(trace_incremental_marking, false,"trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true,"Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false,"Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true,"use inline caching") DEFINE_bool(native_code_counters, false,"generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false,"Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true,"Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false,"Never perform compaction on full GC - testing only") DEFINE_bool(compact_code_space, true,"Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true,"Flush inline caches prior to mark compact collection and ""flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0,"Default seed for initializing random generator ""(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true,"allows verbose printing") DEFINE_bool(allow_natives_syntax, false,"allow natives syntax") DEFINE_bool(trace_sim, false,"Trace simulator execution") DEFINE_bool(check_icache, false,"Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0,"Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8,"Stack alingment in bytes in simulator (4 or 8, 8 is default)") DEFINE_bool(trace_exception, false,"print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false,"preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true,"randomize hashes to avoid predictable hash collisions ""(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0,"Fixed seed to use to hash property keys (0 means random)""(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false,"activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true,"generate optimized regexp code") DEFINE_bool(testing_bool_flag, true,"testing_bool_flag") DEFINE_int(testing_int_flag, 13,"testing_int_flag") DEFINE_float(testing_float_flag, 2.5,"float-flag") DEFINE_string(testing_string_flag,"Hello, world!","string-flag") DEFINE_int(testing_prng_seed, 42,"Seed used for threading test randomness") DEFINE_string(testing_serialization_file,"/tmp/serdes","file in which to serialize heap") DEFINE_bool(help, false,"Print usage message, including flags, on console") DEFINE_bool(dump_counters, false,"Dump counters on exit") DEFINE_string(map_counters,"","Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT,"Pass all remaining arguments to the script. Alias for \"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#47"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2 namespace{struct Flag{enum FlagType{TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS} name
Definition: flags.cc:1349
static bool IsUnaryOp(Value op)
Definition: token.h:260
Flag flags[]
Definition: flags.cc:1467
int literal_length() const
Definition: scanner.h:349
void Add(T value)
Definition: utils.h:565
#define ASSERT(condition)
Definition: checks.h:270
bool HasAnyLineTerminatorBeforeNext() const
Definition: scanner.h:423
int AddNumber(i::Vector< const char > key, int value)
Definition: preparser.cc:1675
virtual void LogFunction(int start, int end, int literals, int properties, LanguageMode language_mode)=0
double StringToDouble(UnicodeCache *unicode_cache, const char *str, int flags, double empty_string_val)
Definition: conversions.cc:41
#define IN
uint8_t byte
Definition: preparser.h:43
Vector< T > AddBlock(int size, T initial_value)
Definition: utils.h:578
T * start() const
Definition: utils.h:389
bool literal_contains_escapes() const
Definition: scanner.h:354
virtual void LogAsciiSymbol(int start, Vector< const char > literal)
Definition: preparse-data.h:55
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
static const char * String(Value tok)
Definition: token.h:275
const char * DoubleToCString(double v, Vector< char > buffer)
Definition: conversions.cc:68
static bool IsAssignmentOp(Value tok)
Definition: token.h:206
virtual void ResumeRecording()=0
Entry * Lookup(void *key, uint32_t hash, bool insert, AllocationPolicy allocator=AllocationPolicy())
Definition: hashmap.h:130
int length() const
Definition: utils.h:383
#define CHECK_OK
Definition: preparser.cc:782
bool is_literal_ascii()
Definition: scanner.h:345
int AddUtf16Symbol(i::Vector< const uint16_t > key, int value)
Definition: preparser.cc:1658
static bool IsKeyword(Value tok)
Definition: token.h:202
int AddAsciiSymbol(i::Vector< const char > key, int value)
Definition: preparser.cc:1654
int StrLength(const char *string)
Definition: utils.h:234
PreParseResult PreParseLazyFunction(i::LanguageMode mode, i::ParserRecorder *log)
Definition: preparser.cc:55
const SwVfpRegister s1
Location location() const
Definition: scanner.h:330
Vector< T > EndSequence()
Definition: utils.h:714
virtual void PauseRecording()=0
virtual void LogUtf16Symbol(int start, Vector< const uc16 > literal)
Definition: preparse-data.h:56
void clear_octal_position()
Definition: scanner.h:399
#define ASSERT_EQ(v1, v2)
Definition: checks.h:271
Vector< const char > literal_ascii_string()
Definition: scanner.h:337
Token::Value peek() const
Definition: scanner.h:367
Location octal_position() const
Definition: scanner.h:398
Token::Value current_token()
Definition: scanner.h:327
Vector< const uc16 > literal_utf16_string()
Definition: scanner.h:341
bool ScanRegExpPattern(bool seen_equal)
Definition: scanner.cc:993
static bool IsCountOp(Value op)
Definition: token.h:264
UnicodeCache * unicode_cache()
Definition: scanner.h:390
FlagType type() const
Definition: flags.cc:1358
int isfinite(double x)
Location peek_location() const
Definition: scanner.h:369