Refactor ScriptData class for cached compile data.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 10 Jul 2014 10:28:05 +0000 (10:28 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 10 Jul 2014 10:28:05 +0000 (10:28 +0000)
R=marja@chromium.org, vogelheim@chromium.org

Review URL: https://codereview.chromium.org/376223002

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

17 files changed:
include/v8.h
src/api.cc
src/compiler.cc
src/compiler.h
src/messages.js
src/mksnapshot.cc
src/parser.cc
src/parser.h
src/preparse-data.cc
src/preparse-data.h
src/serialize.cc
src/serialize.h
src/snapshot-source-sink.cc
src/snapshot-source-sink.h
test/cctest/test-api.cc
test/cctest/test-parsing.cc
test/cctest/test-serialize.cc

index 11bf598..82d5784 100644 (file)
@@ -1087,6 +1087,12 @@ class V8_EXPORT ScriptCompiler {
 
   /**
    * Compiles the specified script (context-independent).
+   * Cached data as part of the source object can be optionally produced to be
+   * consumed later to speed up compilation of identical source scripts.
+   *
+   * Note that when producing cached data, the source must point to NULL for
+   * cached data. When consuming cached data, the cached data must have been
+   * produced by the same version of V8.
    *
    * \param source Script source code.
    * \return Compiled script object (context independent; for running it must be
index d01d826..106c1fd 100644 (file)
@@ -1699,43 +1699,19 @@ Local<UnboundScript> ScriptCompiler::CompileUnbound(
     Isolate* v8_isolate,
     Source* source,
     CompileOptions options) {
-  i::ScriptData* script_data_impl = NULL;
+  i::ScriptData* script_data = NULL;
   i::CachedDataMode cached_data_mode = i::NO_CACHED_DATA;
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
   ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
              return Local<UnboundScript>());
   if (options & kProduceDataToCache) {
     cached_data_mode = i::PRODUCE_CACHED_DATA;
-    ASSERT(source->cached_data == NULL);
-    if (source->cached_data) {
-      // Asked to produce cached data even though there is some already -> not
-      // good. Fail the compilation.
-      EXCEPTION_PREAMBLE(isolate);
-      i::Handle<i::Object> result = isolate->factory()->NewSyntaxError(
-          "invalid_cached_data", isolate->factory()->NewJSArray(0));
-      isolate->Throw(*result);
-      isolate->ReportPendingMessages();
-      has_pending_exception = true;
-      EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
-    }
+    CHECK(source->cached_data == NULL);
   } else if (source->cached_data) {
     cached_data_mode = i::CONSUME_CACHED_DATA;
-    // ScriptData takes care of aligning, in case the data is not aligned
-    // correctly.
-    script_data_impl = i::ScriptData::New(
-        reinterpret_cast<const char*>(source->cached_data->data),
-        source->cached_data->length);
-    // If the cached data is not valid, fail the compilation.
-    if (script_data_impl == NULL || !script_data_impl->SanityCheck()) {
-      EXCEPTION_PREAMBLE(isolate);
-      i::Handle<i::Object> result = isolate->factory()->NewSyntaxError(
-          "invalid_cached_data", isolate->factory()->NewJSArray(0));
-      isolate->Throw(*result);
-      isolate->ReportPendingMessages();
-      delete script_data_impl;
-      has_pending_exception = true;
-      EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
-    }
+    // ScriptData takes care of pointer-aligning the data.
+    script_data = new i::ScriptData(source->cached_data->data,
+                                    source->cached_data->length);
   }
 
   i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
@@ -1763,36 +1739,28 @@ Local<UnboundScript> ScriptCompiler::CompileUnbound(
           source->resource_is_shared_cross_origin == v8::True(v8_isolate);
     }
     EXCEPTION_PREAMBLE(isolate);
-    i::Handle<i::SharedFunctionInfo> result =
-        i::Compiler::CompileScript(str,
-                                   name_obj,
-                                   line_offset,
-                                   column_offset,
-                                   is_shared_cross_origin,
-                                   isolate->global_context(),
-                                   NULL,
-                                   &script_data_impl,
-                                   cached_data_mode,
-                                   i::NOT_NATIVES_CODE);
+    i::Handle<i::SharedFunctionInfo> result = i::Compiler::CompileScript(
+        str, name_obj, line_offset, column_offset, is_shared_cross_origin,
+        isolate->global_context(), NULL, &script_data, cached_data_mode,
+        i::NOT_NATIVES_CODE);
     has_pending_exception = result.is_null();
     if (has_pending_exception && cached_data_mode == i::CONSUME_CACHED_DATA) {
       // This case won't happen during normal operation; we have compiled
       // successfully and produced cached data, and but the second compilation
       // of the same source code fails.
-      delete script_data_impl;
-      script_data_impl = NULL;
+      delete script_data;
+      script_data = NULL;
     }
     EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
     raw_result = *result;
-    if ((options & kProduceDataToCache) && script_data_impl != NULL) {
+    if ((options & kProduceDataToCache) && script_data != NULL) {
       // script_data_impl now contains the data that was generated. source will
       // take the ownership.
       source->cached_data = new CachedData(
-          reinterpret_cast<const uint8_t*>(script_data_impl->Data()),
-          script_data_impl->Length(), CachedData::BufferOwned);
-      script_data_impl->owns_store_ = false;
+          script_data->data(), script_data->length(), CachedData::BufferOwned);
+      script_data->ReleaseDataOwnership();
     }
-    delete script_data_impl;
+    delete script_data;
   }
   i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
   return ToApiHandle<UnboundScript>(result);
index 59c6a36..00c2667 100644 (file)
@@ -31,6 +31,18 @@ namespace v8 {
 namespace internal {
 
 
+ScriptData::ScriptData(const byte* data, int length)
+    : owns_data_(false), data_(data), length_(length) {
+  if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
+    byte* copy = NewArray<byte>(length);
+    ASSERT(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment));
+    CopyBytes(copy, data, length);
+    data_ = copy;
+    AcquireDataOwnership();
+  }
+}
+
+
 CompilationInfo::CompilationInfo(Handle<Script> script,
                                  Zone* zone)
     : flags_(StrictModeField::encode(SLOPPY)),
index b0c4e11..58fb164 100644 (file)
@@ -13,7 +13,6 @@ namespace v8 {
 namespace internal {
 
 class AstValueFactory;
-class ScriptData;
 class HydrogenCodeStub;
 
 // ParseRestriction is used to restrict the set of valid statements in a
@@ -35,6 +34,36 @@ struct OffsetRange {
   int to;
 };
 
+
+class ScriptData {
+ public:
+  ScriptData(const byte* data, int length);
+  ~ScriptData() {
+    if (owns_data_) DeleteArray(data_);
+  }
+
+  const byte* data() const { return data_; }
+  int length() const { return length_; }
+
+  void AcquireDataOwnership() {
+    ASSERT(!owns_data_);
+    owns_data_ = true;
+  }
+
+  void ReleaseDataOwnership() {
+    ASSERT(owns_data_);
+    owns_data_ = false;
+  }
+
+ private:
+  bool owns_data_;
+  const byte* data_;
+  int length_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptData);
+};
+
+
 // CompilationInfo encapsulates some information known at compile time.  It
 // is constructed based on the resources available at compile-time.
 class CompilationInfo {
@@ -722,7 +751,6 @@ class CompilationPhase BASE_EMBEDDED {
   DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
 };
 
-
 } }  // namespace v8::internal
 
 #endif  // V8_COMPILER_H_
index e3d941b..815f97a 100644 (file)
@@ -137,8 +137,6 @@ var kMessages = {
   array_indexof_not_defined:     ["Array.getIndexOf: Argument undefined"],
   object_not_extensible:         ["Can't add property ", "%0", ", object is not extensible"],
   illegal_access:                ["Illegal access"],
-  invalid_cached_data_function:  ["Invalid cached data for function ", "%0"],
-  invalid_cached_data:           ["Invalid cached data"],
   strict_mode_with:              ["Strict mode code may not include a with statement"],
   strict_eval_arguments:         ["Unexpected eval or arguments in strict mode"],
   too_many_arguments:            ["Too many arguments in function call (only 65535 allowed)"],
index 36c0376..57880e2 100644 (file)
@@ -27,8 +27,8 @@ using namespace v8;
 class Compressor {
  public:
   virtual ~Compressor() {}
-  virtual bool Compress(i::Vector<char> input) = 0;
-  virtual i::Vector<char>* output() = 0;
+  virtual bool Compress(i::Vector<i::byte> input) = 0;
+  virtual i::Vector<i::byte>* output() = 0;
 };
 
 
@@ -63,9 +63,9 @@ class SnapshotWriter {
       startup_blob_file_ = GetFileDescriptorOrDie(startup_blob_file);
   }
 
-  void WriteSnapshot(const i::List<char>& snapshot_data,
+  void WriteSnapshot(const i::List<i::byte>& snapshot_data,
                      const i::Serializer& serializer,
-                     const i::List<char>& context_snapshot_data,
+                     const i::List<i::byte>& context_snapshot_data,
                      const i::Serializer& context_serializer) const {
     WriteSnapshotFile(snapshot_data, serializer,
                       context_snapshot_data, context_serializer);
@@ -74,14 +74,14 @@ class SnapshotWriter {
   }
 
  private:
-  void MaybeWriteStartupBlob(const i::List<char>& snapshot_data,
+  void MaybeWriteStartupBlob(const i::List<i::byte>& snapshot_data,
                              const i::Serializer& serializer,
-                             const i::List<char>& context_snapshot_data,
+                             const i::List<i::byte>& context_snapshot_data,
                              const i::Serializer& context_serializer) const {
     if (!startup_blob_file_)
       return;
 
-    i::List<char> startup_blob;
+    i::List<i::byte> startup_blob;
     i::ListSnapshotSink sink(&startup_blob);
 
     int spaces[] = {
@@ -89,13 +89,12 @@ class SnapshotWriter {
         i::MAP_SPACE, i::CELL_SPACE,  i::PROPERTY_CELL_SPACE
     };
 
-    i::byte* snapshot_bytes = reinterpret_cast<i::byte*>(snapshot_data.begin());
+    i::byte* snapshot_bytes = snapshot_data.begin();
     sink.PutBlob(snapshot_bytes, snapshot_data.length(), "snapshot");
     for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i)
       sink.PutInt(serializer.CurrentAllocationAddress(spaces[i]), "spaces");
 
-    i::byte* context_bytes =
-        reinterpret_cast<i::byte*>(context_snapshot_data.begin());
+    i::byte* context_bytes = context_snapshot_data.begin();
     sink.PutBlob(context_bytes, context_snapshot_data.length(), "context");
     for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i)
       sink.PutInt(context_serializer.CurrentAllocationAddress(spaces[i]),
@@ -109,9 +108,9 @@ class SnapshotWriter {
     }
   }
 
-  void WriteSnapshotFile(const i::List<char>& snapshot_data,
+  void WriteSnapshotFile(const i::List<i::byte>& snapshot_data,
                          const i::Serializer& serializer,
-                         const i::List<char>& context_snapshot_data,
+                         const i::List<i::byte>& context_snapshot_data,
                          const i::Serializer& context_serializer) const {
     WriteFilePrefix();
     WriteData("", snapshot_data, raw_file_);
@@ -135,11 +134,10 @@ class SnapshotWriter {
     fprintf(fp_, "}  // namespace v8\n");
   }
 
-  void WriteData(const char* prefix,
-                 const i::List<char>& source_data,
+  void WriteData(const char* prefix, const i::List<i::byte>& source_data,
                  FILE* raw_file) const {
-    const i::List <char>* data_to_be_written = NULL;
-    i::List<char> compressed_data;
+    const i::List<i::byte>* data_to_be_written = NULL;
+    i::List<i::byte> compressed_data;
     if (!compressor_) {
       data_to_be_written = &source_data;
     } else if (compressor_->Compress(source_data.ToVector())) {
@@ -155,7 +153,7 @@ class SnapshotWriter {
     WriteData(prefix, source_data, data_to_be_written);
   }
 
-  void MaybeWriteRawFile(const i::List<char>* data, FILE* raw_file) const {
+  void MaybeWriteRawFile(const i::List<i::byte>* data, FILE* raw_file) const {
     if (!data || !raw_file)
       return;
 
@@ -170,9 +168,8 @@ class SnapshotWriter {
     }
   }
 
-  void WriteData(const char* prefix,
-                 const i::List<char>& source_data,
-                 const i::List<char>* data_to_be_written) const {
+  void WriteData(const char* prefix, const i::List<i::byte>& source_data,
+                 const i::List<i::byte>* data_to_be_written) const {
     fprintf(fp_, "const byte Snapshot::%sdata_[] = {\n", prefix);
     WriteSnapshotData(data_to_be_written);
     fprintf(fp_, "};\n");
@@ -209,7 +206,7 @@ class SnapshotWriter {
             prefix, name, ser.CurrentAllocationAddress(space));
   }
 
-  void WriteSnapshotData(const i::List<char>* data) const {
+  void WriteSnapshotData(const i::List<i::byte>* data) const {
     for (int i = 0; i < data->length(); i++) {
       if ((i & 0x1f) == 0x1f)
         fprintf(fp_, "\n");
@@ -405,12 +402,12 @@ int main(int argc, char** argv) {
 
     // This results in a somewhat smaller snapshot, probably because it gets
     // rid of some things that are cached between garbage collections.
-    i::List<char> snapshot_data;
+    i::List<i::byte> snapshot_data;
     i::ListSnapshotSink snapshot_sink(&snapshot_data);
     i::StartupSerializer ser(internal_isolate, &snapshot_sink);
     ser.SerializeStrongReferences();
 
-    i::List<char> context_data;
+    i::List<i::byte> context_data;
     i::ListSnapshotSink contex_sink(&context_data);
     i::PartialSerializer context_ser(internal_isolate, &ser, &contex_sink);
     context_ser.Serialize(&raw_context);
index 544c8c7..2011ff7 100644 (file)
@@ -182,147 +182,86 @@ void RegExpBuilder::AddQuantifierToAtom(
 }
 
 
-ScriptData* ScriptData::New(const char* data, int length, bool owns_store) {
-  // The length is obviously invalid.
-  if (length % sizeof(unsigned) != 0) {
-    return NULL;
-  }
-
-  int deserialized_data_length = length / sizeof(unsigned);
-  unsigned* deserialized_data;
-  owns_store =
-      owns_store || reinterpret_cast<intptr_t>(data) % sizeof(unsigned) != 0;
-  if (owns_store) {
-    // Copy the data to align it.
-    deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
-    i::CopyBytes(reinterpret_cast<char*>(deserialized_data),
-                 data, static_cast<size_t>(length));
-  } else {
-    // If aligned, don't create a copy of the data.
-    deserialized_data = reinterpret_cast<unsigned*>(const_cast<char*>(data));
-  }
-  return new ScriptData(
-      Vector<unsigned>(deserialized_data, deserialized_data_length),
-      owns_store);
-}
-
-
-FunctionEntry ScriptData::GetFunctionEntry(int start) {
+FunctionEntry ParseData::GetFunctionEntry(int start) {
   // The current pre-data entry must be a FunctionEntry with the given
   // start position.
-  if ((function_index_ + FunctionEntry::kSize <= store_.length())
-      && (static_cast<int>(store_[function_index_]) == start)) {
+  if ((function_index_ + FunctionEntry::kSize <= Length()) &&
+      (static_cast<int>(Data()[function_index_]) == start)) {
     int index = function_index_;
     function_index_ += FunctionEntry::kSize;
-    return FunctionEntry(store_.SubVector(index,
-                                          index + FunctionEntry::kSize));
+    Vector<unsigned> subvector(&(Data()[index]), FunctionEntry::kSize);
+    return FunctionEntry(subvector);
   }
   return FunctionEntry();
 }
 
 
-int ScriptData::GetSymbolIdentifier() {
-  return ReadNumber(&symbol_data_);
+int ParseData::FunctionCount() {
+  int functions_size = FunctionsSize();
+  if (functions_size < 0) return 0;
+  if (functions_size % FunctionEntry::kSize != 0) return 0;
+  return functions_size / FunctionEntry::kSize;
 }
 
 
-bool ScriptData::SanityCheck() {
+bool ParseData::IsSane() {
   // Check that the header data is valid and doesn't specify
   // point to positions outside the store.
-  if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
-  if (magic() != PreparseDataConstants::kMagicNumber) return false;
-  if (version() != PreparseDataConstants::kCurrentVersion) return false;
-  if (has_error()) {
-    // Extra sane sanity check for error message encoding.
-    if (store_.length() <= PreparseDataConstants::kHeaderSize
-                         + PreparseDataConstants::kMessageTextPos) {
-      return false;
-    }
-    if (Read(PreparseDataConstants::kMessageStartPos) >
-        Read(PreparseDataConstants::kMessageEndPos)) {
-      return false;
-    }
-    unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
-    int pos = PreparseDataConstants::kMessageTextPos;
-    for (unsigned int i = 0; i <= arg_count; i++) {
-      if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
-        return false;
-      }
-      int length = static_cast<int>(Read(pos));
-      if (length < 0) return false;
-      pos += 1 + length;
-    }
-    if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
-      return false;
-    }
-    return true;
-  }
+  int data_length = Length();
+  if (data_length < PreparseDataConstants::kHeaderSize) return false;
+  if (Magic() != PreparseDataConstants::kMagicNumber) return false;
+  if (Version() != PreparseDataConstants::kCurrentVersion) return false;
+  if (HasError()) return false;
   // Check that the space allocated for function entries is sane.
-  int functions_size =
-      static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
+  int functions_size = FunctionsSize();
   if (functions_size < 0) return false;
   if (functions_size % FunctionEntry::kSize != 0) return false;
   // Check that the total size has room for header and function entries.
   int minimum_size =
       PreparseDataConstants::kHeaderSize + functions_size;
-  if (store_.length() < minimum_size) return false;
+  if (data_length < minimum_size) return false;
   return true;
 }
 
 
-
-const char* ScriptData::ReadString(unsigned* start, int* chars) {
-  int length = start[0];
-  char* result = NewArray<char>(length + 1);
-  for (int i = 0; i < length; i++) {
-    result[i] = start[i + 1];
+void ParseData::Initialize() {
+  // Prepares state for use.
+  int data_length = Length();
+  if (data_length >= PreparseDataConstants::kHeaderSize) {
+    function_index_ = PreparseDataConstants::kHeaderSize;
   }
-  result[length] = '\0';
-  if (chars != NULL) *chars = length;
-  return result;
-}
-
-
-Scanner::Location ScriptData::MessageLocation() const {
-  int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
-  int end_pos = Read(PreparseDataConstants::kMessageEndPos);
-  return Scanner::Location(beg_pos, end_pos);
 }
 
 
-bool ScriptData::IsReferenceError() const {
-  return Read(PreparseDataConstants::kIsReferenceErrorPos);
+bool ParseData::HasError() {
+  return Data()[PreparseDataConstants::kHasErrorOffset];
 }
 
 
-const char* ScriptData::BuildMessage() const {
-  unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
-  return ReadString(start, NULL);
+unsigned ParseData::Magic() {
+  return Data()[PreparseDataConstants::kMagicOffset];
 }
 
 
-const char* ScriptData::BuildArg() const {
-  int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
-  ASSERT(arg_count == 0 || arg_count == 1);
-  if (arg_count == 0) {
-    return NULL;
-  }
-  // Position after text found by skipping past length field and
-  // length field content words.
-  int pos = PreparseDataConstants::kMessageTextPos + 1
-      + Read(PreparseDataConstants::kMessageTextPos);
-  int count = 0;
-  return ReadString(ReadAddress(pos), &count);
+unsigned ParseData::Version() {
+  return Data()[PreparseDataConstants::kVersionOffset];
 }
 
 
-unsigned ScriptData::Read(int position) const {
-  return store_[PreparseDataConstants::kHeaderSize + position];
+int ParseData::FunctionsSize() {
+  return static_cast<int>(Data()[PreparseDataConstants::kFunctionsSizeOffset]);
 }
 
 
-unsigned* ScriptData::ReadAddress(int position) const {
-  return &store_[PreparseDataConstants::kHeaderSize + position];
+void Parser::SetCachedData() {
+  if (cached_data_mode() == NO_CACHED_DATA) {
+    cached_parse_data_ = NULL;
+  } else {
+    ASSERT(info_->cached_data() != NULL);
+    if (cached_data_mode() == CONSUME_CACHED_DATA) {
+      cached_parse_data_ = new ParseData(*info_->cached_data());
+    }
+  }
 }
 
 
@@ -757,18 +696,14 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral(
 Parser::Parser(CompilationInfo* info)
     : ParserBase<ParserTraits>(&scanner_,
                                info->isolate()->stack_guard()->real_climit(),
-                               info->extension(),
-                               NULL,
-                               info->zone(),
-                               this),
+                               info->extension(), NULL, info->zone(), this),
       isolate_(info->isolate()),
       script_(info->script()),
       scanner_(isolate_->unicode_cache()),
       reusable_preparser_(NULL),
       original_scope_(NULL),
       target_stack_(NULL),
-      cached_data_(NULL),
-      cached_data_mode_(NO_CACHED_DATA),
+      cached_parse_data_(NULL),
       ast_value_factory_(NULL),
       info_(info),
       has_pending_error_(false),
@@ -805,10 +740,10 @@ FunctionLiteral* Parser::ParseProgram() {
 
   // Initialize parser state.
   CompleteParserRecorder recorder;
-  if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+  if (cached_data_mode() == PRODUCE_CACHED_DATA) {
     log_ = &recorder;
-  } else if (cached_data_mode_ == CONSUME_CACHED_DATA) {
-    (*cached_data_)->Initialize();
+  } else if (cached_data_mode() == CONSUME_CACHED_DATA) {
+    cached_parse_data_->Initialize();
   }
 
   source = String::Flatten(source);
@@ -840,11 +775,8 @@ FunctionLiteral* Parser::ParseProgram() {
     }
     PrintF(" - took %0.3f ms]\n", ms);
   }
-  if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
-    if (result != NULL) {
-      Vector<unsigned> store = recorder.ExtractData();
-      *cached_data_ = new ScriptData(store);
-    }
+  if (cached_data_mode() == PRODUCE_CACHED_DATA) {
+    if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
     log_ = NULL;
   }
   return result;
@@ -3292,12 +3224,6 @@ DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
 }
 
 
-void Parser::ReportInvalidCachedData(const AstRawString* name, bool* ok) {
-  ParserTraits::ReportMessage("invalid_cached_data_function", name);
-  *ok = false;
-}
-
-
 bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
   if (expression->IsLiteral()) return true;
   MaterializedLiteral* lit = expression->AsMaterializedLiteral();
@@ -3614,37 +3540,27 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
                                   int* expected_property_count,
                                   bool* ok) {
   int function_block_pos = position();
-  if (cached_data_mode_ == CONSUME_CACHED_DATA) {
+  if (cached_data_mode() == CONSUME_CACHED_DATA) {
     // If we have cached data, we use it to skip parsing the function body. The
     // data contains the information we need to construct the lazy function.
     FunctionEntry entry =
-        (*cached_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.
-        ReportInvalidCachedData(function_name, ok);
-        if (!*ok) {
-          return;
-        }
-      }
-      scanner()->SeekForward(entry.end_pos() - 1);
-
-      scope_->set_end_position(entry.end_pos());
-      Expect(Token::RBRACE, ok);
-      if (!*ok) {
-        return;
-      }
-      isolate()->counters()->total_preparse_skipped()->Increment(
-          scope_->end_position() - function_block_pos);
-      *materialized_literal_count = entry.literal_count();
-      *expected_property_count = entry.property_count();
-      scope_->SetStrictMode(entry.strict_mode());
-    } else {
-      // This case happens when we have preparse data but it doesn't contain an
-      // entry for the function. Fail the compilation.
-      ReportInvalidCachedData(function_name, ok);
+        cached_parse_data_->GetFunctionEntry(function_block_pos);
+    // Check that cached data is valid.
+    CHECK(entry.is_valid());
+    // End position greater than end of stream is safe, and hard to check.
+    CHECK(entry.end_pos() > function_block_pos);
+    scanner()->SeekForward(entry.end_pos() - 1);
+
+    scope_->set_end_position(entry.end_pos());
+    Expect(Token::RBRACE, ok);
+    if (!*ok) {
       return;
     }
+    isolate()->counters()->total_preparse_skipped()->Increment(
+        scope_->end_position() - function_block_pos);
+    *materialized_literal_count = entry.literal_count();
+    *expected_property_count = entry.property_count();
+    scope_->SetStrictMode(entry.strict_mode());
   } else {
     // With no cached data, we partially parse the function, without building an
     // AST. This gathers the data needed to build a lazy function.
@@ -3674,7 +3590,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
     *materialized_literal_count = logger.literals();
     *expected_property_count = logger.properties();
     scope_->SetStrictMode(logger.strict_mode());
-    if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+    if (cached_data_mode() == PRODUCE_CACHED_DATA) {
       ASSERT(log_);
       // Position right after terminal '}'.
       int body_end = scanner()->location().end_pos;
@@ -4766,70 +4682,6 @@ RegExpTree* RegExpParser::ParseCharacterClass() {
 // ----------------------------------------------------------------------------
 // The Parser interface.
 
-ScriptData::~ScriptData() {
-  if (owns_store_) store_.Dispose();
-}
-
-
-int ScriptData::Length() {
-  return store_.length() * sizeof(unsigned);
-}
-
-
-const char* ScriptData::Data() {
-  return reinterpret_cast<const char*>(store_.start());
-}
-
-
-bool ScriptData::HasError() {
-  return has_error();
-}
-
-
-void ScriptData::Initialize() {
-  // Prepares state for use.
-  if (store_.length() >= PreparseDataConstants::kHeaderSize) {
-    function_index_ = PreparseDataConstants::kHeaderSize;
-    int symbol_data_offset = PreparseDataConstants::kHeaderSize
-        + store_[PreparseDataConstants::kFunctionsSizeOffset];
-    if (store_.length() > symbol_data_offset) {
-      symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
-    } else {
-      // Partial preparse causes no symbol information.
-      symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
-    }
-    symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
-  }
-}
-
-
-int ScriptData::ReadNumber(byte** source) {
-  // Reads a number from symbol_data_ in base 128. The most significant
-  // bit marks that there are more digits.
-  // If the first byte is 0x80 (kNumberTerminator), it would normally
-  // represent a leading zero. Since that is useless, and therefore won't
-  // appear as the first digit of any actual value, it is used to
-  // mark the end of the input stream.
-  byte* data = *source;
-  if (data >= symbol_data_end_) return -1;
-  byte input = *data;
-  if (input == PreparseDataConstants::kNumberTerminator) {
-    // End of stream marker.
-    return -1;
-  }
-  int result = input & 0x7f;
-  data++;
-  while ((input & 0x80u) != 0) {
-    if (data >= symbol_data_end_) return -1;
-    input = *data;
-    result = (result << 7) | (input & 0x7f);
-    data++;
-  }
-  *source = data;
-  return result;
-}
-
-
 bool RegExpParser::ParseRegExp(FlatStringReader* input,
                                bool multiline,
                                RegExpCompileData* result,
@@ -4876,7 +4728,7 @@ bool Parser::Parse() {
       result = ParseProgram();
     }
   } else {
-    SetCachedData(info()->cached_data(), info()->cached_data_mode());
+    SetCachedData();
     result = ParseProgram();
   }
   info()->SetFunction(result);
index ac27664..1537e5d 100644 (file)
@@ -59,73 +59,39 @@ class FunctionEntry BASE_EMBEDDED {
 };
 
 
-class ScriptData {
+// Wrapper around ScriptData to provide parser-specific functionality.
+class ParseData {
  public:
-  explicit ScriptData(Vector<unsigned> store)
-      : store_(store),
-        owns_store_(true) { }
-
-  ScriptData(Vector<unsigned> store, bool owns_store)
-      : store_(store),
-        owns_store_(owns_store) { }
-
-  // The created ScriptData won't take ownership of the data. If the alignment
-  // is not correct, this will copy the data (and the created ScriptData will
-  // take ownership of the copy).
-  static ScriptData* New(const char* data, int length, bool owns_store = false);
-
-  virtual ~ScriptData();
-  virtual int Length();
-  virtual const char* Data();
-  virtual bool HasError();
-
+  explicit ParseData(ScriptData* script_data) : script_data_(script_data) {
+    CHECK(IsAligned(script_data->length(), sizeof(unsigned)));
+    CHECK(IsSane());
+  }
   void Initialize();
-  void ReadNextSymbolPosition();
-
   FunctionEntry GetFunctionEntry(int start);
-  int GetSymbolIdentifier();
-  bool SanityCheck();
-
-  Scanner::Location MessageLocation() const;
-  bool IsReferenceError() const;
-  const char* BuildMessage() const;
-  const char* BuildArg() const;
-
-  int function_count() {
-    int functions_size =
-        static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
-    if (functions_size < 0) return 0;
-    if (functions_size % FunctionEntry::kSize != 0) return 0;
-    return functions_size / FunctionEntry::kSize;
+  int FunctionCount();
+
+  bool HasError();
+
+  unsigned* Data() {  // Writable data as unsigned int array.
+    return reinterpret_cast<unsigned*>(const_cast<byte*>(script_data_->data()));
   }
-  // The following functions should only be called if SanityCheck has
-  // returned true.
-  bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; }
-  unsigned magic() { return store_[PreparseDataConstants::kMagicOffset]; }
-  unsigned version() { return store_[PreparseDataConstants::kVersionOffset]; }
 
  private:
-  // Disable copying and assigning; because of owns_store they won't be correct.
-  ScriptData(const ScriptData&);
-  ScriptData& operator=(const ScriptData&);
-
-  friend class v8::ScriptCompiler;
-  Vector<unsigned> store_;
-  unsigned char* symbol_data_;
-  unsigned char* symbol_data_end_;
-  int function_index_;
-  bool owns_store_;
+  bool IsSane();
+  unsigned Magic();
+  unsigned Version();
+  int FunctionsSize();
+  int Length() const {
+    // Script data length is already checked to be a multiple of unsigned size.
+    return script_data_->length() / sizeof(unsigned);
+  }
 
-  unsigned Read(int position) const;
-  unsigned* ReadAddress(int position) const;
-  // Reads a number from the current symbols
-  int ReadNumber(byte** source);
+  ScriptData* script_data_;
+  int function_index_;
 
-  // Read strings written by ParserRecorder::WriteString.
-  static const char* ReadString(unsigned* start, int* chars);
+  DISALLOW_COPY_AND_ASSIGN(ParseData);
 };
 
-
 // ----------------------------------------------------------------------------
 // REGEXP PARSING
 
@@ -646,23 +612,10 @@ class Parser : public ParserBase<ParserTraits> {
   FunctionLiteral* DoParseProgram(CompilationInfo* info,
                                   Handle<String> source);
 
-  // Report syntax error
-  void ReportInvalidCachedData(const AstRawString* name, bool* ok);
-
-  void SetCachedData(ScriptData** data,
-                     CachedDataMode cached_data_mode) {
-    cached_data_mode_ = cached_data_mode;
-    if (cached_data_mode == NO_CACHED_DATA) {
-      cached_data_ = NULL;
-    } else {
-      ASSERT(data != NULL);
-      cached_data_ = data;
-    }
-  }
+  void SetCachedData();
 
   bool inside_with() const { return scope_->inside_with(); }
-  ScriptData** cached_data() const { return cached_data_; }
-  CachedDataMode cached_data_mode() const { return cached_data_mode_; }
+  CachedDataMode cached_data_mode() const { return info_->cached_data_mode(); }
   Scope* DeclarationScope(VariableMode mode) {
     return IsLexicalVariableMode(mode)
         ? scope_ : scope_->DeclarationScope();
@@ -809,7 +762,7 @@ class Parser : public ParserBase<ParserTraits> {
   PreParser* reusable_preparser_;
   Scope* original_scope_;  // for ES5 function declarations in sloppy eval
   Target* target_stack_;  // for break, continue statements
-  ScriptData** cached_data_;
+  ParseData* cached_parse_data_;
   CachedDataMode cached_data_mode_;
   AstValueFactory* ast_value_factory_;
 
index 50e9120..3dd02bd 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "include/v8stdint.h"
 #include "src/base/logging.h"
+#include "src/compiler.h"
 #include "src/globals.h"
 #include "src/hashmap.h"
 #include "src/preparse-data.h"
@@ -34,7 +35,7 @@ void CompleteParserRecorder::LogMessage(int start_pos,
                                         const char* message,
                                         const char* arg_opt,
                                         bool is_reference_error) {
-  if (has_error()) return;
+  if (HasError()) return;
   preamble_[PreparseDataConstants::kHasErrorOffset] = true;
   function_store_.Reset();
   STATIC_ASSERT(PreparseDataConstants::kMessageStartPos == 0);
@@ -59,17 +60,21 @@ void CompleteParserRecorder::WriteString(Vector<const char> str) {
 }
 
 
-Vector<unsigned> CompleteParserRecorder::ExtractData() {
+ScriptData* CompleteParserRecorder::GetScriptData() {
   int function_size = function_store_.size();
   int total_size = PreparseDataConstants::kHeaderSize + function_size;
-  Vector<unsigned> data = Vector<unsigned>::New(total_size);
+  unsigned* data = NewArray<unsigned>(total_size);
   preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
-  MemCopy(data.start(), preamble_, sizeof(preamble_));
+  MemCopy(data, preamble_, sizeof(preamble_));
   if (function_size > 0) {
-    function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
-                                           total_size));
+    function_store_.WriteTo(Vector<unsigned>(
+        data + PreparseDataConstants::kHeaderSize, function_size));
   }
-  return data;
+  ASSERT(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
+  ScriptData* result = new ScriptData(reinterpret_cast<byte*>(data),
+                                      total_size * sizeof(unsigned));
+  result->AcquireDataOwnership();
+  return result;
 }
 
 
index 36c481c..caae0ef 100644 (file)
@@ -13,6 +13,8 @@
 namespace v8 {
 namespace internal {
 
+class ScriptData;
+
 
 // Abstract interface for preparse data recorder.
 class ParserRecorder {
@@ -149,13 +151,17 @@ class CompleteParserRecorder : public ParserRecorder {
                           const char* message,
                           const char* argument_opt,
                           bool is_reference_error_);
-  Vector<unsigned> ExtractData();
+  ScriptData* GetScriptData();
 
- private:
-  bool has_error() {
+  bool HasError() {
     return static_cast<bool>(preamble_[PreparseDataConstants::kHasErrorOffset]);
   }
+  Vector<unsigned> ErrorMessageData() {
+    ASSERT(HasError());
+    return function_store_.ToVector();
+  }
 
+ private:
   void WriteString(Vector<const char> str);
 
   // Write a non-negative number to the symbol store.
index 9e203b5..30fde9b 100644 (file)
@@ -1799,13 +1799,12 @@ int Serializer::SpaceAreaSize(int space) {
 }
 
 
-void Serializer::PadByte() { sink_->Put(kNop, "Padding"); }
-
-
 void Serializer::Pad() {
   // The non-branching GetInt will read up to 3 bytes too far, so we need
   // to pad the snapshot to make sure we don't read over the end.
-  for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) PadByte();
+  for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
+    sink_->Put(kNop, "Padding");
+  }
 }
 
 
@@ -1817,33 +1816,16 @@ void Serializer::InitializeCodeAddressMap() {
 
 ScriptData* CodeSerializer::Serialize(Handle<SharedFunctionInfo> info) {
   // Serialize code object.
-  List<char> payload;
-  ListSnapshotSink listsink(&payload);
-  CodeSerializer ser(info->GetIsolate(), &listsink);
+  List<byte> payload;
+  ListSnapshotSink list_sink(&payload);
+  CodeSerializer cs(info->GetIsolate(), &list_sink);
   DisallowHeapAllocation no_gc;
   Object** location = Handle<Object>::cast(info).location();
-  ser.VisitPointer(location);
-  ser.Pad();
-
-  // Allocate storage.  The payload length may not be aligned.  Round up.
-  // TODO(yangguo) replace ScriptData with a more generic super class.
-  int payload_length = payload.length();
-  int raw_length = payload_length / sizeof(unsigned) + kHeaderSize;
-  if (!IsAligned(payload_length, sizeof(unsigned))) raw_length++;
-  unsigned* raw_data = i::NewArray<unsigned>(raw_length);
-  char* payload_data = reinterpret_cast<char*>(raw_data + kHeaderSize);
-
-  // Write header.
-  raw_data[kVersionHashOffset] = Version::Hash();
-  raw_data[kPayloadLengthOffset] = payload_length;
-  STATIC_ASSERT(NEW_SPACE == 0);
-  for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
-    raw_data[kReservationsOffset + i] = ser.CurrentAllocationAddress(i);
-  }
+  cs.VisitPointer(location);
+  cs.Pad();
 
-  CopyBytes(payload_data, payload.begin(), static_cast<size_t>(payload_length));
-
-  return new ScriptData(Vector<unsigned>(raw_data, raw_length), true);
+  SerializedCodeData data(&payload, &cs);
+  return data.GetScriptData();
 }
 
 
@@ -1892,20 +1874,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
 
 
 Object* CodeSerializer::Deserialize(Isolate* isolate, ScriptData* data) {
-  const unsigned* raw_data = reinterpret_cast<const unsigned*>(data->Data());
-  CHECK_EQ(Version::Hash(), raw_data[kVersionHashOffset]);
-  int payload_length = raw_data[kPayloadLengthOffset];
-  const byte* payload_data =
-      reinterpret_cast<const byte*>(raw_data + kHeaderSize);
-  ASSERT_LE(payload_length, data->Length() - kHeaderSize);
-
-  SnapshotByteSource payload(payload_data, payload_length);
+  SerializedCodeData scd(data);
+  SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
   Deserializer deserializer(&payload);
   STATIC_ASSERT(NEW_SPACE == 0);
   // TODO(yangguo) what happens if remaining new space is too small?
   for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
-    deserializer.set_reservation(
-        i, raw_data[CodeSerializer::kReservationsOffset + i]);
+    deserializer.set_reservation(i, scd.GetReservation(i));
   }
   Object* root;
   deserializer.DeserializePartial(isolate, &root);
@@ -1913,4 +1888,27 @@ Object* CodeSerializer::Deserialize(Isolate* isolate, ScriptData* data) {
   ASSERT(root->IsSharedFunctionInfo());
   return root;
 }
+
+
+SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
+    : owns_script_data_(true) {
+  int data_length = payload->length() + kHeaderEntries * kIntSize;
+  byte* data = NewArray<byte>(data_length);
+  ASSERT(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
+  CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(),
+            static_cast<size_t>(payload->length()));
+  script_data_ = new ScriptData(data, data_length);
+  script_data_->AcquireDataOwnership();
+  SetHeaderValue(kVersionHashOffset, Version::Hash());
+  STATIC_ASSERT(NEW_SPACE == 0);
+  for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+    SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
+  }
+}
+
+
+bool SerializedCodeData::IsSane() {
+  return GetHeaderValue(kVersionHashOffset) == Version::Hash() &&
+         PayloadLength() >= SharedFunctionInfo::kSize;
+}
 } }  // namespace v8::internal
index 6cc90ea..72bcfe5 100644 (file)
@@ -5,10 +5,10 @@
 #ifndef V8_SERIALIZE_H_
 #define V8_SERIALIZE_H_
 
+#include "src/compiler.h"
 #include "src/hashmap.h"
 #include "src/heap-profiler.h"
 #include "src/isolate.h"
-#include "src/parser.h"
 #include "src/snapshot-source-sink.h"
 
 namespace v8 {
@@ -470,7 +470,6 @@ class Serializer : public SerializerDeserializer {
   SerializationAddressMapper address_mapper_;
   intptr_t root_index_wave_front_;
   void Pad();
-  void PadByte();
 
   friend class ObjectSerializer;
   friend class Deserializer;
@@ -576,6 +575,67 @@ class CodeSerializer : public Serializer {
   static const int kPayloadLengthOffset = 1;
   static const int kReservationsOffset = 2;
 };
+
+
+// Wrapper around ScriptData to provide code-serializer-specific functionality.
+class SerializedCodeData {
+ public:
+  // Used by when consuming.
+  explicit SerializedCodeData(ScriptData* data)
+      : script_data_(data), owns_script_data_(false) {
+    CHECK(IsSane());
+  }
+
+  // Used when producing.
+  SerializedCodeData(List<byte>* payload, CodeSerializer* cs);
+
+  ~SerializedCodeData() {
+    if (owns_script_data_) delete script_data_;
+  }
+
+  // Return ScriptData object and relinquish ownership over it to the caller.
+  ScriptData* GetScriptData() {
+    ScriptData* result = script_data_;
+    script_data_ = NULL;
+    ASSERT(owns_script_data_);
+    owns_script_data_ = false;
+    return result;
+  }
+
+  const byte* Payload() const {
+    return script_data_->data() + kHeaderEntries * kIntSize;
+  }
+
+  int PayloadLength() const {
+    return script_data_->length() - kHeaderEntries * kIntSize;
+  }
+
+  int GetReservation(int space) const {
+    return GetHeaderValue(kReservationsOffset + space);
+  }
+
+ private:
+  void SetHeaderValue(int offset, int value) {
+    reinterpret_cast<int*>(const_cast<byte*>(script_data_->data()))[offset] =
+        value;
+  }
+
+  int GetHeaderValue(int offset) const {
+    return reinterpret_cast<const int*>(script_data_->data())[offset];
+  }
+
+  bool IsSane();
+
+  // The data header consists of int-sized entries:
+  // [0] version hash
+  // [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
+  static const int kVersionHashOffset = 0;
+  static const int kReservationsOffset = 1;
+  static const int kHeaderEntries = 8;
+
+  ScriptData* script_data_;
+  bool owns_script_data_;
+};
 } }  // namespace v8::internal
 
 #endif  // V8_SERIALIZE_H_
index e9988eb..b223b58 100644 (file)
@@ -92,9 +92,9 @@ bool SnapshotByteSource::GetBlob(const byte** data, int* number_of_bytes) {
 }
 
 
-void DebugSnapshotSink::Put(int byte, const char* description) {
-  PrintF("%24s: %x\n", description, byte);
-  sink_->Put(byte, description);
+void DebugSnapshotSink::Put(byte b, const char* description) {
+  PrintF("%24s: %x\n", description, b);
+  sink_->Put(b, description);
 }
 
 }  // namespace v8::internal
index eae8606..f98b5d0 100644 (file)
@@ -71,9 +71,10 @@ class SnapshotByteSource V8_FINAL {
 class SnapshotByteSink {
  public:
   virtual ~SnapshotByteSink() { }
-  virtual void Put(int byte, const char* description) = 0;
-  virtual void PutSection(int byte, const char* description) {
-    Put(byte, description);
+  virtual void Put(byte b, const char* description) = 0;
+  virtual void PutSection(int b, const char* description) {
+    ASSERT_LE(b, kMaxUInt8);
+    Put(static_cast<byte>(b), description);
   }
   void PutInt(uintptr_t integer, const char* description);
   void PutRaw(byte* data, int number_of_bytes, const char* description);
@@ -86,7 +87,7 @@ class DummySnapshotSink : public SnapshotByteSink {
  public:
   DummySnapshotSink() : length_(0) {}
   virtual ~DummySnapshotSink() {}
-  virtual void Put(int byte, const char* description) { length_++; }
+  virtual void Put(byte b, const char* description) { length_++; }
   virtual int Position() { return length_; }
 
  private:
@@ -98,7 +99,7 @@ class DummySnapshotSink : public SnapshotByteSink {
 class DebugSnapshotSink : public SnapshotByteSink {
  public:
   explicit DebugSnapshotSink(SnapshotByteSink* chained) : sink_(chained) {}
-  virtual void Put(int byte, const char* description) V8_OVERRIDE;
+  virtual void Put(byte b, const char* description) V8_OVERRIDE;
   virtual int Position() V8_OVERRIDE { return sink_->Position(); }
 
  private:
@@ -108,14 +109,14 @@ class DebugSnapshotSink : public SnapshotByteSink {
 
 class ListSnapshotSink : public i::SnapshotByteSink {
  public:
-  explicit ListSnapshotSink(i::List<char>* data) : data_(data) {}
-  virtual void Put(int byte, const char* description) V8_OVERRIDE {
-    data_->Add(byte);
+  explicit ListSnapshotSink(i::List<byte>* data) : data_(data) {}
+  virtual void Put(byte b, const char* description) V8_OVERRIDE {
+    data_->Add(b);
   }
   virtual int Position() V8_OVERRIDE { return data_->length(); }
 
  private:
-  i::List<char>* data_;
+  i::List<byte>* data_;
 };
 
 }  // namespace v8::internal
index 6afdf1b..6251172 100644 (file)
@@ -14814,134 +14814,21 @@ TEST(PreCompileSerialization) {
                               v8::ScriptCompiler::kProduceDataToCache);
   // Serialize.
   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
-  char* serialized_data = i::NewArray<char>(cd->length);
+  i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
   i::MemCopy(serialized_data, cd->data, cd->length);
 
   // Deserialize.
-  i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
+  i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
 
   // Verify that the original is the same as the deserialized.
-  CHECK_EQ(cd->length, deserialized->Length());
-  CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
+  CHECK_EQ(cd->length, deserialized->length());
+  CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
 
   delete deserialized;
   i::DeleteArray(serialized_data);
 }
 
 
-// Attempts to deserialize bad data.
-TEST(PreCompileDeserializationError) {
-  v8::V8::Initialize();
-  const char* data = "DONT CARE";
-  int invalid_size = 3;
-  i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
-  CHECK_EQ(NULL, sd);
-}
-
-
-TEST(CompileWithInvalidCachedData) {
-  v8::V8::Initialize();
-  v8::Isolate* isolate = CcTest::isolate();
-  LocalContext context;
-  v8::HandleScope scope(context->GetIsolate());
-  i::FLAG_min_preparse_length = 0;
-
-  const char* script = "function foo(){ return 5;}\n"
-      "function bar(){ return 6 + 7;}  foo();";
-  v8::ScriptCompiler::Source source(v8_str(script));
-  v8::ScriptCompiler::Compile(isolate, &source,
-                              v8::ScriptCompiler::kProduceDataToCache);
-  // source owns its cached data. Create a ScriptData based on it. The user
-  // never needs to create ScriptDatas any more; we only need it here because we
-  // want to modify the data before passing it back.
-  const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
-  // ScriptData does not take ownership of the buffers passed to it.
-  i::ScriptData* sd =
-      i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
-  CHECK(!sd->HasError());
-  // ScriptData private implementation details
-  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
-  const int kFunctionEntrySize = i::FunctionEntry::kSize;
-  const int kFunctionEntryStartOffset = 0;
-  const int kFunctionEntryEndOffset = 1;
-  unsigned* sd_data =
-      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
-
-  // Overwrite function bar's end position with 0.
-  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
-  v8::TryCatch try_catch;
-
-  // Make the script slightly different so that we don't hit the compilation
-  // cache. Don't change the lenghts of tokens.
-  const char* script2 = "function foo(){ return 6;}\n"
-      "function bar(){ return 6 + 7;}  foo();";
-  v8::ScriptCompiler::Source source2(
-      v8_str(script2),
-      // CachedData doesn't take ownership of the buffers, Source takes
-      // ownership of CachedData.
-      new v8::ScriptCompiler::CachedData(
-          reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
-  Local<v8::UnboundScript> compiled_script =
-      v8::ScriptCompiler::CompileUnbound(isolate, &source2);
-
-  CHECK(try_catch.HasCaught());
-  {
-    String::Utf8Value exception_value(try_catch.Message()->Get());
-    CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
-             *exception_value);
-  }
-
-  try_catch.Reset();
-  delete sd;
-
-  // Overwrite function bar's start position with 200. The function entry will
-  // not be found when searching for it by position, and the compilation fails.
-
-  // ScriptData does not take ownership of the buffers passed to it.
-  sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
-  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
-  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
-      200;
-  const char* script3 = "function foo(){ return 7;}\n"
-      "function bar(){ return 6 + 7;}  foo();";
-  v8::ScriptCompiler::Source source3(
-      v8_str(script3),
-      new v8::ScriptCompiler::CachedData(
-          reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
-  compiled_script =
-      v8::ScriptCompiler::CompileUnbound(isolate, &source3);
-  CHECK(try_catch.HasCaught());
-  {
-    String::Utf8Value exception_value(try_catch.Message()->Get());
-    CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
-             *exception_value);
-  }
-  CHECK(compiled_script.IsEmpty());
-  try_catch.Reset();
-  delete sd;
-
-  // Try passing in cached data which is obviously invalid (wrong length).
-  sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
-  const char* script4 =
-      "function foo(){ return 8;}\n"
-      "function bar(){ return 6 + 7;}  foo();";
-  v8::ScriptCompiler::Source source4(
-      v8_str(script4),
-      new v8::ScriptCompiler::CachedData(
-          reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
-  compiled_script =
-      v8::ScriptCompiler::CompileUnbound(isolate, &source4);
-  CHECK(try_catch.HasCaught());
-  {
-    String::Utf8Value exception_value(try_catch.Message()->Get());
-    CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
-             *exception_value);
-  }
-  CHECK(compiled_script.IsEmpty());
-  delete sd;
-}
-
-
 // This tests that we do not allow dictionary load/call inline caches
 // to use functions that have not yet been compiled.  The potential
 // problem of loading a function that has not yet been compiled can
index b12098a..a2806d8 100644 (file)
@@ -157,8 +157,7 @@ TEST(ScanHTMLEndComments) {
     preparser.set_allow_lazy(true);
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
-    i::ScriptData data(log.ExtractData());
-    CHECK(!data.has_error());
+    CHECK(!log.HasError());
   }
 
   for (int i = 0; fail_tests[i]; i++) {
@@ -173,8 +172,7 @@ TEST(ScanHTMLEndComments) {
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     // Even in the case of a syntax error, kPreParseSuccess is returned.
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
-    i::ScriptData data(log.ExtractData());
-    CHECK(data.has_error());
+    CHECK(log.HasError());
   }
 }
 
@@ -306,8 +304,7 @@ TEST(StandAlonePreParser) {
     preparser.set_allow_natives_syntax(true);
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
-    i::ScriptData data(log.ExtractData());
-    CHECK(!data.has_error());
+    CHECK(!log.HasError());
   }
 }
 
@@ -339,9 +336,7 @@ TEST(StandAlonePreParserNoNatives) {
     preparser.set_allow_lazy(true);
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
-    i::ScriptData data(log.ExtractData());
-    // Data contains syntax error.
-    CHECK(data.has_error());
+    CHECK(log.HasError());
   }
 }
 
@@ -407,8 +402,7 @@ TEST(RegressChromium62639) {
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   // Even in the case of a syntax error, kPreParseSuccess is returned.
   CHECK_EQ(i::PreParser::kPreParseSuccess, result);
-  i::ScriptData data(log.ExtractData());
-  CHECK(data.has_error());
+  CHECK(log.HasError());
 }
 
 
@@ -438,15 +432,15 @@ TEST(Regress928) {
   preparser.set_allow_lazy(true);
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   CHECK_EQ(i::PreParser::kPreParseSuccess, result);
-  i::ScriptData data(log.ExtractData());
-  CHECK(!data.has_error());
-  data.Initialize();
+  i::ScriptData* sd = log.GetScriptData();
+  i::ParseData pd(sd);
+  pd.Initialize();
 
   int first_function =
       static_cast<int>(strstr(program, "function") - program);
   int first_lbrace = first_function + i::StrLength("function () ");
   CHECK_EQ('{', program[first_lbrace]);
-  i::FunctionEntry entry1 = data.GetFunctionEntry(first_lbrace);
+  i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
   CHECK(!entry1.is_valid());
 
   int second_function =
@@ -454,9 +448,10 @@ TEST(Regress928) {
   int second_lbrace =
       second_function + i::StrLength("function () ");
   CHECK_EQ('{', program[second_lbrace]);
-  i::FunctionEntry entry2 = data.GetFunctionEntry(second_lbrace);
+  i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
   CHECK(entry2.is_valid());
   CHECK_EQ('}', program[entry2.end_pos() - 1]);
+  delete sd;
 }
 
 
@@ -1134,20 +1129,41 @@ TEST(ScopePositions) {
 }
 
 
-i::Handle<i::String> FormatMessage(i::ScriptData* data) {
+const char* ReadString(unsigned* start) {
+  int length = start[0];
+  char* result = i::NewArray<char>(length + 1);
+  for (int i = 0; i < length; i++) {
+    result[i] = start[i + 1];
+  }
+  result[length] = '\0';
+  return result;
+}
+
+
+i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
   i::Isolate* isolate = CcTest::i_isolate();
   i::Factory* factory = isolate->factory();
-  const char* message = data->BuildMessage();
+  const char* message =
+      ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
   i::Handle<i::String> format = v8::Utils::OpenHandle(
       *v8::String::NewFromUtf8(CcTest::isolate(), message));
-  const char* arg = data->BuildArg();
-  i::Handle<i::JSArray> args_array = factory->NewJSArray(arg == NULL ? 0 : 1);
-  if (arg != NULL) {
-    i::JSArray::SetElement(
-        args_array, 0, v8::Utils::OpenHandle(*v8::String::NewFromUtf8(
-                                                  CcTest::isolate(), arg)),
-        NONE, i::SLOPPY).Check();
+  int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
+  const char* arg = NULL;
+  i::Handle<i::JSArray> args_array;
+  if (arg_count == 1) {
+    // Position after text found by skipping past length field and
+    // length field content words.
+    int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
+              data[i::PreparseDataConstants::kMessageTextPos];
+    arg = ReadString(&data[pos]);
+    args_array = factory->NewJSArray(1);
+    i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
+                           NONE, i::SLOPPY).Check();
+  } else {
+    CHECK_EQ(0, arg_count);
+    args_array = factory->NewJSArray(0);
   }
+
   i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
   i::Handle<i::Object> format_fun = i::Object::GetProperty(
       isolate, builtins, "FormatMessage").ToHandleChecked();
@@ -1157,6 +1173,7 @@ i::Handle<i::String> FormatMessage(i::ScriptData* data) {
   CHECK(result->IsString());
   i::DeleteArray(message);
   i::DeleteArray(arg);
+  data.Dispose();
   return i::Handle<i::String>::cast(result);
 }
 
@@ -1211,7 +1228,8 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
   }
-  i::ScriptData data(log.ExtractData());
+
+  bool preparse_error = log.HasError();
 
   // Parse the data
   i::FunctionLiteral* function;
@@ -1246,7 +1264,7 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
       CHECK(false);
     }
 
-    if (!data.has_error()) {
+    if (!preparse_error) {
       v8::base::OS::Print(
           "Parser failed on:\n"
           "\t%s\n"
@@ -1257,7 +1275,8 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
       CHECK(false);
     }
     // Check that preparser and parser produce the same error.
-    i::Handle<i::String> preparser_message = FormatMessage(&data);
+    i::Handle<i::String> preparser_message =
+        FormatMessage(log.ErrorMessageData());
     if (!i::String::Equals(message_string, preparser_message)) {
       v8::base::OS::Print(
           "Expected parser and preparser to produce the same error on:\n"
@@ -1270,14 +1289,14 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
           preparser_message->ToCString().get());
       CHECK(false);
     }
-  } else if (data.has_error()) {
+  } else if (preparse_error) {
     v8::base::OS::Print(
         "Preparser failed on:\n"
         "\t%s\n"
         "with error:\n"
         "\t%s\n"
         "However, the parser succeeded",
-        source->ToCString().get(), FormatMessage(&data)->ToCString().get());
+        source->ToCString().get(), FormatMessage(log.ErrorMessageData()));
     CHECK(false);
   } else if (result == kError) {
     v8::base::OS::Print(
@@ -2165,22 +2184,20 @@ TEST(DontRegressPreParserDataSizes) {
         factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
     i::Handle<i::Script> script = factory->NewScript(source);
     i::CompilationInfoWithZone info(script);
-    i::ScriptData* data = NULL;
-    info.SetCachedData(&data, i::PRODUCE_CACHED_DATA);
+    i::ScriptData* sd = NULL;
+    info.SetCachedData(&sd, i::PRODUCE_CACHED_DATA);
     i::Parser::Parse(&info, true);
-    CHECK(data);
-    CHECK(!data->HasError());
+    i::ParseData pd(sd);
 
-    if (data->function_count() != test_cases[i].functions) {
+    if (pd.FunctionCount() != test_cases[i].functions) {
       v8::base::OS::Print(
           "Expected preparse data for program:\n"
           "\t%s\n"
           "to contain %d functions, however, received %d functions.\n",
-          program, test_cases[i].functions,
-          data->function_count());
+          program, test_cases[i].functions, pd.FunctionCount());
       CHECK(false);
     }
-    delete data;
+    delete sd;
   }
 }
 
index c29f51f..d692ffc 100644 (file)
@@ -177,9 +177,9 @@ class FileByteSink : public SnapshotByteSink {
       fclose(fp_);
     }
   }
-  virtual void Put(int byte, const char* description) {
+  virtual void Put(byte b, const char* description) {
     if (fp_ != NULL) {
-      fputc(byte, fp_);
+      fputc(b, fp_);
     }
   }
   virtual int Position() {