New Compilation API, part 1, try 2
authormarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 14 Mar 2014 10:20:33 +0000 (10:20 +0000)
committermarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 14 Mar 2014 10:20:33 +0000 (10:20 +0000)
- Distinguish between context bound scripts (Script) and context unbound scripts
(UnboundScript).
- Add ScriptCompiler (which will later contain functions for async compilation).

This is a breaking change, in particular, Script::New no longer exists (it is
replaced by ScriptCompiler::CompileUnbound). Script::Compile remains as a
backwards-compatible shorthand for ScriptCompiler::Compile.

Passing CompilerOptions with produce_data_to_cache = true doesn't do anything
yet; the only way to generate the data to cache is the old preparsing API. (To
be fixed in the next version.)

This is a fixed version of https://codereview.chromium.org/186723005/

BUG=
R=dcarney@chromium.org

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

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

14 files changed:
include/v8.h
samples/lineprocessor.cc
samples/shell.cc
src/api.cc
src/api.h
src/d8.cc
src/heap.cc
src/profile-generator-inl.h
test/cctest/cctest.h
test/cctest/test-api.cc
test/cctest/test-cpu-profiler.cc
test/cctest/test-debug.cc
test/cctest/test-log.cc
test/cctest/test-parsing.cc

index 9bda3dc..fdaa2a2 100644 (file)
@@ -108,6 +108,7 @@ class ObjectTemplate;
 class Platform;
 class Primitive;
 class RawOperationDescriptor;
+class Script;
 class Signature;
 class StackFrame;
 class StackTrace;
@@ -1146,95 +1147,156 @@ class ScriptOrigin {
 
 
 /**
- * A compiled JavaScript script.
+ * A compiled JavaScript script, not yet tied to a Context.
  */
-class V8_EXPORT Script {
+class V8_EXPORT UnboundScript {
  public:
   /**
-   * Compiles the specified script (context-independent).
-   *
-   * \param source Script source code.
-   * \param origin Script origin, owned by caller, no references are kept
-   *   when New() returns
-   * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
-   *   using pre_data speeds compilation if it's done multiple times.
-   *   Owned by caller, no references are kept when New() returns.
-   * \return Compiled script object (context independent; when run it
-   *   will use the currently entered context).
+   * Binds the script to the currently entered context.
    */
-  static Local<Script> New(Handle<String> source,
-                           ScriptOrigin* origin = NULL,
-                           ScriptData* pre_data = NULL);
+  Local<Script> BindToCurrentContext();
+
+  int GetId();
+  Handle<Value> GetScriptName();
 
   /**
-   * Compiles the specified script using the specified file name
-   * object (typically a string) as the script's origin.
-   *
-   * \param source Script source code.
-   * \param file_name file name object (typically a string) to be used
-   *   as the script's origin.
-   * \return Compiled script object (context independent; when run it
-   *   will use the currently entered context).
+   * Returns zero based line number of the code_pos location in the script.
+   * -1 will be returned if no information available.
    */
-  static Local<Script> New(Handle<String> source,
-                           Handle<Value> file_name);
+  int GetLineNumber(int code_pos);
+
+  static const int kNoScriptId = 0;
+};
+
 
+/**
+ * A compiled JavaScript script, tied to a Context which was active when the
+ * script was compiled.
+ */
+class V8_EXPORT Script {
+ public:
   /**
-   * Compiles the specified script (bound to current context).
-   *
-   * \param source Script source code.
-   * \param origin Script origin, owned by caller, no references are kept
-   *   when Compile() returns
-   * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
-   *   using pre_data speeds compilation if it's done multiple times.
-   *   Owned by caller, no references are kept when Compile() returns.
-   * \return Compiled script object, bound to the context that was active
-   *   when this function was called.  When run it will always use this
-   *   context.
+   * A shorthand for ScriptCompiler::Compile().
+   * The ScriptData parameter will be deprecated; use ScriptCompiler::Compile if
+   * you want to pass it.
    */
   static Local<Script> Compile(Handle<String> source,
                                ScriptOrigin* origin = NULL,
-                               ScriptData* pre_data = NULL);
+                               ScriptData* script_data = NULL);
 
-  /**
-   * Compiles the specified script using the specified file name
-   * object (typically a string) as the script's origin.
-   *
-   * \param source Script source code.
-   * \param file_name File name to use as script's origin
-   * \return Compiled script object, bound to the context that was active
-   *   when this function was called.  When run it will always use this
-   *   context.
-   */
+  // To be decprecated, use the Compile above.
   static Local<Script> Compile(Handle<String> source,
-                               Handle<Value> file_name);
+                               Handle<String> file_name);
 
   /**
-   * Runs the script returning the resulting value.  If the script is
-   * context independent (created using ::New) it will be run in the
-   * currently entered context.  If it is context specific (created
-   * using ::Compile) it will be run in the context in which it was
-   * compiled.
+   * Runs the script returning the resulting value. It will be run in the
+   * context in which it was created (ScriptCompiler::CompileBound or
+   * UnboundScript::BindToGlobalContext()).
    */
   Local<Value> Run();
 
   /**
-   * Returns the script id.
+   * Returns the corresponding context-unbound script.
    */
-  int GetId();
+  Local<UnboundScript> GetUnboundScript();
 
-  /**
-   * Returns the name value of one Script.
-   */
-  Handle<Value> GetScriptName();
+  // To be deprecated; use GetUnboundScript()->GetId();
+  int GetId() {
+    return GetUnboundScript()->GetId();
+  }
+
+  // Use GetUnboundScript()->GetId();
+  V8_DEPRECATED("Use GetUnboundScript()->GetId()",
+                Handle<Value> GetScriptName()) {
+    return GetUnboundScript()->GetScriptName();
+  }
 
   /**
    * Returns zero based line number of the code_pos location in the script.
    * -1 will be returned if no information available.
    */
-  int GetLineNumber(int code_pos);
+  V8_DEPRECATED("Use GetUnboundScript()->GetLineNumber()",
+                int GetLineNumber(int code_pos)) {
+    return GetUnboundScript()->GetLineNumber(code_pos);
+  }
+};
 
