Revision: 10066
Author:   l...@chromium.org
Date:     Fri Nov 25 01:36:31 2011
Log:      Don't preparse large files to find boundaries of lazy functions.

Instead use the preparser inline to parse only the lazy function
bodies.

This is still disabled for small files.
More measurements are needed to determine if lazy-compiling small
sources is worth it.

Review URL: http://codereview.chromium.org/8662037
http://code.google.com/p/v8/source/detail?r=10066

Modified:
 /branches/bleeding_edge/src/compiler.cc
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/liveedit.cc
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/parser.h
 /branches/bleeding_edge/src/preparser.cc
 /branches/bleeding_edge/src/preparser.h
 /branches/bleeding_edge/src/scanner.h
 /branches/bleeding_edge/test/cctest/test-parsing.cc
 /branches/bleeding_edge/test/mjsunit/regress/regress-1110.js

=======================================
--- /branches/bleeding_edge/src/compiler.cc     Thu Nov 24 07:17:04 2011
+++ /branches/bleeding_edge/src/compiler.cc     Fri Nov 25 01:36:31 2011
@@ -377,8 +377,14 @@

   // Only allow non-global compiles for eval.
   ASSERT(info->is_eval() || info->is_global());
-
-  if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null();
+  ParsingFlags flags = kNoParsingFlags;
+  if (info->pre_parse_data() != NULL ||
+ String::cast(script->source())->length() > FLAG_min_preparse_length) {
+    flags = kAllowLazy;
+  }
+  if (!ParserApi::Parse(info, flags)) {
+    return Handle<SharedFunctionInfo>::null();
+  }

   // Measure how long it takes to do the compilation; only take the
   // rest of the function into account to avoid overlap with the
@@ -453,7 +459,7 @@
                                              int line_offset,
                                              int column_offset,
                                              v8::Extension* extension,
- ScriptDataImpl* input_pre_data,
+                                             ScriptDataImpl* pre_data,
                                              Handle<Object> script_data,
                                              NativesFlag natives) {
   Isolate* isolate = source->GetIsolate();
@@ -484,24 +490,12 @@
     // for small sources, odds are that there aren't many functions
     // that would be compiled lazily anyway, so we skip the preparse step
     // in that case too.
-    ScriptDataImpl* pre_data = input_pre_data;
     int flags = kNoParsingFlags;
     if ((natives == NATIVES_CODE) || FLAG_allow_natives_syntax) {
       flags |= kAllowNativesSyntax;
     }
     if (natives != NATIVES_CODE && FLAG_harmony_scoping) {
-      flags |= kHarmonyScoping;
-    }
-    if (pre_data == NULL
-        && source_length >= FLAG_min_preparse_length) {
-      if (source->IsExternalTwoByteString()) {
-        ExternalTwoByteStringUC16CharacterStream stream(
- Handle<ExternalTwoByteString>::cast(source), 0, source->length());
-        pre_data = ParserApi::PartialPreParse(&stream, extension, flags);
-      } else {
- GenericStringUC16CharacterStream stream(source, 0, source->length());
-        pre_data = ParserApi::PartialPreParse(&stream, extension, flags);
-      }
+      flags |= EXTENDED_MODE;
     }

     // Create a script object describing the script to be compiled.
@@ -527,11 +521,6 @@
     if (extension == NULL && !result.is_null()) {
       compilation_cache->PutScript(source, result);
     }
-
-    // Get rid of the pre-parsing data (if necessary).
-    if (input_pre_data == NULL && pre_data != NULL) {
-      delete pre_data;
-    }
   }

   if (result.is_null()) isolate->ReportPendingMessages();
@@ -604,7 +593,7 @@
   isolate->counters()->total_compile_size()->Increment(compiled_size);

   // Generate the AST for the lazily compiled function.
