Preparser extracted into separate files that can be compiled to a library.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 29 Nov 2010 13:24:37 +0000 (13:24 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 29 Nov 2010 13:24:37 +0000 (13:24 +0000)
No scons target yet.

Review URL: http://codereview.chromium.org/5295004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5899 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
include/v8-preparser.h [new file with mode: 0644]
preparser/preparser-process.cc
src/parser.cc
src/parser.h
src/preparser-api.cc [new file with mode: 0644]
src/preparser.cc
src/preparser.h
src/scanner-base.cc
src/scanner-base.h
src/scanner.cc
src/scanner.h
test/cctest/test-parsing.cc

diff --git a/include/v8-preparser.h b/include/v8-preparser.h
new file mode 100644 (file)
index 0000000..68ce502
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef PREPARSER_H
+#define PREPARSER_H
+
+#include "v8stdint.h"
+
+#ifdef _WIN32
+
+// Setup for Windows DLL export/import. When building the V8 DLL the
+// BUILDING_V8_SHARED needs to be defined. When building a program which uses
+// the V8 DLL USING_V8_SHARED needs to be defined. When either building the V8
+// static library or building a program which uses the V8 static library neither
+// BUILDING_V8_SHARED nor USING_V8_SHARED should be defined.
+#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED)
+#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\
+  build configuration to ensure that at most one of these is set
+#endif
+
+#ifdef BUILDING_V8_SHARED
+#define V8EXPORT __declspec(dllexport)
+#elif USING_V8_SHARED
+#define V8EXPORT __declspec(dllimport)
+#else
+#define V8EXPORT
+#endif  // BUILDING_V8_SHARED
+
+#else  // _WIN32
+
+// Setup for Linux shared library export. There is no need to distinguish
+// between building or using the V8 shared library, but we should not
+// export symbols when we are building a static library.
+#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(V8_SHARED)
+#define V8EXPORT __attribute__ ((visibility("default")))
+#else  // defined(__GNUC__) && (__GNUC__ >= 4)
+#define V8EXPORT
+#endif  // defined(__GNUC__) && (__GNUC__ >= 4)
+
+#endif  // _WIN32
+
+
+namespace v8 {
+
+
+class PreParserData {
+ public:
+  PreParserData(size_t size, const uint8_t* data)
+      : data_(data), size_(size) { }
+
+  // Create a PreParserData value where stack_overflow reports true.
+  static PreParserData StackOverflow() { return PreParserData(NULL, 0); }
+  // Whether the pre-parser stopped due to a stack overflow.
+  // If this is the case, size() and data() should not be used.
+
+  bool stack_overflow() { return size_ == 0u; }
+
+  // The size of the data in bytes.
+  size_t size() const { return size_; }
+
+  // Pointer to the data.
+  const uint8_t* data() const { return data_; }
+
+ private:
+  const uint8_t* const data_;
+  const size_t size_;
+};
+
+
+// Interface for a stream of Unicode characters.
+class UnicodeInputStream {
+ public:
+  virtual ~UnicodeInputStream();
+
+  // Returns the next Unicode code-point in the input, or a negative value when
+  // there is no more input in the stream.
+  virtual int32_t Next() = 0;
+
+  // Pushes a read character back into the stream, so that it will be the next
+  // to be read by Advance(). The character pushed back must be the most
+  // recently read character that hasn't already been pushed back (i.e., if
+  // pushing back more than one character, they must occur in the opposite order
+  // of the one they were read in).
+  virtual void PushBack(int32_t ch) = 0;
+};
+
+
+// Preparse a JavaScript program. The source code is provided as a
+// UnicodeInputStream. The max_stack_size limits the amount of stack
+// space that the preparser is allowed to use. If the preparser uses
+// more stack space than the limit provided, the result's stack_overflow()
+// method will return true. Otherwise the result contains preparser
+// data that can be used by the V8 parser to speed up parsing.
+PreParserData V8EXPORT Preparse(UnicodeInputStream* input,
+                                size_t max_stack_size);
+
+}  // namespace v8.
+
+#endif  // PREPARSER_H
index 706a2259696cb946f7812af07b8634eb7514e875..80e83508e422901c4e0e82878a97dde75fc4775d 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <stdlib.h>
 #include <stdarg.h>
 #include "../include/v8stdint.h"
-#include "globals.h"
-#include "checks.h"
-#include "allocation.h"
-#include "utils.h"
-#include "list.h"
-#include "smart-pointer.h"
-#include "scanner-base.h"
-#include "preparse-data.h"
-#include "preparser.h"
+#include "../include/v8-preparser.h"
+#include "unicode-inl.h"
 
 enum ResultCode { kSuccess = 0, kErrorReading = 1, kErrorWriting = 2 };
 
@@ -45,78 +39,66 @@ namespace internal {
 // THIS FILE IS PROOF-OF-CONCEPT ONLY.
 // The final goal is a stand-alone preparser library.
 
-// UTF16Buffer based on an UTF-8 string in memory.
-class UTF8UTF16Buffer : public UTF16Buffer {
+
+class UTF8InputStream : public v8::UnicodeInputStream {
  public:
-  UTF8UTF16Buffer(uint8_t* buffer, size_t length)
-      : UTF16Buffer(),
-        buffer_(buffer),
+  UTF8InputStream(uint8_t* buffer, size_t length)
+      : buffer_(buffer),
         offset_(0),
+        pos_(0),
         end_offset_(static_cast<int>(length)) { }
 
-  virtual void PushBack(uc32 ch) {
+  virtual ~UTF8InputStream() { }
+
+  virtual void PushBack(int32_t ch) {
     // Pushback assumes that the character pushed back is the
     // one that was most recently read, and jumps back in the
     // UTF-8 stream by the length of that character's encoding.
     offset_ -= unibrow::Utf8::Length(ch);
     pos_--;
 #ifdef DEBUG
-    int tmp = 0;
-    ASSERT_EQ(ch, unibrow::Utf8::ValueOf(buffer_ + offset_,
-                                         end_offset_ - offset_,
-                                         &tmp);
+    if (static_cast<unsigned>(ch) <= unibrow::Utf8::kMaxOneByteChar) {
+      if (ch != buffer_[offset_]) {
+        fprintf(stderr, "Invalid pushback: '%c'.", ch);
+        exit(1);
+      }
+    } else {
+      unsigned tmp = 0;
+      if (static_cast<unibrow::uchar>(ch) !=
+          unibrow::Utf8::CalculateValue(buffer_ + offset_,
+                                        end_offset_ - offset_,
+                                        &tmp)) {
+        fprintf(stderr, "Invalid pushback: 0x%x.", ch);
+        exit(1);
+      }
+    }
 #endif
   }
 
-  virtual uc32 Advance() {
+  virtual int32_t Next() {
     if (offset_ == end_offset_) return -1;
     uint8_t first_char = buffer_[offset_];
     if (first_char <= unibrow::Utf8::kMaxOneByteChar) {
       pos_++;
       offset_++;
-      return static_cast<uc32>(first_char);
+      return static_cast<int32_t>(first_char);
     }
     unibrow::uchar codepoint =
         unibrow::Utf8::CalculateValue(buffer_ + offset_,
                                       end_offset_ - offset_,
                                       &offset_);
     pos_++;
-    return static_cast<uc32>(codepoint);
-  }
-
-  virtual void SeekForward(int pos) {
-    while (pos_ < pos) {
-      uint8_t first_byte = buffer_[offset_++];
-      while (first_byte & 0x80u && offset_ < end_offset_) {
-        offset_++;
-        first_byte <<= 1;
-      }
-      pos_++;
-    }
+    return static_cast<int32_t>(codepoint);
   }
 
  private:
   const uint8_t* buffer_;
   unsigned offset_;
+  unsigned pos_;
   unsigned end_offset_;
 };
 
 
-class StandAloneJavaScriptScanner : public JavaScriptScanner {
- public:
-  void Initialize(UTF16Buffer* source) {
-    source_ = source;
-    literal_flags_ = kLiteralString | kLiteralIdentifier;
-    Init();
-    // Skip initial whitespace allowing HTML comment ends just like
-    // after a newline and scan first token.
-    has_line_terminator_before_next_ = true;
-    SkipWhiteSpace();
-    Scan();
-  }
-};
-
-
 // Write a number to dest in network byte order.
 void WriteUInt32(FILE* dest, uint32_t value, bool* ok) {
   for (int i = 3; i >= 0; i--) {
@@ -150,56 +132,55 @@ bool ReadBuffer(FILE* source, void* buffer, size_t length) {
 }
 
 
-bool WriteBuffer(FILE* dest, void* buffer, size_t length) {
+bool WriteBuffer(FILE* dest, const void* buffer, size_t length) {
   size_t actually_written = fwrite(buffer, 1, length, dest);
   return (actually_written == length);
 }
 
+
+template <typename T>
+class ScopedPointer {
+ public:
+  explicit ScopedPointer(T* pointer) : pointer_(pointer) {}
+  ~ScopedPointer() { delete[] pointer_; }
+  T& operator[](int index) { return pointer_[index]; }
+  T* operator*() { return pointer_ ;}
+ private:
+  T* pointer_;
+};
+
+
 // Preparse stdin and output result on stdout.
 int PreParseIO() {
   fprintf(stderr, "LOG: Enter parsing loop\n");
   bool ok = true;
   uint32_t length = ReadUInt32(stdin, &ok);
   if (!ok) return kErrorReading;
-  SmartPointer<byte> buffer(NewArray<byte>(length));
+  ScopedPointer<uint8_t> buffer(new uint8_t[length]);
+
   if (!ReadBuffer(stdin, *buffer, length)) {
     return kErrorReading;
   }
-  UTF8UTF16Buffer input_buffer(*buffer, static_cast<size_t>(length));
-  StandAloneJavaScriptScanner scanner;
-  scanner.Initialize(&input_buffer);
-  CompleteParserRecorder recorder;
-  preparser::PreParser preparser;
-
-  if (!preparser.PreParseProgram(&scanner, &recorder, true)) {
-    if (scanner.stack_overflow()) {
-      // Report stack overflow error/no-preparser-data.
-      WriteUInt32(stdout, 0, &ok);
-      if (!ok) return kErrorWriting;
-      return 0;
-    }
+  UTF8InputStream input_buffer(*buffer, static_cast<size_t>(length));
+
+  v8::PreParserData data =
+      v8::Preparse(&input_buffer, 64 * sizeof(void*));  // NOLINT
+  if (data.stack_overflow()) {
+    // Report stack overflow error/no-preparser-data.
+    WriteUInt32(stdout, 0, &ok);
+    if (!ok) return kErrorWriting;
+    return 0;
   }
-  Vector<unsigned> pre_data = recorder.ExtractData();
 
-  uint32_t size = static_cast<uint32_t>(pre_data.length() * sizeof(uint32_t));
+  uint32_t size = data.size();
   WriteUInt32(stdout, size, &ok);
   if (!ok) return kErrorWriting;
-  if (!WriteBuffer(stdout,
-                   reinterpret_cast<byte*>(pre_data.start()),
-                   size)) {
+  if (!WriteBuffer(stdout, data.data(), size)) {
     return kErrorWriting;
   }
   return 0;
 }
 
-// Functions declared by allocation.h
-
-void FatalProcessOutOfMemory(const char* location) {
-  V8_Fatal("", 0, location);
-}
-
-bool EnableSlowAsserts() { return true; }
-
 } }  // namespace v8::internal
 
 
@@ -211,17 +192,3 @@ int main(int argc, char* argv[]) {
   fprintf(stderr, "EXIT: Failure %d\n", status);
   return EXIT_FAILURE;
 }
-
-
-// Fatal error handling declared by checks.h.
-
-extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
-  fflush(stdout);
-  fflush(stderr);
-  va_list arguments;
-  va_start(arguments, format);
-  vfprintf(stderr, format, arguments);
-  va_end(arguments);
-  fputs("\n#\n\n", stderr);
-  exit(EXIT_FAILURE);
-}
index 186d1020d7ce90cb44c9413fe7ec12849fc3bd03..d147dff9390646382b814f8ab1f11a0ac1460fef 100644 (file)
@@ -593,7 +593,8 @@ Parser::Parser(Handle<Script> script,
       allow_natives_syntax_(allow_natives_syntax),
       extension_(extension),
       pre_data_(pre_data),
-      fni_(NULL) {
+      fni_(NULL),
+      stack_overflow_(false) {
 }
 
 
@@ -643,7 +644,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
           source->length(),
           false,
           temp_scope.ContainsLoops());
-    } else if (scanner().stack_overflow()) {
+    } else if (stack_overflow_) {
       Top::StackOverflow();
     }
   }
@@ -693,7 +694,7 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
     // Make sure the results agree.
     ASSERT(ok == (result != NULL));
     // The only errors should be stack overflows.
-    ASSERT(ok || scanner_.stack_overflow());
+    ASSERT(ok || stack_overflow_);
   }
 
   // Make sure the target stack is empty.
@@ -2590,25 +2591,24 @@ void Parser::ReportUnexpectedToken(Token::Value token) {
   // We don't report stack overflows here, to avoid increasing the
   // stack depth even further.  Instead we report it after parsing is
   // over, in ParseProgram/ParseJson.
-  if (token == Token::ILLEGAL && scanner().stack_overflow())
-    return;
+  if (token == Token::ILLEGAL && stack_overflow_) return;
   // Four of the tokens are treated specially
   switch (token) {
-  case Token::EOS:
-    return ReportMessage("unexpected_eos", Vector<const char*>::empty());
-  case Token::NUMBER:
-    return ReportMessage("unexpected_token_number",
-                         Vector<const char*>::empty());
-  case Token::STRING:
-    return ReportMessage("unexpected_token_string",
-                         Vector<const char*>::empty());
-  case Token::IDENTIFIER:
-    return ReportMessage("unexpected_token_identifier",
-                         Vector<const char*>::empty());
-  default:
-    const char* name = Token::String(token);
-    ASSERT(name != NULL);
-    ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
+    case Token::EOS:
+      return ReportMessage("unexpected_eos", Vector<const char*>::empty());
+    case Token::NUMBER:
+      return ReportMessage("unexpected_token_number",
+                           Vector<const char*>::empty());
+    case Token::STRING:
+      return ReportMessage("unexpected_token_string",
+                           Vector<const char*>::empty());
+    case Token::IDENTIFIER:
+      return ReportMessage("unexpected_token_identifier",
+                           Vector<const char*>::empty());
+    default:
+      const char* name = Token::String(token);
+      ASSERT(name != NULL);
+      ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
   }
 }
 
@@ -3498,9 +3498,10 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
 Handle<Object> JsonParser::ParseJson(Handle<String> source) {
   source->TryFlatten();
   scanner_.Initialize(source);
+  stack_overflow_ = false;
   Handle<Object> result = ParseJsonValue();
   if (result.is_null() || scanner_.Next() != Token::EOS) {
-    if (scanner_.stack_overflow()) {
+    if (stack_overflow_) {
       // Scanner failed.
       Top::StackOverflow();
     } else {
@@ -3598,6 +3599,10 @@ Handle<Object> JsonParser::ParseJsonObject() {
   if (scanner_.peek() == Token::RBRACE) {
     scanner_.Next();
   } else {
+    if (StackLimitCheck().HasOverflowed()) {
+      stack_overflow_ = true;
+      return Handle<Object>::null();
+    }
     do {
       if (scanner_.Next() != Token::STRING) {
         return ReportUnexpectedToken();
@@ -3632,6 +3637,10 @@ Handle<Object> JsonParser::ParseJsonArray() {
   if (token == Token::RBRACK) {
     scanner_.Next();
   } else {
+    if (StackLimitCheck().HasOverflowed()) {
+      stack_overflow_ = true;
+      return Handle<Object>::null();
+    }
     do {
       Handle<Object> element = ParseJsonValue();
       if (element.is_null()) return Handle<Object>::null();
@@ -4531,8 +4540,11 @@ static ScriptDataImpl* DoPreParse(Handle<String> source,
                                   int literal_flags) {
   V8JavaScriptScanner scanner;
   scanner.Initialize(source, stream, literal_flags);
-  preparser::PreParser preparser;
-  if (!preparser.PreParseProgram(&scanner, recorder, allow_lazy)) {
+  intptr_t stack_limit = StackGuard::real_climit();
+  if (!preparser::PreParser::PreParseProgram(&scanner,
+                                             recorder,
+                                             allow_lazy,
+                                             stack_limit)) {
     Top::StackOverflow();
     return NULL;
   }
index a067bd7c7dbbde265d76b691b1475d02e55c3b6f..58cd946cad639367d57650283a84a3445576f06d 100644 (file)
@@ -546,8 +546,25 @@ class Parser {
   // Magical syntax support.
   Expression* ParseV8Intrinsic(bool* ok);
 
-  INLINE(Token::Value peek()) { return scanner_.peek(); }
-  INLINE(Token::Value Next()) { return scanner_.NextCheckStack(); }
+  INLINE(Token::Value peek()) {
+    if (stack_overflow_) return Token::ILLEGAL;
+    return scanner_.peek();
+  }
+
+  INLINE(Token::Value Next()) {
+    // BUG 1215673: Find a thread safe way to set a stack limit in
+    // pre-parse mode. Otherwise, we cannot safely pre-parse from other
+    // threads.
+    if (stack_overflow_) {
+      return Token::ILLEGAL;
+    }
+    if (StackLimitCheck().HasOverflowed()) {
+      // Any further calls to Next or peek will return the illegal token.
+      stack_overflow_ = true;
+    }
+    return scanner_.Next();
+  }
+
   INLINE(void Consume(Token::Value token));
   void Expect(Token::Value token, bool* ok);
   bool Check(Token::Value token);
@@ -639,6 +656,7 @@ class Parser {
   bool is_pre_parsing_;
   ScriptDataImpl* pre_data_;
   FuncNameInferrer* fni_;
+  bool stack_overflow_;
 };
 
 
@@ -718,6 +736,7 @@ class JsonParser BASE_EMBEDDED {
   Handle<String> GetString();
 
   JsonScanner scanner_;
+  bool stack_overflow_;
 };
 } }  // namespace v8::internal
 
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
new file mode 100644 (file)
index 0000000..f096e94
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "../include/v8-preparser.h"
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "utils.h"
+#include "list.h"
+#include "scanner-base.h"
+#include "preparse-data.h"
+#include "preparser.h"
+
+namespace v8 {
+namespace internal {
+
+// UTF16Buffer based on a v8::UnicodeInputStream.
+class InputStreamUTF16Buffer : public UTF16Buffer {
+ public:
+  explicit InputStreamUTF16Buffer(UnicodeInputStream* stream)
+      : UTF16Buffer(),
+        stream_(stream) { }
+
+  virtual ~InputStreamUTF16Buffer() { }
+
+  virtual void PushBack(uc32 ch) {
+    stream_->PushBack(ch);
+    pos_--;
+  }
+
+  virtual uc32 Advance() {
+    uc32 result = stream_->Next();
+    if (result >= 0) pos_++;
+    return result;
+  }
+
+  virtual void SeekForward(int pos) {
+    // Seeking in the input is not used by preparsing.
+    // It's only used by the real parser based on preparser data.
+    UNIMPLEMENTED();
+  }
+
+ private:
+  v8::UnicodeInputStream* const stream_;
+};
+
+
+class StandAloneJavaScriptScanner : public JavaScriptScanner {
+ public:
+  void Initialize(UTF16Buffer* source) {
+    source_ = source;
+    literal_flags_ = kLiteralString | kLiteralIdentifier;
+    Init();
+    // Skip initial whitespace allowing HTML comment ends just like
+    // after a newline and scan first token.
+    has_line_terminator_before_next_ = true;
+    SkipWhiteSpace();
+    Scan();
+  }
+};
+
+
+// Functions declared by allocation.h
+
+void FatalProcessOutOfMemory(const char* reason) {
+  V8_Fatal(__FILE__, __LINE__, reason);
+}
+
+bool EnableSlowAsserts() { return true; }
+
+
+}  // namespace internal.
+
+
+UnicodeInputStream::~UnicodeInputStream() { }
+
+
+PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) {
+  internal::InputStreamUTF16Buffer buffer(input);
+  uintptr_t stack_limit = reinterpret_cast<uintptr_t>(&buffer) - max_stack;
+  internal::StandAloneJavaScriptScanner scanner;
+  scanner.Initialize(&buffer);
+  internal::CompleteParserRecorder recorder;
+  preparser::PreParser::PreParseResult result =
+      preparser::PreParser::PreParseProgram(&scanner,
+                                            &recorder,
+                                            true,
+                                            stack_limit);
+  if (result == preparser::PreParser::kPreParseStackOverflow) {
+    return PreParserData::StackOverflow();
+  }
+  internal::Vector<unsigned> pre_data = recorder.ExtractData();
+  size_t size = pre_data.length() * sizeof(pre_data[0]);
+  unsigned char* data = reinterpret_cast<unsigned char*>(pre_data.start());
+  return PreParserData(size, data);
+}
+
+}  // namespace v8.
+
+
+// Used by ASSERT macros and other immediate exits.
+extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
+  exit(EXIT_FAILURE);
+}
index 9061731237e8d168ace9aeaebaf45a91b92df5f2..52421befae91c710ccc0a0950d7a106b0969792d 100644 (file)
@@ -65,7 +65,7 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
   // We don't report stack overflows here, to avoid increasing the
   // stack depth even further.  Instead we report it after parsing is
   // over, in ParseProgram.
-  if (token == i::Token::ILLEGAL && scanner_->stack_overflow()) {
+  if (token == i::Token::ILLEGAL && stack_overflow_) {
     return;
   }
   i::JavaScriptScanner::Location source_location = scanner_->location();
@@ -92,8 +92,8 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
 }
 
 
-SourceElements PreParser::ParseSourceElements(int end_token,
-                                                            bool* ok) {
+PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
+                                                         bool* ok) {
   // SourceElements ::
   //   (Statement)* <end_token>
 
@@ -104,7 +104,7 @@ SourceElements PreParser::ParseSourceElements(int end_token,
 }
 
 
-Statement PreParser::ParseStatement(bool* ok) {
+PreParser::PreParser::Statement PreParser::ParseStatement(bool* ok) {
   // Statement ::
   //   Block
   //   VariableStatement
@@ -190,7 +190,7 @@ Statement PreParser::ParseStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseFunctionDeclaration(bool* ok) {
+PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
   // FunctionDeclaration ::
   //   'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
   Expect(i::Token::FUNCTION, CHECK_OK);
@@ -204,7 +204,7 @@ Statement PreParser::ParseFunctionDeclaration(bool* ok) {
 // through the API's extension mechanism.  A native function
 // declaration is resolved by looking up the function through a
 // callback provided by the extension.
-Statement PreParser::ParseNativeDeclaration(bool* ok) {
+PreParser::Statement PreParser::ParseNativeDeclaration(bool* ok) {
   Expect(i::Token::NATIVE, CHECK_OK);
   Expect(i::Token::FUNCTION, CHECK_OK);
   ParseIdentifier(CHECK_OK);
@@ -223,7 +223,7 @@ Statement PreParser::ParseNativeDeclaration(bool* ok) {
 }
 
 
-Statement PreParser::ParseBlock(bool* ok) {
+PreParser::Statement PreParser::ParseBlock(bool* ok) {
   // Block ::
   //   '{' Statement* '}'
 
@@ -239,7 +239,7 @@ Statement PreParser::ParseBlock(bool* ok) {
 }
 
 
-Statement PreParser::ParseVariableStatement(bool* ok) {
+PreParser::Statement PreParser::ParseVariableStatement(bool* ok) {
   // VariableStatement ::
   //   VariableDeclarations ';'
 
@@ -254,9 +254,9 @@ Statement PreParser::ParseVariableStatement(bool* ok) {
 // *var is untouched; in particular, it is the caller's responsibility
 // to initialize it properly. This mechanism is also used for the parsing
 // of 'for-in' loops.
-Statement PreParser::ParseVariableDeclarations(bool accept_IN,
-                                                  int* num_decl,
-                                                  bool* ok) {
+PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN,
+                                                          int* num_decl,
+                                                          bool* ok) {
   // VariableDeclarations ::
   //   ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
 
@@ -288,7 +288,7 @@ Statement PreParser::ParseVariableDeclarations(bool accept_IN,
 }
 
 
-Statement PreParser::ParseExpressionOrLabelledStatement(
+PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
     bool* ok) {
   // ExpressionStatement | LabelledStatement ::
   //   Expression ';'
@@ -305,7 +305,7 @@ Statement PreParser::ParseExpressionOrLabelledStatement(
 }
 
 
-Statement PreParser::ParseIfStatement(bool* ok) {
+PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
   // IfStatement ::
   //   'if' '(' Expression ')' Statement ('else' Statement)?
 
@@ -322,7 +322,7 @@ Statement PreParser::ParseIfStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseContinueStatement(bool* ok) {
+PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
   // ContinueStatement ::
   //   'continue' [no line terminator] Identifier? ';'
 
@@ -339,7 +339,7 @@ Statement PreParser::ParseContinueStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseBreakStatement(bool* ok) {
+PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
   // BreakStatement ::
   //   'break' [no line terminator] Identifier? ';'
 
@@ -356,7 +356,7 @@ Statement PreParser::ParseBreakStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseReturnStatement(bool* ok) {
+PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
   // ReturnStatement ::
   //   'return' [no line terminator] Expression? ';'
 
@@ -382,7 +382,7 @@ Statement PreParser::ParseReturnStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseWithStatement(bool* ok) {
+PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
   // WithStatement ::
   //   'with' '(' Expression ')' Statement
   Expect(i::Token::WITH, CHECK_OK);
@@ -397,7 +397,7 @@ Statement PreParser::ParseWithStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseSwitchStatement(bool* ok) {
+PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
   // SwitchStatement ::
   //   'switch' '(' Expression ')' '{' CaseClause* '}'
 
@@ -427,7 +427,7 @@ Statement PreParser::ParseSwitchStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseDoWhileStatement(bool* ok) {
+PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
   // DoStatement ::
   //   'do' Statement 'while' '(' Expression ')' ';'
 
@@ -441,7 +441,7 @@ Statement PreParser::ParseDoWhileStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseWhileStatement(bool* ok) {
+PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
   // WhileStatement ::
   //   'while' '(' Expression ')' Statement
 
@@ -454,7 +454,7 @@ Statement PreParser::ParseWhileStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseForStatement(bool* ok) {
+PreParser::Statement PreParser::ParseForStatement(bool* ok) {
   // ForStatement ::
   //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
 
@@ -503,7 +503,7 @@ Statement PreParser::ParseForStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseThrowStatement(bool* ok) {
+PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
   // ThrowStatement ::
   //   'throw' [no line terminator] Expression ';'
 
@@ -522,7 +522,7 @@ Statement PreParser::ParseThrowStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseTryStatement(bool* ok) {
+PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
   // TryStatement ::
   //   'try' Block Catch
   //   'try' Block Finally
@@ -565,7 +565,7 @@ Statement PreParser::ParseTryStatement(bool* ok) {
 }
 
 
-Statement PreParser::ParseDebuggerStatement(bool* ok) {
+PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
   // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
   // contexts this is used as a statement which invokes the debugger as if a
   // break point is present.
@@ -579,7 +579,7 @@ Statement PreParser::ParseDebuggerStatement(bool* ok) {
 
 
 // Precedence = 1
-Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
+PreParser::Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
   // Expression ::
   //   AssignmentExpression
   //   Expression ',' AssignmentExpression
@@ -595,8 +595,8 @@ Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
 
 
 // Precedence = 2
-Expression PreParser::ParseAssignmentExpression(bool accept_IN,
-                                                              bool* ok) {
+PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
+                                                           bool* ok) {
   // AssignmentExpression ::
   //   ConditionalExpression
   //   LeftHandSideExpression AssignmentOperator AssignmentExpression
@@ -620,8 +620,8 @@ Expression PreParser::ParseAssignmentExpression(bool accept_IN,
 
 
 // Precedence = 3
-Expression PreParser::ParseConditionalExpression(bool accept_IN,
-                                                               bool* ok) {
+PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN,
+                                                            bool* ok) {
   // ConditionalExpression ::
   //   LogicalOrExpression
   //   LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
@@ -649,9 +649,9 @@ int PreParser::Precedence(i::Token::Value tok, bool accept_IN) {
 
 
 // Precedence >= 4
-Expression PreParser::ParseBinaryExpression(int prec,
-                                                          bool accept_IN,
-                                                          bool* ok) {
+PreParser::Expression PreParser::ParseBinaryExpression(int prec,
+                                                       bool accept_IN,
+                                                       bool* ok) {
   Expression result = ParseUnaryExpression(CHECK_OK);
   for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
     // prec1 >= 4
@@ -665,7 +665,7 @@ Expression PreParser::ParseBinaryExpression(int prec,
 }
 
 
-Expression PreParser::ParseUnaryExpression(bool* ok) {
+PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
   // UnaryExpression ::
   //   PostfixExpression
   //   'delete' UnaryExpression
@@ -689,7 +689,7 @@ Expression PreParser::ParseUnaryExpression(bool* ok) {
 }
 
 
-Expression PreParser::ParsePostfixExpression(bool* ok) {
+PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
   // PostfixExpression ::
   //   LeftHandSideExpression ('++' | '--')?
 
@@ -703,7 +703,7 @@ Expression PreParser::ParsePostfixExpression(bool* ok) {
 }
 
 
-Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
+PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
   // LeftHandSideExpression ::
   //   (NewExpression | MemberExpression) ...
 
@@ -752,7 +752,7 @@ Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
 }
 
 
-Expression PreParser::ParseNewExpression(bool* ok) {
+PreParser::Expression PreParser::ParseNewExpression(bool* ok) {
   // NewExpression ::
   //   ('new')+ MemberExpression
 
@@ -774,12 +774,12 @@ Expression PreParser::ParseNewExpression(bool* ok) {
 }
 
 
-Expression PreParser::ParseMemberExpression(bool* ok) {
+PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
   return ParseMemberWithNewPrefixesExpression(0, ok);
 }
 
 
-Expression PreParser::ParseMemberWithNewPrefixesExpression(
+PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
     unsigned new_count, bool* ok) {
   // MemberExpression ::
   //   (PrimaryExpression | FunctionLiteral)
@@ -835,7 +835,7 @@ Expression PreParser::ParseMemberWithNewPrefixesExpression(
 }
 
 
-Expression PreParser::ParsePrimaryExpression(bool* ok) {
+PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
   // PrimaryExpression ::
   //   'this'
   //   'null'
@@ -914,7 +914,7 @@ Expression PreParser::ParsePrimaryExpression(bool* ok) {
 }
 
 
-Expression PreParser::ParseArrayLiteral(bool* ok) {
+PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
   // ArrayLiteral ::
   //   '[' Expression? (',' Expression?)* ']'
   Expect(i::Token::LBRACK, CHECK_OK);
@@ -933,7 +933,7 @@ Expression PreParser::ParseArrayLiteral(bool* ok) {
 }
 
 
-Expression PreParser::ParseObjectLiteral(bool* ok) {
+PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
   // ObjectLiteral ::
   //   '{' (
   //       ((IdentifierName | String | Number) ':' AssignmentExpression)
@@ -995,8 +995,8 @@ Expression PreParser::ParseObjectLiteral(bool* ok) {
 }
 
 
-Expression PreParser::ParseRegExpLiteral(bool seen_equal,
-                                         bool* ok) {
+PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
+                                                    bool* ok) {
   if (!scanner_->ScanRegExpPattern(seen_equal)) {
     Next();
     i::JavaScriptScanner::Location location = scanner_->location();
@@ -1021,7 +1021,7 @@ Expression PreParser::ParseRegExpLiteral(bool seen_equal,
 }
 
 
-Arguments PreParser::ParseArguments(bool* ok) {
+PreParser::Arguments PreParser::ParseArguments(bool* ok) {
   // Arguments ::
   //   '(' (AssignmentExpression)*[','] ')'
 
@@ -1039,7 +1039,7 @@ Arguments PreParser::ParseArguments(bool* ok) {
 }
 
 
-Expression PreParser::ParseFunctionLiteral(bool* ok) {
+PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
   // Function ::
   //   '(' FormalParameterList? ')' '{' FunctionBody '}'
 
@@ -1090,7 +1090,7 @@ Expression PreParser::ParseFunctionLiteral(bool* ok) {
 }
 
 
-Expression PreParser::ParseV8Intrinsic(bool* ok) {
+PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
   // CallRuntime ::
   //   '%' Identifier Arguments
 
@@ -1119,7 +1119,7 @@ void PreParser::ExpectSemicolon(bool* ok) {
 }
 
 
-Identifier PreParser::GetIdentifierSymbol() {
+PreParser::Identifier PreParser::GetIdentifierSymbol() {
   const char* literal_chars = scanner_->literal_string();
   int literal_length = scanner_->literal_length();
   int identifier_pos = scanner_->location().beg_pos;
@@ -1130,7 +1130,7 @@ Identifier PreParser::GetIdentifierSymbol() {
 }
 
 
-Expression PreParser::GetStringSymbol() {
+PreParser::Expression PreParser::GetStringSymbol() {
   const char* literal_chars = scanner_->literal_string();
   int literal_length = scanner_->literal_length();
 
@@ -1141,14 +1141,14 @@ Expression PreParser::GetStringSymbol() {
 }
 
 
-Identifier PreParser::ParseIdentifier(bool* ok) {
+PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
   Expect(i::Token::IDENTIFIER, ok);
   if (!*ok) return kUnknownIdentifier;
   return GetIdentifierSymbol();
 }
 
 
-Identifier PreParser::ParseIdentifierName(bool* ok) {
+PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
   i::Token::Value next = Next();
   if (i::Token::IsKeyword(next)) {
     int pos = scanner_->location().beg_pos;
@@ -1168,9 +1168,9 @@ Identifier PreParser::ParseIdentifierName(bool* ok) {
 // is 'get' or 'set'.  The reason for not using ParseIdentifier and
 // checking on the output is that this involves heap allocation which
 // we can't do during preparsing.
-Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
-                                                bool* is_set,
-                                                bool* ok) {
+PreParser::Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
+                                                           bool* is_set,
+                                                           bool* ok) {
   Expect(i::Token::IDENTIFIER, CHECK_OK);
   if (scanner_->literal_length() == 3) {
     const char* token = scanner_->literal_string();
index b783d65db32468c6395a76ecd046399cd6d851c6..893b575198bf0cf0cdd775d458ca310d1cddae76 100644 (file)
@@ -46,56 +46,24 @@ namespace preparser {
 
 namespace i = v8::internal;
 
-enum StatementType {
-  kUnknownStatement
-};
-
-enum ExpressionType {
-  kUnknownExpression,
-  kIdentifierExpression,  // Used to detect labels.
-  kThisExpression,
-  kThisPropertyExpression
-};
-
-enum IdentifierType {
-  kUnknownIdentifier
-};
-
-enum SourceElementTypes {
-  kUnknownSourceElements
-};
-
-
-typedef int SourceElements;
-typedef int Expression;
-typedef int Statement;
-typedef int Identifier;
-typedef int Arguments;
-
-
 class PreParser {
  public:
-  PreParser() : scope_(NULL), allow_lazy_(true) { }
+  enum PreParseResult {
+    kPreParseStackOverflow,
+    kPreParseSuccess
+  };
+
   ~PreParser() { }
 
   // Pre-parse the program from the character stream; returns true on
   // success (even if parsing failed, the pre-parse data successfully
   // captured the syntax error), and false if a stack-overflow happened
   // during parsing.
-  bool PreParseProgram(i::JavaScriptScanner* scanner,
-                       i::ParserRecorder* log,
-                       bool allow_lazy) {
-    allow_lazy_ = allow_lazy;
-    scanner_ = scanner;
-    log_ = log;
-    Scope top_scope(&scope_, kTopLevelScope);
-    bool ok = true;
-    ParseSourceElements(i::Token::EOS, &ok);
-    bool stack_overflow = scanner_->stack_overflow();
-    if (!ok && !stack_overflow) {
-      ReportUnexpectedToken(scanner_->current_token());
-    }
-    return !stack_overflow;
+  static PreParseResult PreParseProgram(i::JavaScriptScanner* scanner,
+                                        i::ParserRecorder* log,
+                                        bool allow_lazy,
+                                        uintptr_t stack_limit) {
+    return PreParser(scanner, log, stack_limit, allow_lazy).PreParse();
   }
 
  private:
@@ -104,6 +72,38 @@ class PreParser {
     kFunctionScope
   };
 
+  // Types that allow us to recognize simple this-property assignments.
+  // A simple this-property assignment is a statement on the form
+  // "this.propertyName = {primitive constant or function parameter name);"
+  // where propertyName isn't "__proto__".
+  // The result is only relevant if the function body contains only
+  // simple this-property assignments.
+
+  enum StatementType {
+    kUnknownStatement
+  };
+
+  enum ExpressionType {
+    kUnknownExpression,
+    kIdentifierExpression,  // Used to detect labels.
+    kThisExpression,
+    kThisPropertyExpression
+  };
+
+  enum IdentifierType {
+    kUnknownIdentifier
+  };
+
+  enum SourceElementTypes {
+    kUnknownSourceElements
+  };
+
+  typedef int SourceElements;
+  typedef int Expression;
+  typedef int Statement;
+  typedef int Identifier;
+  typedef int Arguments;
+
   class Scope {
    public:
     Scope(Scope** variable, ScopeType type)
@@ -134,12 +134,30 @@ class PreParser {
     int with_nesting_count_;
   };
 
-  // Types that allow us to recognize simple this-property assignments.
-  // A simple this-property assignment is a statement on the form
-  // "this.propertyName = {primitive constant or function parameter name);"
-  // where propertyName isn't "__proto__".
-  // The result is only relevant if the function body contains only
-  // simple this-property assignments.
+  // Private constructor only used in PreParseProgram.
+  PreParser(i::JavaScriptScanner* scanner,
+            i::ParserRecorder* log,
+            uintptr_t stack_limit,
+            bool allow_lazy)
+      : scanner_(scanner),
+        log_(log),
+        scope_(NULL),
+        stack_limit_(stack_limit),
+        stack_overflow_(false),
+        allow_lazy_(true) { }
+
+  // Preparse the program. Only called in PreParseProgram after creating
+  // the instance.
+  PreParseResult PreParse() {
+    Scope top_scope(&scope_, kTopLevelScope);
+    bool ok = true;
+    ParseSourceElements(i::Token::EOS, &ok);
+    if (stack_overflow_) return kPreParseStackOverflow;
+    if (!ok) {
+      ReportUnexpectedToken(scanner_->current_token());
+    }
+    return kPreParseSuccess;
+  }
 
   // Report syntax error
   void ReportUnexpectedToken(i::Token::Value token);
@@ -202,16 +220,26 @@ class PreParser {
   unsigned int HexDigitValue(char digit);
   Expression GetStringSymbol();
 
+  i::Token::Value peek() {
+    if (stack_overflow_) return i::Token::ILLEGAL;
+    return scanner_->peek();
+  }
 
-  i::Token::Value peek() { return scanner_->peek(); }
   i::Token::Value Next() {
-    i::Token::Value next = scanner_->Next();
-    return next;
+    if (stack_overflow_) return i::Token::ILLEGAL;
+    {
+      int marker;
+      if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
+        // Further calls to peek/Next will return illegal token.
+        // The current one will still be returned. It might already
+        // have been seen using peek.
+        stack_overflow_ = true;
+      }
+    }
+    return scanner_->Next();
   }
 
-  void Consume(i::Token::Value token) {
-    Next();
-  }
+  void Consume(i::Token::Value token) { Next(); }
 
   void Expect(i::Token::Value token, bool* ok) {
     if (Next() != token) {
@@ -234,6 +262,8 @@ class PreParser {
   i::JavaScriptScanner* scanner_;
   i::ParserRecorder* log_;
   Scope* scope_;
+  uintptr_t stack_limit_;
+  bool stack_overflow_;
   bool allow_lazy_;
 };
 } }  // v8::preparser
index 8242f81c3f11dedc982c63f06dd3e587f0283de3..9e58c4e6371d746fe4ef523701c14015390be70f 100644 (file)
@@ -92,7 +92,7 @@ bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) {
 // ----------------------------------------------------------------------------
 // Scanner
 
-Scanner::Scanner() : source_(NULL), stack_overflow_(false) {}
+Scanner::Scanner() : source_(NULL) {}
 
 
 uc32 Scanner::ScanHexEscape(uc32 c, int length) {
index 3714ae2d1bc626ad2a2127b3fe5dcc6b86cef84b..3d344f306ca0953e479ee90fe5446e0b999243f3 100644 (file)
@@ -228,8 +228,6 @@ class Scanner {
     return Vector<const char>(next_literal_string(), next_literal_length());
   }
 
-  bool stack_overflow() { return stack_overflow_; }
-
   static const int kCharacterLookaheadBufferSize = 1;
 
  protected:
@@ -316,8 +314,6 @@ class Scanner {
   // using '\x00'-terminated UTF-8 encoding. Handles allocation internally.
   LiteralCollector literal_buffer_;
 
-  bool stack_overflow_;
-
   // One Unicode character look-ahead; c0_ < 0 at the end of the input.
   uc32 c0_;
 };
index 63b2fd807d4d01eb80527be7a59bbdd15d69e688..d22ebc741fd482d19bcc7b098faf4616ff59dda9 100755 (executable)
@@ -164,22 +164,6 @@ void V8JavaScriptScanner::Initialize(Handle<String> source,
 }
 
 
-Token::Value V8JavaScriptScanner::NextCheckStack() {
-  // BUG 1215673: Find a thread safe way to set a stack limit in
-  // pre-parse mode. Otherwise, we cannot safely pre-parse from other
-  // threads.
-  StackLimitCheck check;
-  if (check.HasOverflowed()) {
-    stack_overflow_ = true;
-    current_ = next_;
-    next_.token = Token::ILLEGAL;
-    return current_.token;
-  } else {
-    return Next();
-  }
-}
-
-
 UTF16Buffer* StreamInitializer::Init(Handle<String> source,
                                      unibrow::CharacterStream* stream,
                                      int start_position,
@@ -236,13 +220,7 @@ Token::Value JsonScanner::Next() {
   // threads.
   current_ = next_;
   // Check for stack-overflow before returning any tokens.
-  StackLimitCheck check;
-  if (check.HasOverflowed()) {
-    stack_overflow_ = true;
-    next_.token = Token::ILLEGAL;
-  } else {
-    ScanJson();
-  }
+  ScanJson();
   return current_.token;
 }
 
index acb9b47bd99cf9c3f848d4fdf7d74a3dc05da6b8..adeea9b23a00d50d7f07a9203dcc311fd50cebe4 100644 (file)
@@ -105,8 +105,6 @@ class V8JavaScriptScanner : public JavaScriptScanner {
  public:
   V8JavaScriptScanner() {}
 
-  Token::Value NextCheckStack();
-
   // Initialize the Scanner to scan source.
   void Initialize(Handle<String> source, int literal_flags = kAllLiterals);
   void Initialize(Handle<String> source,
index a93fc2712d33e8ab14ee86167301d7f04ebe96da..badbab5eeb1614bd487489a835ca92cebcc4d2e0 100755 (executable)
@@ -257,15 +257,20 @@ TEST(StandAlonePreParser) {
       NULL
   };
 
+  uintptr_t stack_limit = i::StackGuard::real_climit();
   for (int i = 0; programs[i]; i++) {
     const char* program = programs[i];
     unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
     i::CompleteParserRecorder log;
     i::V8JavaScriptScanner scanner;
     scanner.Initialize(i::Handle<i::String>::null(), &stream);
-    v8::preparser::PreParser preparser;
-    bool result = preparser.PreParseProgram(&scanner, &log, true);
-    CHECK(result);
+
+    v8::preparser::PreParser::PreParseResult result =
+        v8::preparser::PreParser::PreParseProgram(&scanner,
+                                                  &log,
+                                                  true,
+                                                  stack_limit);
+    CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
     i::ScriptDataImpl data(log.ExtractData());
     CHECK(!data.has_error());
   }
@@ -327,3 +332,31 @@ TEST(Regress928) {
   CHECK_EQ('}', program[entry2.end_pos() - 1]);
   delete data;
 }
+
+
+TEST(PreParseOverflow) {
+  int marker;
+  i::StackGuard::SetStackLimit(
+      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+  size_t kProgramSize = 1024 * 1024;
+  i::SmartPointer<char> program(
+      reinterpret_cast<char*>(malloc(kProgramSize + 1)));
+  memset(*program, '(', kProgramSize);
+  program[kProgramSize] = '\0';
+
+  uintptr_t stack_limit = i::StackGuard::real_climit();
+
+  unibrow::Utf8InputBuffer<256> stream(*program, strlen(*program));
+  i::CompleteParserRecorder log;
+  i::V8JavaScriptScanner scanner;
+  scanner.Initialize(i::Handle<i::String>::null(), &stream);
+
+
+  v8::preparser::PreParser::PreParseResult result =
+      v8::preparser::PreParser::PreParseProgram(&scanner,
+                                                &log,
+                                                true,
+                                                stack_limit);
+  CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
+}