[api] Add a dedicated UnboundModuleScript type
Module and script SharedFunctionInfos can't be used interchangeably
(e.g.: it should not be possible to bind a Module's SFI to a Context).
The dedicated type disambiguates the two.
This also adds an overload for CreateCodeCache which takes an unbound
module script instead of an unbound script. Both are just a SFI
underneath, so their behavior is identical.
Bug: v8:7685
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: Iab519d0d50b6b41c95abdb6397f5622e292da4d8
Reviewed-on: https://chromium-review.googlesource.com/1047107
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53150}diff --git a/include/v8.h b/include/v8.h
index e8d31bb..727e2d7 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1213,6 +1213,13 @@
};
/**
+ * A compiled JavaScript module, not yet tied to a Context.
+ */
+class V8_EXPORT UnboundModuleScript {
+ // Only used as a container for code caching.
+};
+
+/**
* A location in JavaScript source.
*/
class V8_EXPORT Location {
@@ -1313,12 +1320,12 @@
Local<Value> GetModuleNamespace();
/**
- * Returns the corresponding context-unbound script.
+ * Returns the corresponding context-unbound module script.
*
* The module must be unevaluated, i.e. its status must not be kEvaluating,
* kEvaluated or kErrored.
*/
- Local<UnboundScript> GetUnboundScript();
+ Local<UnboundModuleScript> GetUnboundModuleScript();
};
/**
@@ -1677,6 +1684,14 @@
*/
static CachedData* CreateCodeCache(Local<UnboundScript> unbound_script);
+ /**
+ * Creates and returns code cache for the specified unbound_module_script.
+ * This will return nullptr if the script cannot be serialized. The
+ * CachedData returned by this function should be owned by the caller.
+ */
+ static CachedData* CreateCodeCache(
+ Local<UnboundModuleScript> unbound_module_script);
+
V8_DEPRECATED("Source string is no longer required",
static CachedData* CreateCodeCache(
Local<UnboundScript> unbound_script, Local<String> source));
diff --git a/src/api.cc b/src/api.cc
index 2344bb3..47d1b04 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2323,12 +2323,12 @@
return ToApiHandle<Value>(module_namespace);
}
-Local<UnboundScript> Module::GetUnboundScript() {
+Local<UnboundModuleScript> Module::GetUnboundModuleScript() {
Utils::ApiCheck(
GetStatus() < kEvaluating, "v8::Module::GetUnboundScript",
"v8::Module::GetUnboundScript must be used on an unevaluated module");
i::Handle<i::Module> self = Utils::OpenHandle(this);
- return ToApiHandle<UnboundScript>(
+ return ToApiHandle<UnboundModuleScript>(
i::Handle<i::SharedFunctionInfo>(self->GetSharedFunctionInfo()));
}
@@ -2673,6 +2673,16 @@
return i::CodeSerializer::Serialize(shared);
}
+// static
+ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCache(
+ Local<UnboundModuleScript> unbound_module_script) {
+ i::Handle<i::SharedFunctionInfo> shared =
+ i::Handle<i::SharedFunctionInfo>::cast(
+ Utils::OpenHandle(*unbound_module_script));
+ DCHECK(shared->is_toplevel());
+ return i::CodeSerializer::Serialize(shared);
+}
+
ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCacheForFunction(
Local<Function> function, Local<String> source) {
return CreateCodeCacheForFunction(function);
diff --git a/src/api.h b/src/api.h
index d8b6f94..d1297c8 100644
--- a/src/api.h
+++ b/src/api.h
@@ -112,6 +112,7 @@
V(String, String) \
V(Symbol, Symbol) \
V(Script, JSFunction) \
+ V(UnboundModuleScript, SharedFunctionInfo) \
V(UnboundScript, SharedFunctionInfo) \
V(Module, Module) \
V(Function, JSReceiver) \
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 0cc24b1..a00fae1 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -25636,6 +25636,55 @@
isolate2->Dispose();
}
+v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
+ Local<String> specifier,
+ Local<Module> referrer) {
+ CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
+}
+
+TEST(ModuleCodeCache) {
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+
+ const char* origin = "code cache test";
+ v8::ScriptCompiler::CachedData* cache;
+
+ v8::Isolate* isolate1 = v8::Isolate::New(create_params);
+ {
+ v8::Isolate::Scope iscope(isolate1);
+ v8::HandleScope scope(isolate1);
+ v8::Local<v8::Context> context = v8::Context::New(isolate1);
+ v8::Context::Scope cscope(context);
+
+ Local<String> source_text = v8_str(
+ "export default 5; export const a = 10; function f() { return 42; } "
+ "(function() { return f(); })();");
+ v8::ScriptOrigin script_origin(
+ v8_str(origin), Local<v8::Integer>(), Local<v8::Integer>(),
+ Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
+ Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate1));
+ v8::ScriptCompiler::Source source(source_text, script_origin);
+ Local<Module> module =
+ v8::ScriptCompiler::CompileModule(isolate1, &source).ToLocalChecked();
+ module->InstantiateModule(context, UnexpectedModuleResolveCallback)
+ .ToChecked();
+
+ // Fetch the shared function info before evaluation.
+ Local<v8::UnboundModuleScript> unbound_module_script =
+ module->GetUnboundModuleScript();
+
+ // Evaluate for possible lazy compilation.
+ Local<Value> completion_value = module->Evaluate(context).ToLocalChecked();
+ CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
+
+ // Now create the cache.
+ cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
+ }
+ isolate1->Dispose();
+
+ // TODO(jgruber,v8:7685): Test module code cache consumption once implemented.
+ delete cache;
+}
void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
const char* garbage = "garbage garbage garbage garbage garbage garbage";
@@ -27370,12 +27419,6 @@
meta->CreateDataProperty(context, v8_str("foo"), v8_str("bar")).ToChecked();
}
-v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
- Local<String> specifier,
- Local<Module> referrer) {
- CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
-}
-
TEST(ImportMeta) {
i::FLAG_harmony_dynamic_import = true;
i::FLAG_harmony_import_meta = true;
@@ -27443,7 +27486,7 @@
->StrictEquals(v8::Number::New(isolate, 10)));
}
-TEST(ModuleGetUnboundScript) {
+TEST(ModuleGetUnboundModuleScript) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
@@ -27457,11 +27500,12 @@
v8::ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
- Local<v8::UnboundScript> sfi_before_instantiation =
- module->GetUnboundScript();
+ Local<v8::UnboundModuleScript> sfi_before_instantiation =
+ module->GetUnboundModuleScript();
module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
.ToChecked();
- Local<v8::UnboundScript> sfi_after_instantiation = module->GetUnboundScript();
+ Local<v8::UnboundModuleScript> sfi_after_instantiation =
+ module->GetUnboundModuleScript();
// Check object identity.
{
@@ -27469,11 +27513,6 @@
i::Handle<i::Object> s2 = v8::Utils::OpenHandle(*sfi_after_instantiation);
CHECK_EQ(*s1, *s2);
}
-
- // Check unbound script values.
- Local<v8::UnboundScript> sfi = sfi_after_instantiation;
- CHECK(ValueEqualsString(isolate, sfi->GetScriptName(), "www.google.com"));
- CHECK_EQ(0, sfi->GetLineNumber(0));
}
TEST(GlobalTemplateWithDoubleProperty) {