New compilation API, part 2.
authormarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Mar 2014 13:24:13 +0000 (13:24 +0000)
committermarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Mar 2014 13:24:13 +0000 (13:24 +0000)
This CL makes the Parser produce the data PreParser used to produce. This
enables us to get rid of the unnecessary preparsing phase.

The first part is here: https://codereview.chromium.org/199063003/

BUG=
R=dcarney@chromium.org, svenpanne@chromium.org

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

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

15 files changed:
include/v8.h
src/api.cc
src/bootstrapper.cc
src/compiler.cc
src/compiler.h
src/d8.cc
src/debug.cc
src/parser.cc
src/parser.h
src/preparser.h
test/cctest/cctest.h
test/cctest/test-api.cc
test/cctest/test-compiler.cc
test/cctest/test-debug.cc
test/cctest/test-parsing.cc

index 4ff5830..02942b6 100644 (file)
@@ -1097,25 +1097,52 @@ class V8_EXPORT ScriptCompiler {
    * UnboundScript.
    */
   struct V8_EXPORT CachedData {
-    CachedData() : data(NULL), length(0) {}
-    // Caller keeps the ownership of data and guarantees that the data stays
-    // alive long enough.
-    CachedData(const uint8_t* data, int length) : data(data), length(length) {}
+    enum BufferPolicy {
+      BufferNotOwned,
+      BufferOwned
+    };
+
+    CachedData() : data(NULL), length(0), buffer_policy(BufferNotOwned) {}
+
+    // If buffer_policy is BufferNotOwned, the caller keeps the ownership of
+    // data and guarantees that it stays alive until the CachedData object is
+    // destroyed. If the policy is BufferOwned, the given data will be deleted
+    // (with delete[]) when the CachedData object is destroyed.
+    CachedData(const uint8_t* data, int length,
+               BufferPolicy buffer_policy = BufferNotOwned);
+    ~CachedData();
     // TODO(marja): Async compilation; add constructors which take a callback
     // which will be called when V8 no longer needs the data.
     const uint8_t* data;
     int length;
+    BufferPolicy buffer_policy;
+
+  private:
+     // Prevent copying. Not implemented.
+     CachedData(const CachedData&);
   };
 
   /**
    * Source code which can be then compiled to a UnboundScript or
    * BoundScript.
    */
-  struct V8_EXPORT Source {
+  class V8_EXPORT Source {
+   public:
+    // Source takes ownership of CachedData.
     Source(Local<String> source_string, const ScriptOrigin& origin,
-           const CachedData& cached_data = CachedData());
-    Source(Local<String> source_string,
-           const CachedData& cached_data = CachedData());
+           CachedData* cached_data = NULL);
+    Source(Local<String> source_string, CachedData* cached_data = NULL);
+    ~Source();
+
+    // Ownership of the CachedData or its buffers is *not* transferred to the
+    // caller. The CachedData object is alive as long as the Source object is
+    // alive.
+    const CachedData* GetCachedData() const;
+
+   private:
+    friend class ScriptCompiler;
+     // Prevent copying. Not implemented.
+    Source(const Source&);
 
     Local<String> source_string;
 
@@ -1125,8 +1152,10 @@ class V8_EXPORT ScriptCompiler {
     Handle<Integer> resource_column_offset;
     Handle<Boolean> resource_is_shared_cross_origin;
 
-    // Cached data from previous compilation (if any).
-    CachedData cached_data;
+    // Cached data from previous compilation (if any), or generated during
+    // compilation (if the generate_cached_data flag is passed to
+    // ScriptCompiler).
+    CachedData* cached_data;
   };
 
   enum CompileOptions {
@@ -1142,7 +1171,7 @@ class V8_EXPORT ScriptCompiler {
    *   bound to a context).
    */
   static Local<UnboundScript> CompileUnbound(
-      Isolate* isolate, const Source& source,
+      Isolate* isolate, Source* source,
       CompileOptions options = kNoCompileOptions);
 
   /**
@@ -1157,7 +1186,7 @@ class V8_EXPORT ScriptCompiler {
    *   context.
    */
   static Local<Script> Compile(
-      Isolate* isolate, const Source& source,
+      Isolate* isolate, Source* source,
       CompileOptions options = kNoCompileOptions);
 };
 
index 871da87..d0c9d26 100644 (file)
@@ -1617,8 +1617,20 @@ ScriptData* ScriptData::New(const char* data, int length) {
 // Internally, UnboundScript is a SharedFunctionInfo, and Script is a
 // JSFunction.
 
+ScriptCompiler::CachedData::CachedData(const uint8_t* data_, int length_,
+                                       BufferPolicy buffer_policy_)
+    : data(data_), length(length_), buffer_policy(buffer_policy_) {}
+
+
+ScriptCompiler::CachedData::~CachedData() {
+  if (buffer_policy == BufferOwned) {
+    delete[] data;
+  }
+}
+
+
 ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin,
-                               const CachedData& data)
+                               CachedData* data)
     : source_string(string),
       resource_name(origin.ResourceName()),
       resource_line_offset(origin.ResourceLineOffset()),
@@ -1628,10 +1640,21 @@ ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin,
 
 
 ScriptCompiler::Source::Source(Local<String> string,
-                               const CachedData& data)
+                               CachedData* data)
     : source_string(string), cached_data(data) {}
 
 