-  if (ParserApi::Parse(info)) {
+  if (ParserApi::Parse(info, kNoParsingFlags)) {
     // Measure how long it takes to do the lazy compilation; only take the
     // rest of the function into account to avoid overlap with the lazy
     // parsing statistics.
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Thu Nov 24 07:17:04 2011
+++ /branches/bleeding_edge/src/hydrogen.cc     Fri Nov 25 01:36:31 2011
@@ -4763,7 +4763,7 @@

   // Parse and allocate variables.
   CompilationInfo target_info(target);
-  if (!ParserApi::Parse(&target_info) ||
+  if (!ParserApi::Parse(&target_info, kNoParsingFlags) ||
       !Scope::Analyze(&target_info)) {
     if (target_info.isolate()->has_pending_exception()) {
       // Parse or scope error, never optimize this function.
=======================================
--- /branches/bleeding_edge/src/liveedit.cc     Wed Nov  9 05:54:26 2011
+++ /branches/bleeding_edge/src/liveedit.cc     Fri Nov 25 01:36:31 2011
@@ -602,7 +602,8 @@
   // Build AST.
   CompilationInfo info(script);
   info.MarkAsGlobal();
-  if (ParserApi::Parse(&info)) {
+  // Parse and don't allow skipping lazy functions.
+  if (ParserApi::Parse(&info, kNoParsingFlags)) {
     // Compile the code.
     LiveEditFunctionTracker tracker(info.isolate(), info.function());
     if (Compiler::MakeCodeForLiveEdit(&info)) {
=======================================
--- /branches/bleeding_edge/src/parser.cc       Thu Nov 24 07:58:09 2011
+++ /branches/bleeding_edge/src/parser.cc       Fri Nov 25 01:36:31 2011
@@ -586,24 +586,28 @@
 // Implementation of Parser

 Parser::Parser(Handle<Script> script,
-               bool allow_natives_syntax,
+               int parser_flags,
                v8::Extension* extension,
                ScriptDataImpl* pre_data)
     : isolate_(script->GetIsolate()),
       symbol_cache_(pre_data ? pre_data->symbol_count() : 0),
       script_(script),
       scanner_(isolate_->unicode_cache()),
+      reusable_preparser_(NULL),
       top_scope_(NULL),
       current_function_state_(NULL),
       target_stack_(NULL),
       extension_(extension),
       pre_data_(pre_data),
       fni_(NULL),
-      allow_natives_syntax_(allow_natives_syntax),
+      allow_natives_syntax_((parser_flags & kAllowNativesSyntax) != 0),
+      allow_lazy_((parser_flags & kAllowLazy) != 0),
       stack_overflow_(false),
       parenthesized_function_(false) {
-  scanner().SetHarmonyScoping(FLAG_harmony_scoping);
   AstNode::ResetIds();
+  if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) {
+    scanner().SetHarmonyScoping(true);
+  }
 }


@@ -641,7 +645,7 @@
   if (pre_data_ != NULL) pre_data_->Initialize();

   // Compute the parsing mode.
-  mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
+  mode_ = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY;
   if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;

   Handle<String> no_name = isolate()->factory()->empty_symbol();
@@ -3911,6 +3915,98 @@
 }


+class SingletonLogger : public ParserRecorder {
+ public:
+  SingletonLogger() : has_error_(false), start_(-1), end_(-1) { }
+  ~SingletonLogger() { }
+
+  void Reset() { has_error_ = false; }
+
+  virtual void LogFunction(int start,
+                           int end,
+                           int literals,
+                           int properties,
+                           LanguageMode mode) {
+    ASSERT(!has_error_);
+    start_ = start;
+    end_ = end;
+    literals_ = literals;
+    properties_ = properties;
+    mode_ = mode;
+  };
+
+  // Logs a symbol creation of a literal or identifier.
+  virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
+  virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { }
+
+  // Logs an error message and marks the log as containing an error.
+  // Further logging will be ignored, and ExtractData will return a vector
+  // representing the error only.
+  virtual void LogMessage(int start,
+                          int end,
+                          const char* message,
+                          const char* argument_opt) {
+    has_error_ = true;
+    start_ = start;
+    end_ = end;
+    message_ = message;
+    argument_opt_ = argument_opt;
+  }
+
+  virtual int function_position() { return 0; }
+
+  virtual int symbol_position() { return 0; }
+
+  virtual int symbol_ids() { return -1; }
+
+  virtual Vector<unsigned> ExtractData() {
+    UNREACHABLE();
+    return Vector<unsigned>();
+  }
+
+  virtual void PauseRecording() { }
+
+  virtual void ResumeRecording() { }
+
+  bool has_error() { return has_error_; }
+
+  int start() { return start_; }
+  int end() { return end_; }
+  int literals() {
+    ASSERT(!has_error_);
+    return literals_;
+  }
+  int properties() {
+    ASSERT(!has_error_);
+    return properties_;
+  }
+  LanguageMode language_mode() {
+    ASSERT(!has_error_);
+    return mode_;
+  }
+  const char* message() {
+    ASSERT(has_error_);
+    return message_;
+  }
+  const char* argument_opt() {
+    ASSERT(has_error_);
+    return argument_opt_;
+  }
+
+ private:
+  bool has_error_;
+  int start_;
+  int end_;
+  // For function entries.
+  int literals_;
+  int properties_;
+  LanguageMode mode_;
+  // For error messages.
+  const char* message_;
+  const char* argument_opt_;
+};
+
+
 FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
                                               bool name_is_strict_reserved,
                                               int function_token_position,
@@ -3937,8 +4033,8 @@
       ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
       : NewScope(top_scope_, FUNCTION_SCOPE);
   ZoneList<Statement*>* body = NULL;
-  int materialized_literal_count;
-  int expected_property_count;
+  int materialized_literal_count = -1;
+  int expected_property_count = -1;
   int handler_count = 0;
   bool only_simple_this_property_assignments;
   Handle<FixedArray> this_property_assignments;
@@ -4008,39 +4104,84 @@
       fvar = top_scope_->DeclareFunctionVar(function_name, fvar_mode);
     }

-    // Determine if the function will be lazily compiled. The mode can only
-    // be PARSE_LAZILY if the --lazy flag is true.  We will not lazily
-    // compile if we do not have preparser data for the function.
+    // Determine whether the function will be lazily compiled.
+    // The heuristics are:
+ // - It must not have been prohibited by the caller to Parse (some callers
+    //   need a full AST).
+    // - The outer scope must be trivial (only global variables in scope).
+ // - The function mustn't be a function expression with an open parenthesis
+    //   before; we consider that a hint that the function will be called
+    //   immediately, and it would be a waste of time to make it lazily
+    //   compiled.
+ // These are all things we can know at this point, without looking at the
+    // function itself.
     bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
top_scope_->outer_scope()->is_global_scope() &&
                                top_scope_->HasTrivialOuterContext() &&
-                               !parenthesized_function_ &&
-                               pre_data() != NULL);
+                               !parenthesized_function_);
parenthesized_function_ = false; // The bit was set for this function only.

     if (is_lazily_compiled) {
       int function_block_pos = scanner().location().beg_pos;
- FunctionEntry entry = pre_data()->GetFunctionEntry(function_block_pos);
-      if (!entry.is_valid()) {
-        // There is no preparser data for the function, we will not lazily
-        // compile after all.
-        is_lazily_compiled = false;
+      FunctionEntry entry;
+      if (pre_data_ != NULL) {
+ // If we have pre_data_, we use it to skip parsing the function body. + // the preparser data contains the information we need to construct the
+        // lazy function.
+        entry = pre_data()->GetFunctionEntry(function_block_pos);
+        if (entry.is_valid()) {
+          if (entry.end_pos() <= function_block_pos) {
+            // End position greater than end of stream is safe, and hard
+            // to check.
+            ReportInvalidPreparseData(function_name, CHECK_OK);
+          }
+          scanner().SeekForward(entry.end_pos() - 1);
+
+          scope->set_end_position(entry.end_pos());
+          Expect(Token::RBRACE, CHECK_OK);
+          isolate()->counters()->total_preparse_skipped()->Increment(
+              scope->end_position() - function_block_pos);
+          materialized_literal_count = entry.literal_count();
+          expected_property_count = entry.property_count();
+          top_scope_->SetLanguageMode(entry.language_mode());
+          only_simple_this_property_assignments = false;
+ this_property_assignments = isolate()->factory()->empty_fixed_array();
+        } else {
+          is_lazily_compiled = false;
+        }
       } else {
-        scope->set_end_position(entry.end_pos());
-        if (scope->end_position() <= function_block_pos) {
- // End position greater than end of stream is safe, and hard to check.
-          ReportInvalidPreparseData(function_name, CHECK_OK);
-        }
+        // With no preparser data, we partially parse the function, without
+        // building an AST. This gathers the data needed to build a lazy
+        // function.
+        SingletonLogger logger;
+        preparser::PreParser::PreParseResult result =
+            LazyParseFunctionLiteral(&logger);
+        if (result == preparser::PreParser::kPreParseStackOverflow) {
+          // Propagate stack overflow.
+          stack_overflow_ = true;
+          *ok = false;
+          return NULL;
+        }
+        if (logger.has_error()) {
+          const char* arg = logger.argument_opt();
+          Vector<const char*> args;
+          if (arg != NULL) {
+            args = Vector<const char*>(&arg, 1);
+          }
+          ReportMessageAt(Scanner::Location(logger.start(), logger.end()),
+                          logger.message(), args);
+          *ok = false;
+          return NULL;
+        }
+        scope->set_end_position(logger.end());
+        Expect(Token::RBRACE, CHECK_OK);
         isolate()->counters()->total_preparse_skipped()->Increment(
             scope->end_position() - function_block_pos);
-        // Seek to position just before terminal '}'.
-        scanner().SeekForward(scope->end_position() - 1);
-        materialized_literal_count = entry.literal_count();
-        expected_property_count = entry.property_count();
-        top_scope_->SetLanguageMode(entry.language_mode());
+        materialized_literal_count = logger.literals();
+        expected_property_count = logger.properties();
+        top_scope_->SetLanguageMode(logger.language_mode());
         only_simple_this_property_assignments = false;
this_property_assignments = isolate()->factory()->empty_fixed_array();
-        Expect(Token::RBRACE, CHECK_OK);
       }
     }

@@ -4139,6 +4280,27 @@
if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
   return function_literal;
 }
+
+
+preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
+    SingletonLogger* logger) {
+  HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
+  ASSERT_EQ(Token::LBRACE, scanner().current_token());
+
+  if (reusable_preparser_ == NULL) {
+    intptr_t stack_limit = isolate()->stack_guard()->real_climit();
+    bool do_allow_lazy = true;
+    reusable_preparser_ = new preparser::PreParser(&scanner_,
+                                                   NULL,
+                                                   stack_limit,
+                                                   do_allow_lazy,
+                                                   allow_natives_syntax_);
+  }
+  preparser::PreParser::PreParseResult result =
+ reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
+                                                logger);
+  return result;
+}


 Expression* Parser::ParseV8Intrinsic(bool* ok) {
@@ -5360,10 +5522,12 @@
   scanner.SetHarmonyScoping(FLAG_harmony_scoping);
   scanner.Initialize(source);
   intptr_t stack_limit = isolate->stack_guard()->real_climit();
-  if (!preparser::PreParser::PreParseProgram(&scanner,
-                                             recorder,
-                                             flags,
-                                             stack_limit)) {
+  preparser::PreParser::PreParseResult result =
+      preparser::PreParser::PreParseProgram(&scanner,
+                                            recorder,
+                                            flags,
+                                            stack_limit);
+  if (result == preparser::PreParser::kPreParseStackOverflow) {
     isolate->StackOverflow();
     return NULL;
   }
@@ -5426,26 +5590,26 @@
 }


-bool ParserApi::Parse(CompilationInfo* info) {
+bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
   ASSERT(info->function() == NULL);
   FunctionLiteral* result = NULL;
   Handle<Script> script = info->script();
+  ASSERT((parsing_flags & kLanguageModeMask) == CLASSIC_MODE);
+  if (!info->is_native() && FLAG_harmony_scoping) {
+    // Harmony scoping is requested.
+    parsing_flags |= EXTENDED_MODE;
+  }
+  if (FLAG_allow_natives_syntax || info->is_native()) {
+    // We requre %identifier(..) syntax.
+    parsing_flags |= kAllowNativesSyntax;
+  }
   if (info->is_lazy()) {
     ASSERT(!info->is_eval());
-    bool allow_natives_syntax =
-        FLAG_allow_natives_syntax ||
-        info->is_native();
-    Parser parser(script, allow_natives_syntax, NULL, NULL);
+    Parser parser(script, parsing_flags, NULL, NULL);
     result = parser.ParseLazy(info);
   } else {
-    // Whether we allow %identifier(..) syntax.
-    bool allow_natives_syntax =
-        info->is_native() || FLAG_allow_natives_syntax;
     ScriptDataImpl* pre_data = info->pre_parse_data();
-    Parser parser(script,
-                  allow_natives_syntax,
-                  info->extension(),
-                  pre_data);
+    Parser parser(script, parsing_flags, info->extension(), pre_data);
     if (pre_data != NULL && pre_data->has_error()) {
       Scanner::Location loc = pre_data->MessageLocation();
       const char* message = pre_data->BuildMessage();
=======================================
--- /branches/bleeding_edge/src/parser.h        Thu Nov 24 07:58:09 2011
+++ /branches/bleeding_edge/src/parser.h        Fri Nov 25 01:36:31 2011
@@ -76,8 +76,10 @@
     kSize
   };

-  explicit FunctionEntry(Vector<unsigned> backing) : backing_(backing) { }
-  FunctionEntry() { }
+  explicit FunctionEntry(Vector<unsigned> backing)
+    : backing_(backing) { }
+
+  FunctionEntry() : backing_() { }

   int start_pos() { return backing_[kStartPositionIndex]; }
   int end_pos() { return backing_[kEndPositionIndex]; }
@@ -94,6 +96,7 @@

  private:
   Vector<unsigned> backing_;
+  bool owns_data_;
 };


@@ -166,7 +169,7 @@
// Parses the source code represented by the compilation info and sets its
   // function literal.  Returns false (and deallocates any allocated AST
   // nodes) if parsing failed.
-  static bool Parse(CompilationInfo* info);
+  static bool Parse(CompilationInfo* info, int flags);

   // Generic preparser generating full preparse data.
   static ScriptDataImpl* PreParse(UC16CharacterStream* source,
@@ -422,13 +425,20 @@
// ----------------------------------------------------------------------------
 // JAVASCRIPT PARSING

+// Forward declaration.
+class SingletonLogger;
+
 class Parser {
  public:
   Parser(Handle<Script> script,
-         bool allow_natives_syntax,
+         int parsing_flags,  // Combination of ParsingFlags
          v8::Extension* extension,
          ScriptDataImpl* pre_data);
-  virtual ~Parser() { }
+  virtual ~Parser() {
+    if (reusable_preparser_ != NULL) {
+      delete reusable_preparser_;
+    }
+  }

   // Returns NULL if parsing failed.
   FunctionLiteral* ParseProgram(CompilationInfo* info);
@@ -728,12 +738,15 @@
                             Handle<String> type,
                             Vector< Handle<Object> > arguments);

+  preparser::PreParser::PreParseResult LazyParseFunctionLiteral(
+       SingletonLogger* logger);
+
   Isolate* isolate_;
   ZoneList<Handle<String> > symbol_cache_;

   Handle<Script> script_;
   Scanner scanner_;
-
+  preparser::PreParser* reusable_preparser_;
   Scope* top_scope_;
   FunctionState* current_function_state_;
   Target* target_stack_;  // for break, continue statements
@@ -743,6 +756,7 @@

   Mode mode_;
   bool allow_natives_syntax_;
+  bool allow_lazy_;
   bool stack_overflow_;
   // If true, the next (and immediately following) function literal is
   // preceded by a parenthesis.
=======================================
--- /branches/bleeding_edge/src/preparser.cc    Thu Nov 24 07:17:04 2011
+++ /branches/bleeding_edge/src/preparser.cc    Fri Nov 25 01:36:31 2011
@@ -52,6 +52,34 @@

 namespace preparser {

+PreParser::PreParseResult PreParser::PreParseLazyFunction(
+    i::LanguageMode mode, i::ParserRecorder* log) {
+  log_ = log;
+ // Lazy functions always have trivial outer scopes (no with/catch scopes).
+  Scope top_scope(&scope_, kTopLevelScope);
+  set_language_mode(mode);
+  Scope function_scope(&scope_, kFunctionScope);
+  ASSERT_EQ(i::Token::LBRACE, scanner_->current_token());
+  bool ok = true;
+  int start_position = scanner_->peek_location().beg_pos;
+  ParseLazyFunctionLiteralBody(&ok);
+  if (stack_overflow_) return kPreParseStackOverflow;
+  if (!ok) {
+    ReportUnexpectedToken(scanner_->current_token());
+  } else {
+    ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
+    if (!is_classic_mode()) {
+      int end_pos = scanner_->location().end_pos;
+      CheckOctalLiteral(start_position, end_pos, &ok);
+      if (ok) {
+        CheckDelayedStrictModeViolation(start_position, end_pos, &ok);
+      }
+    }
+  }
+  return kPreParseSuccess;
+}
+
+
// Preparsing checks a JavaScript program and emits preparse-data that helps
 // a later parsing to be faster.
 // See preparser-data.h for the data.
@@ -1350,9 +1378,6 @@
   }
   Expect(i::Token::RPAREN, CHECK_OK);

-  Expect(i::Token::LBRACE, CHECK_OK);
-  int function_block_pos = scanner_->location().beg_pos;
-
   // Determine if the function will be lazily compiled.
   // Currently only happens to top-level functions.
// Optimistically assume that all top-level functions are lazily compiled.
@@ -1361,24 +1386,13 @@
                              !parenthesized_function_);
   parenthesized_function_ = false;

+  Expect(i::Token::LBRACE, CHECK_OK);
   if (is_lazily_compiled) {
-    log_->PauseRecording();
-    ParseSourceElements(i::Token::RBRACE, ok);
-    log_->ResumeRecording();
-    if (!*ok) Expression::Default();
-
-    Expect(i::Token::RBRACE, CHECK_OK);
-
-    // Position right after terminal '}'.
-    int end_pos = scanner_->location().end_pos;
-    log_->LogFunction(function_block_pos, end_pos,
-                      function_scope.materialized_literal_count(),
-                      function_scope.expected_properties(),
-                      language_mode());
+    ParseLazyFunctionLiteralBody(CHECK_OK);
   } else {
-    ParseSourceElements(i::Token::RBRACE, CHECK_OK);
-    Expect(i::Token::RBRACE, CHECK_OK);
-  }
+    ParseSourceElements(i::Token::RBRACE, ok);
+  }
+  Expect(i::Token::RBRACE, CHECK_OK);

   if (!is_classic_mode()) {
     int end_position = scanner_->location().end_pos;
@@ -1389,6 +1403,23 @@

   return Expression::Default();
 }
+
+
+void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
+  int body_start = scanner_->location().beg_pos;
+  log_->PauseRecording();
+  ParseSourceElements(i::Token::RBRACE, ok);
+  log_->ResumeRecording();
+  if (!*ok) return;
+
+  // Position right after terminal '}'.
+  ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
+  int body_end = scanner_->peek_location().end_pos;
+  log_->LogFunction(body_start, body_end,
+                    scope_->materialized_literal_count(),
+                    scope_->expected_properties(),
+                    language_mode());
+}


 PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
=======================================
--- /branches/bleeding_edge/src/preparser.h     Thu Nov 24 07:17:04 2011
+++ /branches/bleeding_edge/src/preparser.h     Fri Nov 25 01:36:31 2011
@@ -109,6 +109,24 @@
     kPreParseStackOverflow,
     kPreParseSuccess
   };
+
+
+  PreParser(i::Scanner* scanner,
+            i::ParserRecorder* log,
+            uintptr_t stack_limit,
+            bool allow_lazy,
+            bool allow_natives_syntax)
+      : scanner_(scanner),
+        log_(log),
+        scope_(NULL),
+        stack_limit_(stack_limit),
+        strict_mode_violation_location_(i::Scanner::Location::invalid()),
+        strict_mode_violation_type_(NULL),
+        stack_overflow_(false),
+        allow_lazy_(allow_lazy),
+        allow_natives_syntax_(allow_natives_syntax),
+        parenthesized_function_(false),
+        harmony_scoping_(scanner->HarmonyScoping()) { }

   ~PreParser() {}

@@ -125,6 +143,17 @@
     return PreParser(scanner, log, stack_limit,
                      allow_lazy, allow_natives_syntax).PreParse();
   }
+
+  // Parses a single function literal, from the opening parentheses before
+  // parameters to the closing brace after the body.
+  // Returns a FunctionEntry describing the body of the funciton in enough
+  // detail that it can be lazily compiled.
+  // The scanner is expected to have matched the "function" keyword and
+  // parameters, and have consumed the initial '{'.
+ // At return, unless an error occured, the scanner is positioned before the
+  // the final '}'.
+  PreParseResult PreParseLazyFunction(i::LanguageMode mode,
+                                      i::ParserRecorder* log);

  private:
   // Used to detect duplicates in object literals. Each of the values
@@ -449,24 +478,6 @@
     int with_nesting_count_;
     i::LanguageMode language_mode_;
   };
-
-  // Private constructor only used in PreParseProgram.
-  PreParser(i::Scanner* scanner,
-            i::ParserRecorder* log,
-            uintptr_t stack_limit,
-            bool allow_lazy,
-            bool allow_natives_syntax)
-      : scanner_(scanner),
-        log_(log),
-        scope_(NULL),
-        stack_limit_(stack_limit),
-        strict_mode_violation_location_(i::Scanner::Location::invalid()),
-        strict_mode_violation_type_(NULL),
-        stack_overflow_(false),
-        allow_lazy_(allow_lazy),
-        allow_natives_syntax_(allow_natives_syntax),
-        parenthesized_function_(false),
-        harmony_scoping_(scanner->HarmonyScoping()) { }

   // Preparse the program. Only called in PreParseProgram after creating
   // the instance.
@@ -547,6 +558,7 @@

   Arguments ParseArguments(bool* ok);
   Expression ParseFunctionLiteral(bool* ok);
+  void ParseLazyFunctionLiteralBody(bool* ok);

   Identifier ParseIdentifier(bool* ok);
   Identifier ParseIdentifierName(bool* ok);
=======================================
--- /branches/bleeding_edge/src/scanner.h       Tue Nov  1 00:47:15 2011
+++ /branches/bleeding_edge/src/scanner.h       Fri Nov 25 01:36:31 2011
@@ -42,15 +42,23 @@
 namespace internal {


-// General collection of bit-flags that can be passed to scanners and
+// General collection of (multi-)bit-flags that can be passed to scanners and
 // parsers to signify their (initial) mode of operation.
 enum ParsingFlags {
   kNoParsingFlags = 0,
-  kAllowLazy = 1,
-  kAllowNativesSyntax = 2,
-  kHarmonyScoping = 4
+  // Embed LanguageMode values in parsing flags, i.e., equivalent to:
+  // CLASSIC_MODE = 0,
+  // STRICT_MODE,
+  // EXTENDED_MODE,
+  kLanguageModeMask = 0x03,
+  kAllowLazy = 4,
+  kAllowNativesSyntax = 8
 };

+STATIC_ASSERT((kLanguageModeMask & CLASSIC_MODE) == CLASSIC_MODE);
+STATIC_ASSERT((kLanguageModeMask & STRICT_MODE) == STRICT_MODE);
+STATIC_ASSERT((kLanguageModeMask & EXTENDED_MODE) == EXTENDED_MODE);
+

 // Returns the value (0 .. 15) of a hexadecimal character c.
 // If c is not a legal hexadecimal character, returns a value < 0.
=======================================
--- /branches/bleeding_edge/test/cctest/test-parsing.cc Thu Nov 24 07:58:09 2011 +++ /branches/bleeding_edge/test/cctest/test-parsing.cc Fri Nov 25 01:36:31 2011
@@ -862,7 +862,7 @@
     i::Handle<i::String> source(
         FACTORY->NewStringFromAscii(i::CStrVector(program.start())));
     i::Handle<i::Script> script = FACTORY->NewScript(source);
-    i::Parser parser(script, false, NULL, NULL);
+    i::Parser parser(script, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
     i::CompilationInfo info(script);
     info.MarkAsGlobal();
     info.SetLanguageMode(source_data[i].language_mode);
=======================================
--- /branches/bleeding_edge/test/mjsunit/regress/regress-1110.js Thu Sep 1 04:28:10 2011 +++ /branches/bleeding_edge/test/mjsunit/regress/regress-1110.js Fri Nov 25 01:36:31 2011
@@ -28,10 +28,9 @@
 // Test that the illegal continue is thrown at parse time.

 try {
-  function Crash() { continue;if (Crash) {
-    } }
+ eval("function Crash() { assertUnreachable(); continue;if (Crash) { } }");
   Crash();
-  assertTrue(false);
+  assertUnreachable();
 } catch (e) {
   assertTrue(e instanceof SyntaxError);
   assertTrue(/continue/.test(e.message));

--
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev

Reply via email to