Commit a209dcf6 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[api] Expose a module's status and exception.

V8 now takes care of recording a module's status, as proposed
in https://github.com/tc39/ecma262/pull/916.

R=adamk@chromium.org

Bug: v8:1569, chromium:594639
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Id884f1c817e1dc3eea79a5d5a7f5cd996db1dbb0
Reviewed-on: https://chromium-review.googlesource.com/548500
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46293}
parent 3088ae38
......@@ -1099,6 +1099,28 @@ class V8_EXPORT Location {
*/
class V8_EXPORT Module {
public:
/**
* The different states a module can be in.
*/
enum Status {
kUninstantiated,
kInstantiating,
kInstantiated,
kEvaluating,
kEvaluated,
kErrored
};
/**
* Returns the module's current status.
*/
Status GetStatus() const;
/**
* For a module in kErrored status, this returns the corresponding exception.
*/
Local<Value> GetException() const;
/**
* Returns the number of modules requested by this module.
*/
......@@ -1142,6 +1164,7 @@ class V8_EXPORT Module {
* ModuleEvaluation
*
* Returns the completion value.
* TODO(neis): Be more precise or say nothing.
*/
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Evaluate(Local<Context> context);
};
......
......@@ -2122,6 +2122,34 @@ Maybe<bool> DynamicImportResult::FinishDynamicImportFailure(
return Just(true);
}
Module::Status Module::GetStatus() const {
i::Handle<i::Module> self = Utils::OpenHandle(this);
switch (self->status()) {
case i::Module::kUninstantiated:
return kUninstantiated;
case i::Module::kPreInstantiating:
case i::Module::kInstantiating:
return kInstantiating;
case i::Module::kInstantiated:
return kInstantiated;
case i::Module::kEvaluating:
return kEvaluating;
case i::Module::kEvaluated:
return kEvaluated;
case i::Module::kErrored:
return kErrored;
}
UNREACHABLE();
}
Local<Value> Module::GetException() const {
Utils::ApiCheck(GetStatus() == kErrored, "v8::Module::GetException",
"Module status must be kErrored");
i::Handle<i::Module> self = Utils::OpenHandle(this);
i::Isolate* isolate = self->GetIsolate();
return ToApiHandle<Value>(i::handle(self->GetException(), isolate));
}
int Module::GetModuleRequestsLength() const {
i::Handle<i::Module> self = Utils::OpenHandle(this);
return self->info()->module_requests()->length();
......
......@@ -57,12 +57,13 @@ TEST(ModuleInstantiationFailures) {
v8::TryCatch try_catch(isolate);
Local<String> source_text = v8_str(
"import './foo.js';"
"\nexport {} from './bar.js';");
"import './foo.js';\n"
"export {} from './bar.js';");
ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
CHECK_EQ(2, module->GetModuleRequestsLength());
CHECK(v8_str("./foo.js")->StrictEquals(module->GetModuleRequest(0)));
v8::Location loc = module->GetModuleRequestLocation(0);
......@@ -81,6 +82,10 @@ TEST(ModuleInstantiationFailures) {
.IsNothing());
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
CHECK_EQ(Module::kErrored, module->GetStatus());
Local<Value> exception = module->GetException();
CHECK(exception->StrictEquals(v8_str("boom")));
// TODO(neis): Check object identity.
}
// Start over again...
......@@ -95,6 +100,9 @@ TEST(ModuleInstantiationFailures) {
.IsNothing());
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("booom")));
CHECK_EQ(Module::kErrored, module->GetStatus());
Local<Value> exception = module->GetException();
CHECK(exception->StrictEquals(v8_str("booom")));
}
CHECK(!try_catch.HasCaught());
......@@ -121,16 +129,63 @@ TEST(ModuleEvaluation) {
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
CHECK(module
->InstantiateModule(env.local(),
CompileSpecifierAsModuleResolveCallback)
.FromJust());
CHECK_EQ(Module::kInstantiated, module->GetStatus());
CHECK(!module->Evaluate(env.local()).IsEmpty());
CHECK_EQ(Module::kEvaluated, module->GetStatus());
ExpectInt32("Object.expando", 10);
CHECK(!try_catch.HasCaught());
}
TEST(ModuleEvaluationError) {
Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
LocalContext env;
v8::TryCatch try_catch(isolate);
Local<String> source_text =
v8_str("Object.x = (Object.x || 0) + 1; throw 'boom';");
ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
CHECK(module
->InstantiateModule(env.local(),
CompileSpecifierAsModuleResolveCallback)
.FromJust());
CHECK_EQ(Module::kInstantiated, module->GetStatus());
{
v8::TryCatch inner_try_catch(isolate);
CHECK(module->Evaluate(env.local()).IsEmpty());
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
CHECK_EQ(Module::kErrored, module->GetStatus());
Local<Value> exception = module->GetException();
CHECK(exception->StrictEquals(v8_str("boom")));
ExpectInt32("Object.x", 1);
}
{
v8::TryCatch inner_try_catch(isolate);
CHECK(module->Evaluate(env.local()).IsEmpty());
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
CHECK_EQ(Module::kErrored, module->GetStatus());
Local<Value> exception = module->GetException();
CHECK(exception->StrictEquals(v8_str("boom")));
ExpectInt32("Object.x", 1);
}
CHECK(!try_catch.HasCaught());
}
TEST(ModuleEvaluationCompletion1) {
Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
......@@ -163,11 +218,16 @@ TEST(ModuleEvaluationCompletion1) {
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
CHECK(module
->InstantiateModule(env.local(),
CompileSpecifierAsModuleResolveCallback)
.FromJust());
CHECK_EQ(Module::kInstantiated, module->GetStatus());
CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
CHECK_EQ(Module::kEvaluated, module->GetStatus());
CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
CHECK_EQ(Module::kEvaluated, module->GetStatus());
}
CHECK(!try_catch.HasCaught());
......@@ -204,13 +264,18 @@ TEST(ModuleEvaluationCompletion2) {
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
CHECK(module
->InstantiateModule(env.local(),
CompileSpecifierAsModuleResolveCallback)
.FromJust());
CHECK_EQ(Module::kInstantiated, module->GetStatus());
CHECK(module->Evaluate(env.local())
.ToLocalChecked()
->StrictEquals(v8_str("gaga")));
CHECK_EQ(Module::kEvaluated, module->GetStatus());
CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
CHECK_EQ(Module::kEvaluated, module->GetStatus());
}
CHECK(!try_catch.HasCaught());
......
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