+ScriptCompiler::Source::~Source() {
+  delete cached_data;
+}
+
+
+const ScriptCompiler::CachedData* ScriptCompiler::Source::GetCachedData()
+    const {
+  return cached_data;
+}
+
+
 Local<Script> UnboundScript::BindToCurrentContext() {
   i::Handle<i::HeapObject> obj =
       i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
@@ -1730,12 +1753,41 @@ Local<UnboundScript> Script::GetUnboundScript() {
 
 Local<UnboundScript> ScriptCompiler::CompileUnbound(
     Isolate* v8_isolate,
-    const Source& source,
+    Source* source,
     CompileOptions options) {
-  // FIXME(marja): This function cannot yet create cached data (if options |
-  // produce_data_to_cache is true), but the PreCompile function is still there
-  // for doing it.
-  i::Handle<i::String> str = Utils::OpenHandle(*(source.source_string));
+  i::ScriptDataImpl* script_data_impl = NULL;
+  i::CachedDataMode cached_data_mode = i::NO_CACHED_DATA;
+  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. In release mode, try to do the right thing: Just regenerate the
+      // data.
+      delete source->cached_data;
+      source->cached_data = NULL;
+    }
+  } else if (source->cached_data) {
+    // FIXME(marja): Make compiler use CachedData directly. Aligning needs to be
+    // taken care of.
+    script_data_impl = static_cast<i::ScriptDataImpl*>(ScriptData::New(
+        reinterpret_cast<const char*>(source->cached_data->data),
+        source->cached_data->length));
+    // We assert that the pre-data is sane, even though we can actually
+    // handle it if it turns out not to be in release mode.
+    ASSERT(script_data_impl->SanityCheck());
+    if (script_data_impl->SanityCheck()) {
+      cached_data_mode = i::CONSUME_CACHED_DATA;
+    } else {
+      // If the pre-data isn't sane we simply ignore it.
+      delete script_data_impl;
+      script_data_impl = NULL;
+      delete source->cached_data;
+      source->cached_data = NULL;
+    }
+  }
+
+  i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
   ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
              return Local<UnboundScript>());
@@ -1747,37 +1799,22 @@ Local<UnboundScript> ScriptCompiler::CompileUnbound(
     int line_offset = 0;
     int column_offset = 0;
     bool is_shared_cross_origin = false;
-    if (!source.resource_name.IsEmpty()) {
-      name_obj = Utils::OpenHandle(*source.resource_name);
+    if (!source->resource_name.IsEmpty()) {
+      name_obj = Utils::OpenHandle(*(source->resource_name));
     }
-    if (!source.resource_line_offset.IsEmpty()) {
-      line_offset = static_cast<int>(source.resource_line_offset->Value());
+    if (!source->resource_line_offset.IsEmpty()) {
+      line_offset = static_cast<int>(source->resource_line_offset->Value());
     }
-    if (!source.resource_column_offset.IsEmpty()) {
+    if (!source->resource_column_offset.IsEmpty()) {
       column_offset =
-          static_cast<int>(source.resource_column_offset->Value());
+          static_cast<int>(source->resource_column_offset->Value());
     }
-    if (!source.resource_is_shared_cross_origin.IsEmpty()) {
+    if (!source->resource_is_shared_cross_origin.IsEmpty()) {
       v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
       is_shared_cross_origin =
-          source.resource_is_shared_cross_origin == v8::True(v8_isolate);
+          source->resource_is_shared_cross_origin == v8::True(v8_isolate);
     }
     EXCEPTION_PREAMBLE(isolate);
-    i::ScriptDataImpl* pre_data_impl = NULL;
-    if (source.cached_data.data) {
-      // FIXME(marja): Make compiler use CachedData directly.
-      pre_data_impl = static_cast<i::ScriptDataImpl*>(ScriptData::New(
-          reinterpret_cast<const char*>(source.cached_data.data),
-          source.cached_data.length));
-    }
-    // We assert that the pre-data is sane, even though we can actually
-    // handle it if it turns out not to be in release mode.
-    ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
-    // If the pre-data isn't sane we simply ignore it
-    if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
-      delete pre_data_impl;
-      pre_data_impl = NULL;
-    }
     i::Handle<i::SharedFunctionInfo> result =
         i::Compiler::CompileScript(str,
                                    name_obj,
@@ -1786,12 +1823,21 @@ Local<UnboundScript> ScriptCompiler::CompileUnbound(
                                    is_shared_cross_origin,
                                    isolate->global_context(),
                                    NULL,
-                                   pre_data_impl,
+                                   &script_data_impl,
+                                   cached_data_mode,
                                    i::NOT_NATIVES_CODE);
     has_pending_exception = result.is_null();
     EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
     raw_result = *result;
-    delete pre_data_impl;
+    if ((options & kProduceDataToCache) && script_data_impl != 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;
+    }
+    delete script_data_impl;
   }
   i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
   return ToApiHandle<UnboundScript>(result);
@@ -1800,7 +1846,7 @@ Local<UnboundScript> ScriptCompiler::CompileUnbound(
 
 Local<Script> ScriptCompiler::Compile(
     Isolate* v8_isolate,
-    const Source& source,
+    Source* source,
     CompileOptions options) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
   ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()",
@@ -1818,20 +1864,22 @@ Local<Script> Script::Compile(v8::Handle<String> source,
                               v8::ScriptOrigin* origin,
                               ScriptData* script_data) {
   i::Handle<i::String> str = Utils::OpenHandle(*source);
-  ScriptCompiler::CachedData cached_data;
+  ScriptCompiler::CachedData* cached_data = NULL;
   if (script_data) {
-    cached_data = ScriptCompiler::CachedData(
+    cached_data = new ScriptCompiler::CachedData(
         reinterpret_cast<const uint8_t*>(script_data->Data()),
         script_data->Length());
   }
   if (origin) {
+    ScriptCompiler::Source script_source(source, *origin, cached_data);
     return ScriptCompiler::Compile(
         reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
-        ScriptCompiler::Source(source, *origin, cached_data));
+        &script_source);
   }
+  ScriptCompiler::Source script_source(source, cached_data);
   return ScriptCompiler::Compile(
       reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
-      ScriptCompiler::Source(source, cached_data));
+      &script_source);
 }
 
 
index 879f103..7edc5d5 100644 (file)
@@ -1524,6 +1524,7 @@ bool Genesis::CompileScriptCached(Isolate* isolate,
         top_context,
         extension,
         NULL,
+        NO_CACHED_DATA,
         use_runtime_context ? NATIVES_CODE : NOT_NATIVES_CODE);
     if (function_info.is_null()) return false;
     if (cache != NULL) cache->Add(name, function_info);
index fdee097..4b53989 100644 (file)
@@ -115,7 +115,8 @@ void CompilationInfo::Initialize(Isolate* isolate,
   scope_ = NULL;
   global_scope_ = NULL;
   extension_ = NULL;
-  pre_parse_data_ = NULL;
+  cached_data_ = NULL;
+  cached_data_mode_ = NO_CACHED_DATA;
   zone_ = zone;
   deferred_handles_ = NULL;
   code_stub_ = NULL;
@@ -782,15 +783,18 @@ static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
   ASSERT(info->is_eval() || info->is_global());
 
   bool parse_allow_lazy =
-      (info->pre_parse_data() != NULL ||
+      (info->cached_data_mode() == CONSUME_CACHED_DATA ||
        String::cast(script->source())->length() > FLAG_min_preparse_length) &&
       !DebuggerWantsEagerCompilation(info);
 
-  if (!parse_allow_lazy && info->pre_parse_data() != NULL) {
-    // We are going to parse eagerly, but we have preparse data produced by lazy
-    // preparsing. We cannot use it, since it won't contain all the symbols we
-    // need for eager parsing.
-    info->SetPreParseData(NULL);
+  if (!parse_allow_lazy && info->cached_data_mode() != NO_CACHED_DATA) {
+    // We are going to parse eagerly, but we either 1) have cached data produced
+    // by lazy parsing or 2) are asked to generate cached data. We cannot use
+    // the existing data, since it won't contain all the symbols we need for
+    // eager parsing. In addition, it doesn't make sense to produce the data
+    // when parsing eagerly. That data would contain all symbols, but no
+    // functions, so it cannot be used to aid lazy parsing later.
+    info->SetCachedData(NULL, NO_CACHED_DATA);
   }
 
   Handle<SharedFunctionInfo> result;
@@ -910,15 +914,25 @@ Handle<JSFunction> Compiler::GetFunctionFromEval(Handle<String> source,
 }
 
 
-Handle<SharedFunctionInfo> Compiler::CompileScript(Handle<String> source,
-                                                   Handle<Object> script_name,
-                                                   int line_offset,
-                                                   int column_offset,
-                                                   bool is_shared_cross_origin,
-                                                   Handle<Context> context,
-                                                   v8::Extension* extension,
-                                                   ScriptDataImpl* pre_data,
-                                                   NativesFlag natives) {
+Handle<SharedFunctionInfo> Compiler::CompileScript(
+    Handle<String> source,
+    Handle<Object> script_name,
+    int line_offset,
+    int column_offset,
+    bool is_shared_cross_origin,
+    Handle<Context> context,
+    v8::Extension* extension,
+    ScriptDataImpl** cached_data,
+    CachedDataMode cached_data_mode,
+    NativesFlag natives) {
+  if (cached_data_mode == NO_CACHED_DATA) {
+    cached_data = NULL;
+  } else if (cached_data_mode == PRODUCE_CACHED_DATA) {
+    ASSERT(cached_data && !*cached_data);
+  } else {
+    ASSERT(cached_data_mode == CONSUME_CACHED_DATA);
+    ASSERT(cached_data && *cached_data);
+  }
   Isolate* isolate = source->GetIsolate();
   int source_length = source->length();
   isolate->counters()->total_load_size()->Increment(source_length);
@@ -963,7 +977,7 @@ Handle<SharedFunctionInfo> Compiler::CompileScript(Handle<String> source,
     CompilationInfoWithZone info(script);
     info.MarkAsGlobal();
     info.SetExtension(extension);
-    info.SetPreParseData(pre_data);
+    info.SetCachedData(cached_data, cached_data_mode);
     info.SetContext(context);
     if (FLAG_use_strict) info.SetStrictMode(STRICT);
     result = CompileToplevel(&info);
index f63475c..3802016 100644 (file)
@@ -45,6 +45,12 @@ enum ParseRestriction {
   ONLY_SINGLE_FUNCTION_LITERAL  // Only a single FunctionLiteral expression.
 };
 
+enum CachedDataMode {
+  NO_CACHED_DATA,
+  CONSUME_CACHED_DATA,
+  PRODUCE_CACHED_DATA
+};
+
 struct OffsetRange {
   OffsetRange(int from, int to) : from(from), to(to) {}
   int from;
@@ -77,7 +83,10 @@ class CompilationInfo {
   Handle<Script> script() const { return script_; }
   HydrogenCodeStub* code_stub() const {return code_stub_; }
   v8::Extension* extension() const { return extension_; }
-  ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
+  ScriptDataImpl** cached_data() const { return cached_data_; }
+  CachedDataMode cached_data_mode() const {
+    return cached_data_mode_;
+  }
   Handle<Context> context() const { return context_; }
   BailoutId osr_ast_id() const { return osr_ast_id_; }
   Handle<Code> unoptimized_code() const { return unoptimized_code_; }
@@ -180,9 +189,15 @@ class CompilationInfo {
     ASSERT(!is_lazy());
     extension_ = extension;
   }
-  void SetPreParseData(ScriptDataImpl* pre_parse_data) {
-    ASSERT(!is_lazy());
-    pre_parse_data_ = pre_parse_data;
+  void SetCachedData(ScriptDataImpl** cached_data,
+                     CachedDataMode cached_data_mode) {
+    cached_data_mode_ = cached_data_mode;
+    if (cached_data_mode == NO_CACHED_DATA) {
+      cached_data_ = NULL;
+    } else {
+      ASSERT(!is_lazy());
+      cached_data_ = cached_data;
+    }
   }
   void SetContext(Handle<Context> context) {
     context_ = context;
@@ -397,7 +412,8 @@ class CompilationInfo {
 
   // Fields possibly needed for eager compilation, NULL by default.
   v8::Extension* extension_;
-  ScriptDataImpl* pre_parse_data_;
+  ScriptDataImpl** cached_data_;
+  CachedDataMode cached_data_mode_;
 
   // The context of the caller for eval code, and the global context for a
   // global script. Will be a null handle otherwise.
@@ -617,15 +633,17 @@ class Compiler : public AllStatic {
                                                 int scope_position);
 
   // Compile a String source within a context.
-  static Handle<SharedFunctionInfo> CompileScript(Handle<String> source,
-                                                  Handle<Object> script_name,
-                                                  int line_offset,
-                                                  int column_offset,
-                                                  bool is_shared_cross_origin,
-                                                  Handle<Context> context,
-                                                  v8::Extension* extension,
-                                                  ScriptDataImpl* pre_data,
-                                                  NativesFlag is_natives_code);
+  static Handle<SharedFunctionInfo> CompileScript(
+      Handle<String> source,
+      Handle<Object> script_name,
+      int line_offset,
+      int column_offset,
+      bool is_shared_cross_origin,
+      Handle<Context> context,
+      v8::Extension* extension,
+      ScriptDataImpl** cached_data,
+      CachedDataMode cached_data_mode,
+      NativesFlag is_natives_code);
 
   // Create a shared function info object (the code may be lazily compiled).
   static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node,
index 539ebaa..d071105 100644 (file)
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -206,8 +206,9 @@ bool Shell::ExecuteString(Isolate* isolate,
     try_catch.SetVerbose(true);
   }
   ScriptOrigin origin(name);
-  Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
-      isolate, ScriptCompiler::Source(source, origin));
+  ScriptCompiler::Source script_source(source, origin);
+  Handle<UnboundScript> script =
+      ScriptCompiler::CompileUnbound(isolate, &script_source);
   if (script.IsEmpty()) {
     // Print errors that happened during compilation.
     if (report_exceptions && !FLAG_debugger)
@@ -407,8 +408,9 @@ void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
     Throw(args.GetIsolate(), "Invalid argument");
     return;
   }
+  ScriptCompiler::Source script_source(args[1]->ToString());
   Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
-      isolate, ScriptCompiler::Source(args[1]->ToString()));
+      isolate, &script_source);
   if (script.IsEmpty()) return;
   Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
   realm->Enter();
index a6dab2a..c8a99d5 100644 (file)
@@ -762,7 +762,7 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
                                           script_name, 0, 0,
                                           false,
                                           context,
-                                          NULL, NULL,
+                                          NULL, NULL, NO_CACHED_DATA,
                                           NATIVES_CODE);
 
   // Silently ignore stack overflows during compilation.
index 62e9cba..01bd853 100644 (file)
@@ -205,19 +205,6 @@ void RegExpBuilder::AddQuantifierToAtom(
 }
 
 
-Handle<String> Parser::LookupSymbol(int symbol_id) {
-  // If there is no preparser symbol data, a negative number will be passed. In
-  // that case, we'll just read the literal from Scanner. This also guards
-  // against corrupt preparse data where the symbol id is larger than the symbol
-  // count.
-  if (symbol_id < 0 ||
-      (pre_parse_data_ && symbol_id >= pre_parse_data_->symbol_count())) {
-    return scanner()->AllocateInternalizedString(isolate_);
-  }
-  return LookupCachedSymbol(symbol_id);
-}
-
-
 Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
   // Make sure the cache is large enough to hold the symbol identifier.
   if (symbol_cache_.length() <= symbol_id) {
@@ -600,11 +587,19 @@ void ParserTraits::ReportMessageAt(Scanner::Location source_location,
 
 
 Handle<String> ParserTraits::GetSymbol(Scanner* scanner) {
-  int symbol_id = -1;
-  if (parser_->pre_parse_data() != NULL) {
-    symbol_id = parser_->pre_parse_data()->GetSymbolIdentifier();
+  if (parser_->cached_data_mode() == CONSUME_CACHED_DATA) {
+    int symbol_id = (*parser_->cached_data())->GetSymbolIdentifier();
+    // If there is no symbol data, -1 will be returned.
+    if (symbol_id >= 0 &&
+        symbol_id < (*parser_->cached_data())->symbol_count()) {
+      return parser_->LookupCachedSymbol(symbol_id);
+    }
+  } else if (parser_->cached_data_mode() == PRODUCE_CACHED_DATA) {
+    if (parser_->log_->ShouldLogSymbols()) {
+      parser_->scanner()->LogSymbol(parser_->log_, parser_->position());
+    }
   }
-  return parser_->LookupSymbol(symbol_id);
+  return parser_->scanner()->AllocateInternalizedString(parser_->isolate_);
 }
 
 
@@ -702,6 +697,7 @@ Parser::Parser(CompilationInfo* info)
     : ParserBase<ParserTraits>(&scanner_,
                                info->isolate()->stack_guard()->real_climit(),
                                info->extension(),
+                               NULL,
                                info->zone(),
                                this),
       isolate_(info->isolate()),
@@ -711,7 +707,8 @@ Parser::Parser(CompilationInfo* info)
       reusable_preparser_(NULL),
       original_scope_(NULL),
       target_stack_(NULL),
-      pre_parse_data_(NULL),
+      cached_data_(NULL),
+      cached_data_mode_(NO_CACHED_DATA),
       info_(info) {
   ASSERT(!script_.is_null());
   isolate_->set_ast_node_id(0);
@@ -738,6 +735,13 @@ FunctionLiteral* Parser::ParseProgram() {
   fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
 
   // Initialize parser state.
+  CompleteParserRecorder recorder;
+  if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+    log_ = &recorder;
+  } else if (cached_data_mode_ == CONSUME_CACHED_DATA) {
+    (*cached_data_)->Initialize();
+  }
+
   source->TryFlatten();
   FunctionLiteral* result;
   if (source->IsExternalTwoByteString()) {
@@ -767,6 +771,11 @@ FunctionLiteral* Parser::ParseProgram() {
     }
     PrintF(" - took %0.3f ms]\n", ms);
   }
+  if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+    Vector<unsigned> store = recorder.ExtractData();
+    *cached_data_ = new ScriptDataImpl(store);
+    log_ = NULL;
+  }
   return result;
 }
 
@@ -775,7 +784,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
                                         Handle<String> source) {
   ASSERT(scope_ == NULL);
   ASSERT(target_stack_ == NULL);
-  if (pre_parse_data_ != NULL) pre_parse_data_->Initialize();
 
   Handle<String> no_name = isolate()->factory()->empty_string();
 
@@ -3580,11 +3588,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
     if (is_lazily_parsed) {
       int function_block_pos = position();
       FunctionEntry entry;
-      if (pre_parse_data_ != NULL) {
-        // If we have pre_parse_data_, we use it to skip parsing the function
-        // body.  The preparser data contains the information we need to
-        // construct the lazy function.
-        entry = pre_parse_data()->GetFunctionEntry(function_block_pos);
+      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.
+        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
@@ -3605,21 +3613,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
           // an entry for the function. As a safety net, fall back to eager
           // parsing. It is unclear whether PreParser's laziness analysis can
           // produce different results than the Parser's laziness analysis (see
-          // https://codereview.chromium.org/7565003 ). This safety net is
-          // guarding against the case where Parser thinks a function should be
-          // lazily parsed, but PreParser thinks it should be eagerly parsed --
-          // in that case we fall back to eager parsing in Parser, too. Note
-          // that the opposite case is worse: if PreParser thinks a function
-          // should be lazily parsed, but Parser thinks it should be eagerly
-          // parsed, it will never advance the preparse data beyond that
-          // function and all further laziness will fail (all functions will be
-          // parsed eagerly).
+          // https://codereview.chromium.org/7565003 ). In this case, we must
+          // discard all the preparse data, since the symbol data will be wrong.
           is_lazily_parsed = false;
+          cached_data_mode_ = NO_CACHED_DATA;
         }
       } else {
-        // With no preparser data, we partially parse the function, without
+        // With no cached data, we partially parse the function, without
         // building an AST. This gathers the data needed to build a lazy
         // function.
+        // FIXME(marja): Now the PreParser doesn't need to log functions /
+        // symbols; only errors -> clean that up.
         SingletonLogger logger;
         PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger);
         if (result == PreParser::kPreParseStackOverflow) {
@@ -3648,6 +3652,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
         materialized_literal_count = logger.literals();
         expected_property_count = logger.properties();
         scope_->SetStrictMode(logger.strict_mode());
+        if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+          ASSERT(log_);
+          // Position right after terminal '}'.
+          int body_end = scanner()->location().end_pos;
+          log_->LogFunction(function_block_pos, body_end,
+                            materialized_literal_count,
+                            expected_property_count,
+                            scope_->strict_mode());
+        }
       }
     }
 
@@ -4922,12 +4935,13 @@ bool Parser::Parse() {
       result = ParseProgram();
     }
   } else {
-    ScriptDataImpl* pre_parse_data = info()->pre_parse_data();
-    set_pre_parse_data(pre_parse_data);
-    if (pre_parse_data != NULL && pre_parse_data->has_error()) {
-      Scanner::Location loc = pre_parse_data->MessageLocation();
-      const char* message = pre_parse_data->BuildMessage();
-      Vector<const char*> args = pre_parse_data->BuildArgs();
+    SetCachedData(info()->cached_data(), info()->cached_data_mode());
+    if (info()->cached_data_mode() == CONSUME_CACHED_DATA &&
+        (*info()->cached_data())->has_error()) {
+      ScriptDataImpl* cached_data = *(info()->cached_data());
+      Scanner::Location loc = cached_data->MessageLocation();
+      const char* message = cached_data->BuildMessage();
+      Vector<const char*> args = cached_data->BuildArgs();
       ParserTraits::ReportMessageAt(loc, message, args);
       DeleteArray(message);
       for (int i = 0; i < args.length(); i++) {
index 0c9857a..072658e 100644 (file)
 
 #include "allocation.h"
 #include "ast.h"
+#include "compiler.h"  // For CachedDataMode
 #include "preparse-data-format.h"
 #include "preparse-data.h"
 #include "scopes.h"
 #include "preparser.h"
 
 namespace v8 {
+class ScriptCompiler;
+
 namespace internal {
 
 class CompilationInfo;
@@ -117,6 +120,7 @@ class ScriptDataImpl : public ScriptData {
   unsigned version() { return store_[PreparseDataConstants::kVersionOffset]; }
 
  private:
+  friend class v8::ScriptCompiler;
   Vector<unsigned> store_;
   unsigned char* symbol_data_;
   unsigned char* symbol_data_end_;
@@ -649,14 +653,22 @@ class Parser : public ParserBase<ParserTraits> {
   // Report syntax error
   void ReportInvalidPreparseData(Handle<String> name, bool* ok);
 
-  void set_pre_parse_data(ScriptDataImpl *data) {
-    pre_parse_data_ = data;
-    symbol_cache_.Initialize(data ? data->symbol_count() : 0, zone());
+  void SetCachedData(ScriptDataImpl** 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;
+      symbol_cache_.Initialize(*data ? (*data)->symbol_count() : 0, zone());
+    }
   }
 
   bool inside_with() const { return scope_->inside_with(); }
   Mode mode() const { return mode_; }
-  ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
+  ScriptDataImpl** cached_data() const { return cached_data_; }
+  CachedDataMode cached_data_mode() const { return cached_data_mode_; }
   Scope* DeclarationScope(VariableMode mode) {
     return IsLexicalVariableMode(mode)
         ? scope_ : scope_->DeclarationScope();
@@ -770,8 +782,6 @@ class Parser : public ParserBase<ParserTraits> {
 
   Scope* NewScope(Scope* parent, ScopeType type);
 
-  Handle<String> LookupSymbol(int symbol_id);
-
   Handle<String> LookupCachedSymbol(int symbol_id);
 
   // Generate AST node that throw a ReferenceError with the given type.
@@ -804,7 +814,8 @@ 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
-  ScriptDataImpl* pre_parse_data_;
+  ScriptDataImpl** cached_data_;
+  CachedDataMode cached_data_mode_;
 
   Mode mode_;
 
index 57ec6ff..a060c03 100644 (file)
@@ -87,6 +87,7 @@ class ParserBase : public Traits {
 
   ParserBase(Scanner* scanner, uintptr_t stack_limit,
              v8::Extension* extension,
+             ParserRecorder* log,
              typename Traits::Type::Zone* zone,
              typename Traits::Type::Parser this_object)
       : Traits(this_object),
@@ -95,6 +96,7 @@ class ParserBase : public Traits {
         function_state_(NULL),
         extension_(extension),
         fni_(NULL),
+        log_(log),
         scanner_(scanner),
         stack_limit_(stack_limit),
         stack_overflow_(false),
@@ -457,6 +459,7 @@ class ParserBase : public Traits {
   FunctionState* function_state_;  // Function state stack.
   v8::Extension* extension_;
   FuncNameInferrer* fni_;
+  ParserRecorder* log_;
 
  private:
   Scanner* scanner_;
@@ -948,11 +951,9 @@ class PreParser : public ParserBase<PreParserTraits> {
     kPreParseSuccess
   };
 
-  PreParser(Scanner* scanner,
-            ParserRecorder* log,
-            uintptr_t stack_limit)
-      : ParserBase<PreParserTraits>(scanner, stack_limit, NULL, NULL, this),
-        log_(log) {}
+  PreParser(Scanner* scanner, ParserRecorder* log, uintptr_t stack_limit)
+      : ParserBase<PreParserTraits>(scanner, stack_limit, NULL, log, NULL,
+                                    this) {}
 
   // Pre-parse the program from the character stream; returns true on
   // success (even if parsing failed, the pre-parse data successfully
@@ -1111,11 +1112,8 @@ class PreParser : public ParserBase<PreParserTraits> {
   Expression GetStringSymbol();
 
   bool CheckInOrOf(bool accept_OF);
-
-  ParserRecorder* log_;
 };
 
-
 template<class Traits>
 ParserBase<Traits>::FunctionState::FunctionState(
     FunctionState** function_state_stack,
index 9319510..6359835 100644 (file)
@@ -316,8 +316,9 @@ static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
 static inline v8::Local<v8::Script> CompileWithOrigin(
     v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
   v8::ScriptOrigin origin(origin_url);
+  v8::ScriptCompiler::Source script_source(source, origin);
   return v8::ScriptCompiler::Compile(
-      v8::Isolate::GetCurrent(), v8::ScriptCompiler::Source(source, origin));
+      v8::Isolate::GetCurrent(), &script_source);
 }
 
 
@@ -350,11 +351,11 @@ static inline v8::Local<v8::Value> PreCompileCompileRun(const char* source) {
       v8::String::NewFromUtf8(isolate, source);
   v8::ScriptData* preparse = v8::ScriptData::PreCompile(source_string);
   v8::ScriptCompiler::Source script_source(
-      source_string, v8::ScriptCompiler::CachedData(
+      source_string, new v8::ScriptCompiler::CachedData(
                          reinterpret_cast<const uint8_t*>(preparse->Data()),
                          preparse->Length()));
-  v8::Local<v8::Script> script = v8::ScriptCompiler::Compile(
-      isolate, v8::ScriptCompiler::Source(script_source));
+  v8::Local<v8::Script> script =
+      v8::ScriptCompiler::Compile(isolate, &script_source);
   v8::Local<v8::Value> result = script->Run();
   delete preparse;
   return result;
@@ -370,18 +371,17 @@ static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
   v8::ScriptOrigin origin(v8_str(origin_url),
                           v8::Integer::New(isolate, line_number),
                           v8::Integer::New(isolate, column_number));
-  return v8::ScriptCompiler::Compile(
-             isolate, v8::ScriptCompiler::Source(v8_str(source), origin))
-      ->Run();
+  v8::ScriptCompiler::Source script_source(v8_str(source), origin);
+  return v8::ScriptCompiler::Compile(isolate, &script_source)->Run();
 }
 
 
 static inline v8::Local<v8::Value> CompileRunWithOrigin(
     v8::Local<v8::String> source, const char* origin_url) {
-  v8::ScriptOrigin origin(v8_str(origin_url));
-  return v8::ScriptCompiler::Compile(
-      v8::Isolate::GetCurrent(),
-      v8::ScriptCompiler::Source(source, origin))->Run();
+  v8::ScriptCompiler::Source script_source(
+      source, v8::ScriptOrigin(v8_str(origin_url)));
+  return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &script_source)
+      ->Run();
 }
 
 
index d8214e1..26420b5 100644 (file)
@@ -14956,10 +14956,10 @@ TEST(PreCompileInvalidPreparseDataError) {
 
   v8::ScriptCompiler::Source script_source(
       String::NewFromUtf8(isolate, script),
-      v8::ScriptCompiler::CachedData(
+      new v8::ScriptCompiler::CachedData(
           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
   Local<v8::UnboundScript> compiled_script =
-      v8::ScriptCompiler::CompileUnbound(isolate, script_source);
+      v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
 
   CHECK(try_catch.HasCaught());
   String::Utf8Value exception_value(try_catch.Message()->Get());
@@ -14979,10 +14979,10 @@ TEST(PreCompileInvalidPreparseDataError) {
       200;
   v8::ScriptCompiler::Source script_source2(
       String::NewFromUtf8(isolate, script),
-      v8::ScriptCompiler::CachedData(
+      new v8::ScriptCompiler::CachedData(
           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
   compiled_script =
-      v8::ScriptCompiler::CompileUnbound(isolate, script_source2);
+      v8::ScriptCompiler::CompileUnbound(isolate, &script_source2);
   CHECK(!try_catch.HasCaught());
 
   delete sd;
@@ -17091,12 +17091,11 @@ THREADED_TEST(ScriptContextDependence) {
   LocalContext c1;
   v8::HandleScope scope(c1->GetIsolate());
   const char *source = "foo";
-  v8::Handle<v8::Script> dep =
-      v8_compile(source);
+  v8::Handle<v8::Script> dep = v8_compile(source);
+  v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
+      c1->GetIsolate(), source));
   v8::Handle<v8::UnboundScript> indep =
-      v8::ScriptCompiler::CompileUnbound(
-          c1->GetIsolate(), v8::ScriptCompiler::Source(v8::String::NewFromUtf8(
-                                c1->GetIsolate(), source)));
+      v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
                     v8::Integer::New(c1->GetIsolate(), 100));
   CHECK_EQ(dep->Run()->Int32Value(), 100);
@@ -17118,9 +17117,8 @@ THREADED_TEST(StackTrace) {
       v8::String::NewFromUtf8(context->GetIsolate(), source);
   v8::Handle<v8::String> origin =
       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
-  v8::ScriptCompiler::CompileUnbound(
-      context->GetIsolate(),
-      v8::ScriptCompiler::Source(src, v8::ScriptOrigin(origin)))
+  v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
+  v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
       ->BindToCurrentContext()
       ->Run();
   CHECK(try_catch.HasCaught());
@@ -17228,10 +17226,10 @@ TEST(CaptureStackTrace) {
     "var x;eval('new foo();');";
   v8::Handle<v8::String> overview_src =
       v8::String::NewFromUtf8(isolate, overview_source);
+  v8::ScriptCompiler::Source script_source(overview_src,
+                                           v8::ScriptOrigin(origin));
   v8::Handle<Value> overview_result(
-      v8::ScriptCompiler::CompileUnbound(
-          isolate,
-          v8::ScriptCompiler::Source(overview_src, v8::ScriptOrigin(origin)))
+      v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
           ->BindToCurrentContext()
           ->Run());
   CHECK(!overview_result.IsEmpty());
@@ -17252,9 +17250,9 @@ TEST(CaptureStackTrace) {
   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
+  v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
   v8::Handle<v8::UnboundScript> detailed_script(
-      v8::ScriptCompiler::CompileUnbound(
-          isolate, v8::ScriptCompiler::Source(detailed_src, detailed_origin)));
+      v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
   v8::Handle<Value> detailed_result(
       detailed_script->BindToCurrentContext()->Run());
   CHECK(!detailed_result.IsEmpty());
index 120a053..6540c5d 100644 (file)
@@ -66,7 +66,7 @@ static Handle<JSFunction> Compile(const char* source) {
                               0,
                               false,
                               Handle<Context>(isolate->native_context()),
-                              NULL, NULL,
+                              NULL, NULL, NO_CACHED_DATA,
                               NOT_NATIVES_CODE);
   return isolate->factory()->NewFunctionFromSharedFunctionInfo(
       shared_function, isolate->native_context());
index 9dfabe1..b51cb77 100644 (file)
@@ -7007,16 +7007,16 @@ TEST(GetMirror) {
   v8::HandleScope scope(isolate);
   v8::Handle<v8::Value> obj =
       v8::Debug::GetMirror(v8::String::NewFromUtf8(isolate, "hodja"));
-  v8::Handle<v8::Function> run_test =
-      v8::Handle<v8::Function>::Cast(
-          v8::ScriptCompiler::CompileUnbound(
-              isolate,
-              v8::ScriptCompiler::Source(v8_str(
-                  "function runTest(mirror) {"
-                  "  return mirror.isString() && (mirror.length() == 5);"
-                  "}"
-                  ""
-                  "runTest;")))->BindToCurrentContext()->Run());
+  v8::ScriptCompiler::Source source(v8_str(
+      "function runTest(mirror) {"
+      "  return mirror.isString() && (mirror.length() == 5);"
+      "}"
+      ""
+      "runTest;"));
+  v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
+      v8::ScriptCompiler::CompileUnbound(isolate, &source)
+          ->BindToCurrentContext()
+          ->Run());
   v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
   CHECK(result->IsTrue());
 }
index 2e282ce..5a2ee13 100644 (file)
@@ -215,11 +215,11 @@ TEST(Preparsing) {
     ScriptResource* resource = new ScriptResource(source, source_length);
     v8::ScriptCompiler::Source script_source(
         v8::String::NewExternal(isolate, resource),
-        v8::ScriptCompiler::CachedData(
+        new v8::ScriptCompiler::CachedData(
             reinterpret_cast<const uint8_t*>(preparse->Data()),
             preparse->Length()));
     v8::ScriptCompiler::Compile(isolate,
-                                v8::ScriptCompiler::Source(script_source));
+                                &script_source);
   }
 
   {
@@ -228,10 +228,10 @@ TEST(Preparsing) {
     ScriptResource* resource = new ScriptResource(source, source_length);
     v8::ScriptCompiler::Source script_source(
         v8::String::NewExternal(isolate, resource),
-        v8::ScriptCompiler::CachedData(
+        new v8::ScriptCompiler::CachedData(
             reinterpret_cast<const uint8_t*>(preparse->Data()),
             preparse->Length()));
-    v8::ScriptCompiler::CompileUnbound(isolate, script_source);
+    v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
   }
   delete preparse;
   i::FLAG_lazy = lazy_flag;
@@ -263,6 +263,10 @@ TEST(Preparsing) {
 TEST(PreparseFunctionDataIsUsed) {
   // This tests that we actually do use the function data generated by the
   // preparser.
+
+  // Make preparsing work for short scripts.
+  i::FLAG_min_preparse_length = 0;
+
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope handles(isolate);
   v8::Local<v8::Context> context = v8::Context::New(isolate);
@@ -271,28 +275,31 @@ TEST(PreparseFunctionDataIsUsed) {
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
 
-  const char* good_source =
+  const char* good_code =
       "function this_is_lazy() { var a; } function foo() { return 25; } foo();";
 
   // Insert a syntax error inside the lazy function.
-  const char* bad_source =
+  const char* bad_code =
       "function this_is_lazy() { if (   } function foo() { return 25; } foo();";
 
-  v8::ScriptData* preparse = v8::ScriptData::PreCompile(v8_str(good_source));
-  CHECK(!preparse->HasError());
+  v8::ScriptCompiler::Source good_source(v8_str(good_code));
+  v8::ScriptCompiler::Compile(isolate, &good_source,
+                              v8::ScriptCompiler::kProduceDataToCache);
+
+  const v8::ScriptCompiler::CachedData* cached_data =
+      good_source.GetCachedData();
+  CHECK(cached_data->data != NULL);
+  CHECK_GT(cached_data->length, 0);
 
   // Now compile the erroneous code with the good preparse data. If the preparse
   // data is used, the lazy function is skipped and it should compile fine.
-  v8::ScriptCompiler::Source source(
-      v8_str(bad_source),
-      v8::ScriptCompiler::CachedData(
-          reinterpret_cast<const uint8_t*>(preparse->Data()),
-          preparse->Length()));
+  v8::ScriptCompiler::Source bad_source(
+      v8_str(bad_code), new v8::ScriptCompiler::CachedData(
+                            cached_data->data, cached_data->length));
   v8::Local<v8::Value> result =
-      v8::ScriptCompiler::Compile(CcTest::isolate(), source)->Run();
+      v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
   CHECK(result->IsInt32());
   CHECK_EQ(25, result->Int32Value());
-  delete preparse;
 }
 
 
@@ -304,6 +311,9 @@ TEST(PreparseSymbolDataIsUsed) {
   // source code again without preparse data and it will fail).
   i::FLAG_crankshaft = false;
 
+  // Make preparsing work for short scripts.
+  i::FLAG_min_preparse_length = 0;
+
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope handles(isolate);
   v8::Local<v8::Context> context = v8::Context::New(isolate);
@@ -313,30 +323,33 @@ TEST(PreparseSymbolDataIsUsed) {
       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
 
   // Note that the ( before function makes the function not lazily compiled.
-  const char* good_source =
+  const char* good_code =
       "(function weird() { var foo = 26; return foo; })()";
 
   // Insert an undefined identifier. If the preparser data is used, the symbol
   // stream is used instead, and this identifier resolves to "foo".
-  const char* bad_source =
+  const char* bad_code =
       "(function weird() { var foo = 26; return wut; })()";
 
-  v8::ScriptData* preparse = v8::ScriptData::PreCompile(v8_str(good_source));
-  CHECK(!preparse->HasError());
+  v8::ScriptCompiler::Source good_source(v8_str(good_code));
+  v8::ScriptCompiler::Compile(isolate, &good_source,
+                              v8::ScriptCompiler::kProduceDataToCache);
+
+  const v8::ScriptCompiler::CachedData* cached_data =
+      good_source.GetCachedData();
+  CHECK(cached_data->data != NULL);
+  CHECK_GT(cached_data->length, 0);
 
   // Now compile the erroneous code with the good preparse data. If the preparse
   // data is used, we will see a second occurrence of "foo" instead of the
   // unknown "wut".
-  v8::ScriptCompiler::Source source(
-      v8_str(bad_source),
-      v8::ScriptCompiler::CachedData(
-          reinterpret_cast<const uint8_t*>(preparse->Data()),
-          preparse->Length()));
+  v8::ScriptCompiler::Source bad_source(
+      v8_str(bad_code), new v8::ScriptCompiler::CachedData(
+                            cached_data->data, cached_data->length));
   v8::Local<v8::Value> result =
-      v8::ScriptCompiler::Compile(CcTest::isolate(), source)->Run();
+      v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
   CHECK(result->IsInt32());
   CHECK_EQ(26, result->Int32Value());
-  delete preparse;
 }