-  static const int kNoScriptId = 0;
+
+/**
+ * For compiling scripts.
+ */
+class V8_EXPORT ScriptCompiler {
+ public:
+  /**
+   * Compilation data that the embedder can cache and pass back to speed up
+   * future compilations. The data is produced if the CompilerOptions passed to
+   * the compilation functions in ScriptCompiler contains produce_data_to_cache
+   * = true. The data to cache can then can be retrieved from
+   * 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) {}
+    // 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;
+  };
+
+  /**
+   * Source code which can be then compiled to a UnboundScript or
+   * BoundScript.
+   */
+  struct V8_EXPORT Source {
+    Source(Local<String> source_string, const ScriptOrigin& origin,
+           const CachedData& cached_data = CachedData());
+    Source(Local<String> source_string,
+           const CachedData& cached_data = CachedData());
+
+    Local<String> source_string;
+
+    // Origin information
+    Handle<Value> resource_name;
+    Handle<Integer> resource_line_offset;
+    Handle<Integer> resource_column_offset;
+    Handle<Boolean> resource_is_shared_cross_origin;
+
+    // Cached data from previous compilation (if any).
+    CachedData cached_data;
+  };
+
+  enum CompileOptions {
+    kNoCompileOptions,
+    kProduceDataToCache = 1 << 0
+  };
+
+  /**
+   * Compiles the specified script (context-independent).
+   *
+   * \param source Script source code.
+   * \return Compiled script object (context independent; for running it must be
+   *   bound to a context).
+   */
+  static Local<UnboundScript> CompileUnbound(
+      Isolate* isolate, const Source& source,
+      CompileOptions options = kNoCompileOptions);
+
+  /**
+   * Compiles the specified script (bound to current context).
+   *
+   * \param source Script source code.
+   * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
+   *   using pre_data speeds compilation if it's done multiple times.
+   *   Owned by caller, no references are kept when this function returns.
+   * \return Compiled script object, bound to the context that was active
+   *   when this function was called. When run it will always use this
+   *   context.
+   */
+  static Local<Script> Compile(
+      Isolate* isolate, const Source& source,
+      CompileOptions options = kNoCompileOptions);
 };
 
 
index 1d6a3bd..a8ad031 100644 (file)
@@ -238,7 +238,8 @@ int RunMain(int argc, char* argv[]) {
   {
     // Compile script in try/catch context.
     v8::TryCatch try_catch;
-    script = v8::Script::Compile(script_source, script_name);
+    v8::ScriptOrigin origin(script_name);
+    script = v8::Script::Compile(script_source, &origin);
     if (script.IsEmpty()) {
       // Print errors that happened during compilation.
       if (report_exceptions)
index 92a4732..f8d2c84 100644 (file)
@@ -304,7 +304,8 @@ bool ExecuteString(v8::Isolate* isolate,
                    bool report_exceptions) {
   v8::HandleScope handle_scope(isolate);
   v8::TryCatch try_catch;
-  v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
+  v8::ScriptOrigin origin(name);
+  v8::Handle<v8::Script> script = v8::Script::Compile(source, &origin);
   if (script.IsEmpty()) {
     // Print errors that happened during compilation.
     if (report_exceptions)
index 8269fd9..0418506 100644 (file)
@@ -1611,107 +1611,89 @@ ScriptData* ScriptData::New(const char* data, int length) {
 }
 
 
-// --- S c r i p t ---
+// --- S c r i p t ---
 
 
-Local<Script> Script::New(v8::Handle<String> source,
-                          v8::ScriptOrigin* origin,
-                          v8::ScriptData* pre_data) {
-  i::Handle<i::String> str = Utils::OpenHandle(*source);
-  i::Isolate* isolate = str->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
-  LOG_API(isolate, "Script::New");
-  ENTER_V8(isolate);
-  i::SharedFunctionInfo* raw_result = NULL;
-  { i::HandleScope scope(isolate);
-    i::Handle<i::Object> name_obj;
-    int line_offset = 0;
-    int column_offset = 0;
-    bool is_shared_cross_origin = false;
-    if (origin != NULL) {
-      if (!origin->ResourceName().IsEmpty()) {
-        name_obj = Utils::OpenHandle(*origin->ResourceName());
-      }
-      if (!origin->ResourceLineOffset().IsEmpty()) {
-        line_offset = static_cast<int>(origin->ResourceLineOffset()->Value());
-      }
-      if (!origin->ResourceColumnOffset().IsEmpty()) {
-        column_offset =
-            static_cast<int>(origin->ResourceColumnOffset()->Value());
-      }
-      if (!origin->ResourceIsSharedCrossOrigin().IsEmpty()) {
-        v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
-        is_shared_cross_origin =
-            origin->ResourceIsSharedCrossOrigin() == v8::True(v8_isolate);
-      }
-    }
-    EXCEPTION_PREAMBLE(isolate);
-    i::ScriptDataImpl* pre_data_impl =
-        static_cast<i::ScriptDataImpl*>(pre_data);
-    // 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()) {
-      pre_data_impl = NULL;
-    }
-    i::Handle<i::SharedFunctionInfo> result =
-        i::Compiler::CompileScript(str,
-                                   name_obj,
-                                   line_offset,
-                                   column_offset,
-                                   is_shared_cross_origin,
-                                   isolate->global_context(),
-                                   NULL,
-                                   pre_data_impl,
-                                   i::NOT_NATIVES_CODE);
-    has_pending_exception = result.is_null();
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
-    raw_result = *result;
-  }
-  i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
-  return ToApiHandle<Script>(result);
+// Internally, UnboundScript is a SharedFunctionInfo, and Script is a
+// JSFunction.
+
+ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin,
+                               const CachedData& data)
+    : source_string(string),
+      resource_name(origin.ResourceName()),
+      resource_line_offset(origin.ResourceLineOffset()),
+      resource_column_offset(origin.ResourceColumnOffset()),
+      resource_is_shared_cross_origin(origin.ResourceIsSharedCrossOrigin()),
+      cached_data(data) {}
+
+
+ScriptCompiler::Source::Source(Local<String> string,
+                               const CachedData& data)
+    : source_string(string), cached_data(data) {}
+
+
+Local<Script> UnboundScript::BindToCurrentContext() {
+  i::Handle<i::HeapObject> obj =
+      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+  i::Handle<i::SharedFunctionInfo>
+      function_info(i::SharedFunctionInfo::cast(*obj), obj->GetIsolate());
+  i::Handle<i::JSFunction> function =
+      obj->GetIsolate()->factory()->NewFunctionFromSharedFunctionInfo(
+          function_info, obj->GetIsolate()->global_context());
+  return ToApiHandle<Script>(function);
 }
 
 
-Local<Script> Script::New(v8::Handle<String> source,
-                          v8::Handle<Value> file_name) {
-  ScriptOrigin origin(file_name);
-  return New(source, &origin);
+int UnboundScript::GetId() {
+  i::Handle<i::HeapObject> obj =
+      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+  i::Isolate* isolate = obj->GetIsolate();
+  ON_BAILOUT(isolate, "v8::UnboundScript::GetId()", return -1);
+  LOG_API(isolate, "v8::UnboundScript::GetId");
+  {
+    i::HandleScope scope(isolate);
+    i::Handle<i::SharedFunctionInfo> function_info(
+        i::SharedFunctionInfo::cast(*obj));
+    i::Handle<i::Script> script(i::Script::cast(function_info->script()));
+    return script->id()->value();
+  }
 }
 
 
-Local<Script> Script::Compile(v8::Handle<String> source,
-                              v8::ScriptOrigin* origin,
-                              v8::ScriptData* pre_data) {
-  i::Handle<i::String> str = Utils::OpenHandle(*source);
-  i::Isolate* isolate = str->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
-  LOG_API(isolate, "Script::Compile");
-  ENTER_V8(isolate);
-  Local<Script> generic = New(source, origin, pre_data);
-  if (generic.IsEmpty())
-    return generic;
-  i::Handle<i::Object> obj = Utils::OpenHandle(*generic);
-  i::Handle<i::SharedFunctionInfo> function =
-      i::Handle<i::SharedFunctionInfo>(i::SharedFunctionInfo::cast(*obj));
-  i::Handle<i::JSFunction> result =
-      isolate->factory()->NewFunctionFromSharedFunctionInfo(
-          function,
-          isolate->global_context());
-  return ToApiHandle<Script>(result);
+int UnboundScript::GetLineNumber(int code_pos) {
+  i::Handle<i::HeapObject> obj =
+      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+  i::Isolate* isolate = obj->GetIsolate();
+  ON_BAILOUT(isolate, "v8::UnboundScript::GetLineNumber()", return -1);
+  LOG_API(isolate, "UnboundScript::GetLineNumber");
+  if (obj->IsScript()) {
+    i::Handle<i::Script> script(i::Script::cast(*obj));
+    return i::GetScriptLineNumber(script, code_pos);
+  } else {
+    return -1;
+  }
 }
 
 
-Local<Script> Script::Compile(v8::Handle<String> source,
-                              v8::Handle<Value> file_name) {
-  ScriptOrigin origin(file_name);
-  return Compile(source, &origin);
+Handle<Value> UnboundScript::GetScriptName() {
+  i::Handle<i::HeapObject> obj =
+      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+  i::Isolate* isolate = obj->GetIsolate();
+  ON_BAILOUT(isolate, "v8::UnboundScript::GetName()",
+             return Handle<String>());
+  LOG_API(isolate, "UnboundScript::GetName");
+  if (obj->IsScript()) {
+    i::Object* name = i::Script::cast(*obj)->name();
+    return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
+  } else {
+    return Handle<String>();
+  }
 }
 
 
 Local<Value> Script::Run() {
-  // If execution is terminating, Compile(script)->Run() requires this check.
+  // If execution is terminating, Compile(..)->Run() requires this
+  // check.
   if (this == NULL) return Local<Value>();
   i::Handle<i::HeapObject> obj =
       i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
@@ -1724,15 +1706,8 @@ Local<Value> Script::Run() {
   i::Object* raw_result = NULL;
   {
     i::HandleScope scope(isolate);
-    i::Handle<i::JSFunction> fun;
-    if (obj->IsSharedFunctionInfo()) {
-      i::Handle<i::SharedFunctionInfo>
-          function_info(i::SharedFunctionInfo::cast(*obj), isolate);
-      fun = isolate->factory()->NewFunctionFromSharedFunctionInfo(
-          function_info, isolate->global_context());
-    } else {
-      fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
-    }
+    i::Handle<i::JSFunction> fun =
+        i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
     EXCEPTION_PREAMBLE(isolate);
     i::Handle<i::Object> receiver(
         isolate->context()->global_proxy(), isolate);
@@ -1746,62 +1721,124 @@ Local<Value> Script::Run() {
 }
 
 
-static i::Handle<i::SharedFunctionInfo> OpenScript(Script* script) {
-  i::Handle<i::Object> obj = Utils::OpenHandle(script);
-  i::Handle<i::SharedFunctionInfo> result;
-  if (obj->IsSharedFunctionInfo()) {
-    result =
-        i::Handle<i::SharedFunctionInfo>(i::SharedFunctionInfo::cast(*obj));
-  } else {
-    result =
-        i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared());
-  }
-  return result;
+Local<UnboundScript> Script::GetUnboundScript() {
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return ToApiHandle<UnboundScript>(
+      i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared()));
 }
 
 
-int Script::GetId() {
-  i::Handle<i::HeapObject> obj =
-      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
-  i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Script::Id()", return -1);
-  LOG_API(isolate, "Script::Id");
-  {
-    i::HandleScope scope(isolate);
-    i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
-    i::Handle<i::Script> script(i::Script::cast(function_info->script()));
-    return script->id()->value();
+Local<UnboundScript> ScriptCompiler::CompileUnbound(
+    Isolate* v8_isolate,
+    const 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::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+  ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
+             return Local<UnboundScript>());
+  LOG_API(isolate, "ScriptCompiler::CompileUnbound");
+  ENTER_V8(isolate);
+  i::SharedFunctionInfo* raw_result = NULL;
+  { i::HandleScope scope(isolate);
+    i::Handle<i::Object> name_obj;
+    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_line_offset.IsEmpty()) {
+      line_offset = static_cast<int>(source.resource_line_offset->Value());
+    }
+    if (!source.resource_column_offset.IsEmpty()) {
+      column_offset =
+          static_cast<int>(source.resource_column_offset->Value());
+    }
+    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);
+    }
+    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,
+                                   line_offset,
+                                   column_offset,
+                                   is_shared_cross_origin,
+                                   isolate->global_context(),
+                                   NULL,
+                                   pre_data_impl,
+                                   i::NOT_NATIVES_CODE);
+    has_pending_exception = result.is_null();
+    EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
+    raw_result = *result;
+    delete pre_data_impl;
   }
+  i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
+  return ToApiHandle<UnboundScript>(result);
 }
 
 
-int Script::GetLineNumber(int code_pos) {
-  i::Handle<i::HeapObject> obj =
-      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
-  i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Script::GetLineNumber()", return -1);
-  LOG_API(isolate, "Script::GetLineNumber");
-  if (obj->IsScript()) {
-    i::Handle<i::Script> script = i::Handle<i::Script>(i::Script::cast(*obj));
-    return i::GetScriptLineNumber(script, code_pos);
-  } else {
-    return -1;
-  }
+Local<Script> ScriptCompiler::Compile(
+    Isolate* v8_isolate,
+    const Source& source,
+    CompileOptions options) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+  ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()",
+             return Local<Script>());
+  LOG_API(isolate, "ScriptCompiler::CompiletBound()");
+  ENTER_V8(isolate);
+  Local<UnboundScript> generic =
+      CompileUnbound(v8_isolate, source, options);
+  if (generic.IsEmpty()) return Local<Script>();
+  return generic->BindToCurrentContext();
 }
 
 
-Handle<Value> Script::GetScriptName() {
-  i::Handle<i::HeapObject> obj =
-      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
-  i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Script::GetName()", return Handle<String>());
-  LOG_API(isolate, "Script::GetName");
-  if (obj->IsScript()) {
-    i::Object* name = i::Script::cast(*obj)->name();
-    return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
-  } else {
-    return Handle<String>();
+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;
+  if (script_data) {
+    cached_data = ScriptCompiler::CachedData(
+        reinterpret_cast<const uint8_t*>(script_data->Data()),
+        script_data->Length());
+  }
+  if (origin) {
+    return ScriptCompiler::Compile(
+        reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
+        ScriptCompiler::Source(source, *origin, cached_data));
   }
+  return ScriptCompiler::Compile(
+      reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
+      ScriptCompiler::Source(source, cached_data));
+}
+
+
+Local<Script> Script::Compile(v8::Handle<String> source,
+                              v8::Handle<String> file_name) {
+  ScriptOrigin origin(file_name);
+  return Compile(source, &origin);
 }
 
 
@@ -4029,7 +4066,9 @@ bool Function::IsBuiltin() const {
 
 int Function::ScriptId() const {
   i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
-  if (!func->shared()->script()->IsScript()) return v8::Script::kNoScriptId;
+  if (!func->shared()->script()->IsScript()) {
+    return v8::UnboundScript::kNoScriptId;
+  }
   i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
   return script->id()->value();
 }
index 9fc99d9..128087c 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -183,7 +183,8 @@ class RegisteredExtension {
   V(DataView, JSDataView)                      \
   V(String, String)                            \
   V(Symbol, Symbol)                            \
-  V(Script, Object)                            \
+  V(Script, JSFunction)                        \
+  V(UnboundScript, SharedFunctionInfo)         \
   V(Function, JSFunction)                      \
   V(Message, JSObject)                         \
   V(Context, Context)                          \
index 564aafe..539ebaa 100644 (file)
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -205,7 +205,9 @@ bool Shell::ExecuteString(Isolate* isolate,
     // When debugging make exceptions appear to be uncaught.
     try_catch.SetVerbose(true);
   }
-  Handle<Script> script = Script::New(source, name);
+  ScriptOrigin origin(name);
+  Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
+      isolate, ScriptCompiler::Source(source, origin));
   if (script.IsEmpty()) {
     // Print errors that happened during compilation.
     if (report_exceptions && !FLAG_debugger)
@@ -216,7 +218,7 @@ bool Shell::ExecuteString(Isolate* isolate,
     Local<Context> realm =
         Local<Context>::New(isolate, data->realms_[data->realm_current_]);
     realm->Enter();
-    Handle<Value> result = script->Run();
+    Handle<Value> result = script->BindToCurrentContext()->Run();
     realm->Exit();
     data->realm_current_ = data->realm_switch_;
     if (result.IsEmpty()) {
@@ -405,11 +407,12 @@ void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
     Throw(args.GetIsolate(), "Invalid argument");
     return;
   }
-  Handle<Script> script = Script::New(args[1]->ToString());
+  Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
+      isolate, ScriptCompiler::Source(args[1]->ToString()));
   if (script.IsEmpty()) return;
   Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
   realm->Enter();
-  Handle<Value> result = script->Run();
+  Handle<Value> result = script->BindToCurrentContext()->Run();
   realm->Exit();
   args.GetReturnValue().Set(result);
 }
@@ -806,7 +809,8 @@ void Shell::InstallUtilityScript(Isolate* isolate) {
   Handle<String> name =
       String::NewFromUtf8(isolate, shell_source_name.start(),
                           String::kNormalString, shell_source_name.length());
-  Handle<Script> script = Script::Compile(source, name);
+  ScriptOrigin origin(name);
+  Handle<Script> script = Script::Compile(source, &origin);
   script->Run();
   // Mark the d8 shell script as native to avoid it showing up as normal source
   // in the debugger.
index 25f7121..aa5c3a9 100644 (file)
@@ -3347,7 +3347,7 @@ bool Heap::CreateInitialObjects() {
   set_materialized_objects(FixedArray::cast(obj));
 
   // Handling of script id generation is in Factory::NewScript.
-  set_last_script_id(Smi::FromInt(v8::Script::kNoScriptId));
+  set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId));
 
   { MaybeObject* maybe_obj = AllocateAllocationSitesScratchpad();
     if (!maybe_obj->ToObject(&obj)) return false;
index e363f67..9aeb8f5 100644 (file)
@@ -47,7 +47,7 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
       line_number_(line_number),
       column_number_(column_number),
       shared_id_(0),
-      script_id_(v8::Script::kNoScriptId),
+      script_id_(v8::UnboundScript::kNoScriptId),
       no_frame_ranges_(NULL),
       bailout_reason_(kEmptyBailoutReason) { }
 
index c4066d0..9319510 100644 (file)
@@ -313,17 +313,23 @@ static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
 }
 
 
-static inline v8::Local<v8::Script> CompileWithOrigin(const char* source,
-                                                      const char* origin_url) {
-  v8::ScriptOrigin origin(v8_str(origin_url));
-  return v8::Script::Compile(v8_str(source), &origin);
+static inline v8::Local<v8::Script> CompileWithOrigin(
+    v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
+  v8::ScriptOrigin origin(origin_url);
+  return v8::ScriptCompiler::Compile(
+      v8::Isolate::GetCurrent(), v8::ScriptCompiler::Source(source, origin));
 }
 
 
 static inline v8::Local<v8::Script> CompileWithOrigin(
     v8::Local<v8::String> source, const char* origin_url) {
-  v8::ScriptOrigin origin(v8_str(origin_url));
-  return v8::Script::Compile(source, &origin);
+  return CompileWithOrigin(source, v8_str(origin_url));
+}
+
+
+static inline v8::Local<v8::Script> CompileWithOrigin(const char* source,
+                                                      const char* origin_url) {
+  return CompileWithOrigin(v8_str(source), v8_str(origin_url));
 }
 
 
@@ -339,11 +345,16 @@ static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
 
 
 static inline v8::Local<v8::Value> PreCompileCompileRun(const char* source) {
-  v8::Local<v8::String> script_source =
-      v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), source);
-  v8::ScriptData* preparse = v8::ScriptData::PreCompile(script_source);
-  v8::Local<v8::Script> script =
-      v8::Script::Compile(script_source, NULL, preparse);
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::Local<v8::String> source_string =
+      v8::String::NewFromUtf8(isolate, source);
+  v8::ScriptData* preparse = v8::ScriptData::PreCompile(source_string);
+  v8::ScriptCompiler::Source script_source(
+      source_string, 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::Value> result = script->Run();
   delete preparse;
   return result;
@@ -359,14 +370,24 @@ 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::Script::Compile(v8_str(source), &origin)->Run();
+  return v8::ScriptCompiler::Compile(
+             isolate, v8::ScriptCompiler::Source(v8_str(source), origin))
+      ->Run();
 }
 
 
 static inline v8::Local<v8::Value> CompileRunWithOrigin(
-    const char* source, const char* origin_url) {
+    v8::Local<v8::String> source, const char* origin_url) {
   v8::ScriptOrigin origin(v8_str(origin_url));
-  return v8::Script::Compile(v8_str(source), &origin)->Run();
+  return v8::ScriptCompiler::Compile(
+      v8::Isolate::GetCurrent(),
+      v8::ScriptCompiler::Source(source, origin))->Run();
+}
+
+
+static inline v8::Local<v8::Value> CompileRunWithOrigin(
+    const char* source, const char* origin_url) {
+  return CompileRunWithOrigin(v8_str(source), origin_url);
 }
 
 
index 01c9ca9..f87d723 100644 (file)
@@ -14952,8 +14952,13 @@ TEST(PreCompileInvalidPreparseDataError) {
   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
   v8::TryCatch try_catch;
 
-  Local<String> source = String::NewFromUtf8(isolate, script);
-  Local<Script> compiled_script = Script::New(source, NULL, sd);
+  v8::ScriptCompiler::Source script_source(
+      String::NewFromUtf8(isolate, script),
+      v8::ScriptCompiler::CachedData(
+          reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
+  Local<v8::UnboundScript> compiled_script =
+      v8::ScriptCompiler::CompileUnbound(isolate, script_source);
+
   CHECK(try_catch.HasCaught());
   String::Utf8Value exception_value(try_catch.Message()->Get());
   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
@@ -14970,7 +14975,12 @@ TEST(PreCompileInvalidPreparseDataError) {
   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
       200;
-  compiled_script = Script::New(source, NULL, sd);
+  v8::ScriptCompiler::Source script_source2(
+      String::NewFromUtf8(isolate, script),
+      v8::ScriptCompiler::CachedData(
+          reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
+  compiled_script =
+      v8::ScriptCompiler::CompileUnbound(isolate, script_source2);
   CHECK(!try_catch.HasCaught());
 
   delete sd;
@@ -17081,17 +17091,19 @@ THREADED_TEST(ScriptContextDependence) {
   const char *source = "foo";
   v8::Handle<v8::Script> dep =
       v8_compile(source);
-  v8::Handle<v8::Script> indep =
-      v8::Script::New(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)));
   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
                     v8::Integer::New(c1->GetIsolate(), 100));
   CHECK_EQ(dep->Run()->Int32Value(), 100);
-  CHECK_EQ(indep->Run()->Int32Value(), 100);
+  CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
   LocalContext c2;
   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
                     v8::Integer::New(c2->GetIsolate(), 101));
   CHECK_EQ(dep->Run()->Int32Value(), 100);
-  CHECK_EQ(indep->Run()->Int32Value(), 101);
+  CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
 }
 
 
@@ -17104,7 +17116,11 @@ THREADED_TEST(StackTrace) {
       v8::String::NewFromUtf8(context->GetIsolate(), source);
   v8::Handle<v8::String> origin =
       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
-  v8::Script::New(src, origin)->Run();
+  v8::ScriptCompiler::CompileUnbound(
+      context->GetIsolate(),
+      v8::ScriptCompiler::Source(src, v8::ScriptOrigin(origin)))
+      ->BindToCurrentContext()
+      ->Run();
   CHECK(try_catch.HasCaught());
   v8::String::Utf8Value stack(try_catch.StackTrace());
   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
@@ -17211,7 +17227,11 @@ TEST(CaptureStackTrace) {
   v8::Handle<v8::String> overview_src =
       v8::String::NewFromUtf8(isolate, overview_source);
   v8::Handle<Value> overview_result(
-      v8::Script::New(overview_src, origin)->Run());
+      v8::ScriptCompiler::CompileUnbound(
+          isolate,
+          v8::ScriptCompiler::Source(overview_src, v8::ScriptOrigin(origin)))
+          ->BindToCurrentContext()
+          ->Run());
   CHECK(!overview_result.IsEmpty());
   CHECK(overview_result->IsObject());
 
@@ -17230,9 +17250,11 @@ 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::Handle<v8::Script> detailed_script(
-      v8::Script::New(detailed_src, &detailed_origin));
-  v8::Handle<Value> detailed_result(detailed_script->Run());
+  v8::Handle<v8::UnboundScript> detailed_script(
+      v8::ScriptCompiler::CompileUnbound(
+          isolate, v8::ScriptCompiler::Source(detailed_src, detailed_origin)));
+  v8::Handle<Value> detailed_result(
+      detailed_script->BindToCurrentContext()->Run());
   CHECK(!detailed_result.IsEmpty());
   CHECK(detailed_result->IsObject());
 }
index 3bba514..ed0b190 100644 (file)
@@ -1495,20 +1495,16 @@ TEST(FunctionDetails) {
   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
   v8::Context::Scope context_scope(env);
 
-  v8::Handle<v8::Script> script_a = v8::Script::Compile(
-      v8::String::NewFromUtf8(
-          env->GetIsolate(),
+  v8::Handle<v8::Script> script_a = CompileWithOrigin(
           "    function foo\n() { try { bar(); } catch(e) {} }\n"
-          " function bar() { startProfiling(); }\n"),
-      v8::String::NewFromUtf8(env->GetIsolate(), "script_a"));
+          " function bar() { startProfiling(); }\n",
+          "script_a");
   script_a->Run();
-  v8::Handle<v8::Script> script_b = v8::Script::Compile(
-      v8::String::NewFromUtf8(
-          env->GetIsolate(),
+  v8::Handle<v8::Script> script_b = CompileWithOrigin(
           "\n\n   function baz() { try { foo(); } catch(e) {} }\n"
           "\n\nbaz();\n"
-          "stopProfiling();\n"),
-      v8::String::NewFromUtf8(env->GetIsolate(), "script_b"));
+          "stopProfiling();\n",
+          "script_b");
   script_b->Run();
   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
index 431bef1..9dfabe1 100644 (file)
@@ -2218,8 +2218,7 @@ TEST(ScriptBreakPointLineTopLevel) {
   v8::Local<v8::Function> f;
   {
     v8::HandleScope scope(env->GetIsolate());
-    v8::Script::Compile(
-        script, v8::String::NewFromUtf8(env->GetIsolate(), "test.html"))->Run();
+    CompileRunWithOrigin(script, "test.html");
   }
   f = v8::Local<v8::Function>::Cast(
       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
@@ -2235,8 +2234,7 @@ TEST(ScriptBreakPointLineTopLevel) {
 
   // Recompile and run script and check that break point was hit.
   break_point_hit_count = 0;
-  v8::Script::Compile(
-      script, v8::String::NewFromUtf8(env->GetIsolate(), "test.html"))->Run();
+  CompileRunWithOrigin(script, "test.html");
   CHECK_EQ(1, break_point_hit_count);
 
   // Call f and check that there are still no break points.
@@ -2271,9 +2269,7 @@ TEST(ScriptBreakPointTopLevelCrash) {
   {
     v8::HandleScope scope(env->GetIsolate());
     break_point_hit_count = 0;
-    v8::Script::Compile(script_source,
-                        v8::String::NewFromUtf8(env->GetIsolate(), "test.html"))
-        ->Run();
+    CompileRunWithOrigin(script_source, "test.html");
     CHECK_EQ(1, break_point_hit_count);
   }
 
@@ -6246,8 +6242,7 @@ TEST(ScriptNameAndData) {
   CHECK_EQ(3, break_point_hit_count);
   CHECK_EQ("new name", last_script_name_hit);
 
-  v8::Handle<v8::Script> script3 = v8::Script::Compile(
-      script, &origin2, NULL);
+  v8::Handle<v8::Script> script3 = v8::Script::Compile(script, &origin2);
   script3->Run();
   f = v8::Local<v8::Function>::Cast(
       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
@@ -6988,7 +6983,7 @@ TEST(Backtrace) {
 
   v8::Handle<v8::String> void0 =
       v8::String::NewFromUtf8(env->GetIsolate(), "void(0)");
-  v8::Handle<v8::Script> script = v8::Script::Compile(void0, void0);
+  v8::Handle<v8::Script> script = CompileWithOrigin(void0, void0);
 
   // Check backtrace from "void(0)" script.
   BacktraceData::frame_counter = -10;
@@ -7008,18 +7003,20 @@ TEST(Backtrace) {
 
 TEST(GetMirror) {
   DebugLocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   v8::Handle<v8::Value> obj =
-      v8::Debug::GetMirror(v8::String::NewFromUtf8(env->GetIsolate(), "hodja"));
+      v8::Debug::GetMirror(v8::String::NewFromUtf8(isolate, "hodja"));
   v8::Handle<v8::Function> run_test =
-      v8::Handle<v8::Function>::Cast(v8::Script::New(
-          v8::String::NewFromUtf8(
-              env->GetIsolate(),
-              "function runTest(mirror) {"
-              "  return mirror.isString() && (mirror.length() == 5);"
-              "}"
-              ""
-              "runTest;"))->Run());
+      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::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
   CHECK(result->IsTrue());
 }
index 6531036..42af0a5 100644 (file)
@@ -310,7 +310,7 @@ TEST(Issue23768) {
   // Script needs to have a name in order to trigger InitLineEnds execution.
   v8::Handle<v8::String> origin =
       v8::String::NewFromUtf8(CcTest::isolate(), "issue-23768-test");
-  v8::Handle<v8::Script> evil_script = v8::Script::Compile(source, origin);
+  v8::Handle<v8::Script> evil_script = CompileWithOrigin(source, origin);
   CHECK(!evil_script.IsEmpty());
   CHECK(!evil_script->Run().IsEmpty());
   i::Handle<i::ExternalTwoByteString> i_source(
@@ -468,7 +468,7 @@ TEST(EquivalenceOfLoggingAndTraversal) {
       CcTest::isolate(), reinterpret_cast<const char*>(source.start()),
       v8::String::kNormalString, source.length());
   v8::TryCatch try_catch;
-  v8::Handle<v8::Script> script = v8::Script::Compile(source_str, v8_str(""));
+  v8::Handle<v8::Script> script = CompileWithOrigin(source_str, "");
   if (script.IsEmpty()) {
     v8::String::Utf8Value exception(try_catch.Exception());
     printf("compile: %s\n", *exception);
index 761048b..2a9a6c4 100644 (file)
@@ -213,18 +213,25 @@ TEST(Preparsing) {
   {
     i::FLAG_lazy = true;
     ScriptResource* resource = new ScriptResource(source, source_length);
-    v8::Local<v8::String> script_source =
-        v8::String::NewExternal(isolate, resource);
-    v8::Script::Compile(script_source, NULL, preparse);
+    v8::ScriptCompiler::Source script_source(
+        v8::String::NewExternal(isolate, resource),
+        v8::ScriptCompiler::CachedData(
+            reinterpret_cast<const uint8_t*>(preparse->Data()),
+            preparse->Length()));
+    v8::ScriptCompiler::Compile(isolate,
+                                v8::ScriptCompiler::Source(script_source));
   }
 
   {
     i::FLAG_lazy = false;
 
     ScriptResource* resource = new ScriptResource(source, source_length);
-    v8::Local<v8::String> script_source =
-        v8::String::NewExternal(isolate, resource);
-    v8::Script::New(script_source, NULL, preparse);
+    v8::ScriptCompiler::Source script_source(
+        v8::String::NewExternal(isolate, resource),
+        v8::ScriptCompiler::CachedData(
+            reinterpret_cast<const uint8_t*>(preparse->Data()),
+            preparse->Length()));
+    v8::ScriptCompiler::CompileUnbound(isolate, script_source);
   }
   delete preparse;
   i::FLAG_lazy = lazy_flag;