Commit 2d3f6f91 authored by jgruber's avatar jgruber Committed by Commit Bot

[api] Add Module::GetUnboundScript()

This method is intended for use by code caching as follows:

1. The module is compiled (and perhaps instantiated).
2. The embedder fetches and stores the module's unbound script (i.e.
   the shared function info).
3. Module evaluation, maybe triggering lazy compilation.
4. Generated code for the module (which hangs off the shared function
   info) is inserted into the code cache.

Subsequent module loads can load from the code cache prior to
evaluation.

Bug: v8:7685
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: I80018cd921ab1a18323906a548b249e19d9f9509
Reviewed-on: https://chromium-review.googlesource.com/1041745
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52998}
parent be9b5f4c
......@@ -1222,6 +1222,14 @@ class V8_EXPORT Module {
* The module's status must be at least kInstantiated.
*/
Local<Value> GetModuleNamespace();
/**
* Returns the corresponding context-unbound script.
*
* The module must be unevaluated, i.e. its status must not be kEvaluating,
* kEvaluated or kErrored.
*/
Local<UnboundScript> GetUnboundScript();
};
/**
......
......@@ -2328,6 +2328,15 @@ Local<Value> Module::GetModuleNamespace() {
return ToApiHandle<Value>(module_namespace);
}
Local<UnboundScript> Module::GetUnboundScript() {
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>(
i::Handle<i::SharedFunctionInfo>(self->GetSharedFunctionInfo()));
}
int Module::GetIdentityHash() const { return Utils::OpenHandle(this)->hash(); }
Maybe<bool> Module::InstantiateModule(Local<Context> context,
......
......@@ -29,16 +29,9 @@ SMI_ACCESSORS(Module, dfs_ancestor_index, kDfsAncestorIndexOffset)
SMI_ACCESSORS(Module, hash, kHashOffset)
ModuleInfo* Module::info() const {
if (status() >= kEvaluating) {
return ModuleInfo::cast(code());
}
ScopeInfo* scope_info =
status() == kInstantiated
? JSGeneratorObject::cast(code())->function()->shared()->scope_info()
: status() == kInstantiating
? JSFunction::cast(code())->shared()->scope_info()
: SharedFunctionInfo::cast(code())->scope_info();
return scope_info->ModuleDescriptorInfo();
return (status() >= kEvaluating)
? ModuleInfo::cast(code())
: GetSharedFunctionInfo()->scope_info()->ModuleDescriptorInfo();
}
TYPE_CHECKER(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE)
......
......@@ -276,6 +276,30 @@ Object* Module::GetException() {
return exception();
}
SharedFunctionInfo* Module::GetSharedFunctionInfo() const {
DisallowHeapAllocation no_alloc;
DCHECK_NE(status(), Module::kEvaluating);
DCHECK_NE(status(), Module::kEvaluated);
switch (status()) {
case kUninstantiated:
case kPreInstantiating:
DCHECK(code()->IsSharedFunctionInfo());
return SharedFunctionInfo::cast(code());
case kInstantiating:
DCHECK(code()->IsJSFunction());
return JSFunction::cast(code())->shared();
case kInstantiated:
DCHECK(code()->IsJSGeneratorObject());
return JSGeneratorObject::cast(code())->function()->shared();
case kEvaluating:
case kEvaluated:
case kErrored:
UNREACHABLE();
}
UNREACHABLE();
}
MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
Handle<String> name, int module_request,
MessageLocation loc, bool must_resolve,
......
......@@ -67,6 +67,10 @@ class Module : public Struct {
// The exception in the case {status} is kErrored.
Object* GetException();
// The shared function info in case {status} is not kEvaluating, kEvaluated or
// kErrored.
SharedFunctionInfo* GetSharedFunctionInfo() const;
// The namespace object (or undefined).
DECL_ACCESSORS(module_namespace, HeapObject)
......
......@@ -24662,6 +24662,15 @@ TEST(CaptureStackTraceForStackOverflow) {
CHECK(try_catch.HasCaught());
}
namespace {
bool ValueEqualsString(v8::Isolate* isolate, Local<Value> lhs,
const char* rhs) {
CHECK(!lhs.IsEmpty());
CHECK(lhs->IsString());
String::Utf8Value utf8_lhs(isolate, lhs);
return strcmp(rhs, *utf8_lhs) == 0;
}
} // namespace
TEST(ScriptNameAndLineNumber) {
LocalContext env;
......@@ -24670,13 +24679,12 @@ TEST(ScriptNameAndLineNumber) {
const char* url = "http://www.foo.com/foo.js";
v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
Local<Script> script =
v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
CHECK(!script_name.IsEmpty());
CHECK(script_name->IsString());
String::Utf8Value utf8_name(env->GetIsolate(), script_name);
CHECK_EQ(0, strcmp(url, *utf8_name));
CHECK(ValueEqualsString(isolate, script->GetUnboundScript()->GetScriptName(),
url));
int line_number = script->GetUnboundScript()->GetLineNumber(0);
CHECK_EQ(13, line_number);
}
......@@ -27318,6 +27326,39 @@ TEST(GetModuleNamespace) {
->StrictEquals(v8::Number::New(isolate, 10)));
}
TEST(ModuleGetUnboundScript) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
Local<String> url = v8_str("www.google.com");
Local<String> source_text = v8_str("export default 5; export const a = 10;");
v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
Local<v8::Boolean>(), Local<v8::Integer>(),
Local<v8::Value>(), Local<v8::Boolean>(),
Local<v8::Boolean>(), True(isolate));
v8::ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
Local<v8::UnboundScript> sfi_before_instantiation =
module->GetUnboundScript();
module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
.ToChecked();
Local<v8::UnboundScript> sfi_after_instantiation = module->GetUnboundScript();
// Check object identity.
{
i::Handle<i::Object> s1 = v8::Utils::OpenHandle(*sfi_before_instantiation);
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) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment