summaryrefslogtreecommitdiff
path: root/deps/v8/test/cctest/test-modules.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/test-modules.cc')
-rw-r--r--deps/v8/test/cctest/test-modules.cc819
1 files changed, 617 insertions, 202 deletions
diff --git a/deps/v8/test/cctest/test-modules.cc b/deps/v8/test/cctest/test-modules.cc
index 0f2bfd2a5f..d7cb6e610e 100644
--- a/deps/v8/test/cctest/test-modules.cc
+++ b/deps/v8/test/cctest/test-modules.cc
@@ -14,6 +14,7 @@ using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Module;
+using v8::Promise;
using v8::ScriptCompiler;
using v8::ScriptOrigin;
using v8::String;
@@ -196,99 +197,480 @@ static MaybeLocal<Module> CompileSpecifierAsModuleResolveCallback(
}
TEST(ModuleEvaluation) {
- Isolate* isolate = CcTest::isolate();
- HandleScope scope(isolate);
- LocalContext env;
- v8::TryCatch try_catch(isolate);
+ bool prev_top_level_await = i::FLAG_harmony_top_level_await;
+ for (auto top_level_await : {true, false}) {
+ i::FLAG_harmony_top_level_await = top_level_await;
- Local<String> source_text = v8_str(
- "import 'Object.expando = 5';"
- "import 'Object.expando *= 2';");
- 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());
- CHECK(!module->Evaluate(env.local()).IsEmpty());
- CHECK_EQ(Module::kEvaluated, module->GetStatus());
- ExpectInt32("Object.expando", 10);
+ Isolate* isolate = CcTest::isolate();
+ HandleScope scope(isolate);
+ LocalContext env;
+ v8::TryCatch try_catch(isolate);
- CHECK(!try_catch.HasCaught());
+ Local<String> source_text = v8_str(
+ "import 'Object.expando = 5';"
+ "import 'Object.expando *= 2';");
+ 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());
+
+ MaybeLocal<Value> result = module->Evaluate(env.local());
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+ if (i::FLAG_harmony_top_level_await) {
+ Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked());
+ CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
+ CHECK(promise->Result()->IsUndefined());
+ } else {
+ CHECK(!result.IsEmpty());
+ ExpectInt32("Object.expando", 10);
+ }
+ CHECK(!try_catch.HasCaught());
+ }
+ i::FLAG_harmony_top_level_await = prev_top_level_await;
}
-TEST(ModuleEvaluationError) {
- Isolate* isolate = CcTest::isolate();
- HandleScope scope(isolate);
- LocalContext env;
- v8::TryCatch try_catch(isolate);
+TEST(ModuleEvaluationError1) {
+ bool prev_top_level_await = i::FLAG_harmony_top_level_await;
+ for (auto top_level_await : {true, false}) {
+ i::FLAG_harmony_top_level_await = top_level_await;
- 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());
+ Isolate* isolate = CcTest::isolate();
+ HandleScope scope(isolate);
+ LocalContext env;
+ v8::TryCatch try_catch(isolate);
- {
- 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);
+ 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());
+
+ MaybeLocal<Value> result_1;
+ {
+ v8::TryCatch inner_try_catch(isolate);
+ result_1 = module->Evaluate(env.local());
+ CHECK_EQ(Module::kErrored, module->GetStatus());
+ Local<Value> exception = module->GetException();
+ CHECK(exception->StrictEquals(v8_str("boom")));
+ ExpectInt32("Object.x", 1);
+ CHECK(inner_try_catch.HasCaught());
+ CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
+ }
+
+ MaybeLocal<Value> result_2;
+ {
+ v8::TryCatch inner_try_catch(isolate);
+ result_2 = module->Evaluate(env.local());
+ CHECK_EQ(Module::kErrored, module->GetStatus());
+ Local<Value> exception = module->GetException();
+ CHECK(exception->StrictEquals(v8_str("boom")));
+ ExpectInt32("Object.x", 1);
+
+ if (i::FLAG_harmony_top_level_await) {
+ // With top level await we do not rethrow the exception.
+ CHECK(!inner_try_catch.HasCaught());
+ } else {
+ CHECK(inner_try_catch.HasCaught());
+ CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
+ }
+ }
+ if (i::FLAG_harmony_top_level_await) {
+ // With top level await, errored evaluation returns a rejected promise
+ // with the exception.
+ Local<Promise> promise_1 =
+ Local<Promise>::Cast(result_1.ToLocalChecked());
+ Local<Promise> promise_2 =
+ Local<Promise>::Cast(result_2.ToLocalChecked());
+ CHECK_EQ(promise_1->State(), v8::Promise::kRejected);
+ CHECK_EQ(promise_2->State(), v8::Promise::kRejected);
+ CHECK_EQ(promise_1->Result(), module->GetException());
+ CHECK_EQ(promise_2->Result(), module->GetException());
+ } else {
+ CHECK(result_1.IsEmpty() && result_2.IsEmpty());
+ }
+
+ CHECK(!try_catch.HasCaught());
}
+ i::FLAG_harmony_top_level_await = prev_top_level_await;
+}
- {
- 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);
+static Local<Module> failure_module;
+static Local<Module> dependent_module;
+MaybeLocal<Module> ResolveCallbackForModuleEvaluationError2(
+ Local<Context> context, Local<String> specifier, Local<Module> referrer) {
+ if (specifier->StrictEquals(v8_str("./failure.js"))) {
+ return failure_module;
+ } else {
+ CHECK(specifier->StrictEquals(v8_str("./dependent.js")));
+ return dependent_module;
}
+}
- CHECK(!try_catch.HasCaught());
+TEST(ModuleEvaluationError2) {
+ bool prev_top_level_await = i::FLAG_harmony_top_level_await;
+ for (auto top_level_await : {true, false}) {
+ i::FLAG_harmony_top_level_await = top_level_await;
+
+ Isolate* isolate = CcTest::isolate();
+ HandleScope scope(isolate);
+ LocalContext env;
+ v8::TryCatch try_catch(isolate);
+
+ Local<String> failure_text = v8_str("throw 'boom';");
+ ScriptOrigin failure_origin =
+ ModuleOrigin(v8_str("failure.js"), CcTest::isolate());
+ ScriptCompiler::Source failure_source(failure_text, failure_origin);
+ failure_module = ScriptCompiler::CompileModule(isolate, &failure_source)
+ .ToLocalChecked();
+ CHECK_EQ(Module::kUninstantiated, failure_module->GetStatus());
+ CHECK(failure_module
+ ->InstantiateModule(env.local(),
+ ResolveCallbackForModuleEvaluationError2)
+ .FromJust());
+ CHECK_EQ(Module::kInstantiated, failure_module->GetStatus());
+
+ MaybeLocal<Value> result_1;
+ {
+ v8::TryCatch inner_try_catch(isolate);
+ result_1 = failure_module->Evaluate(env.local());
+ CHECK_EQ(Module::kErrored, failure_module->GetStatus());
+ Local<Value> exception = failure_module->GetException();
+ CHECK(exception->StrictEquals(v8_str("boom")));
+ CHECK(inner_try_catch.HasCaught());
+ CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
+ }
+
+ Local<String> dependent_text =
+ v8_str("import './failure.js'; export const c = 123;");
+ ScriptOrigin dependent_origin =
+ ModuleOrigin(v8_str("dependent.js"), CcTest::isolate());
+ ScriptCompiler::Source dependent_source(dependent_text, dependent_origin);
+ dependent_module = ScriptCompiler::CompileModule(isolate, &dependent_source)
+ .ToLocalChecked();
+ CHECK_EQ(Module::kUninstantiated, dependent_module->GetStatus());
+ CHECK(dependent_module
+ ->InstantiateModule(env.local(),
+ ResolveCallbackForModuleEvaluationError2)
+ .FromJust());
+ CHECK_EQ(Module::kInstantiated, dependent_module->GetStatus());
+
+ MaybeLocal<Value> result_2;
+ {
+ v8::TryCatch inner_try_catch(isolate);
+ result_2 = dependent_module->Evaluate(env.local());
+ CHECK_EQ(Module::kErrored, dependent_module->GetStatus());
+ Local<Value> exception = dependent_module->GetException();
+ CHECK(exception->StrictEquals(v8_str("boom")));
+ CHECK_EQ(exception, failure_module->GetException());
+
+ if (i::FLAG_harmony_top_level_await) {
+ // With top level await we do not rethrow the exception.
+ CHECK(!inner_try_catch.HasCaught());
+ } else {
+ CHECK(inner_try_catch.HasCaught());
+ CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
+ }
+ }
+
+ if (i::FLAG_harmony_top_level_await) {
+ // With top level await, errored evaluation returns a rejected promise
+ // with the exception.
+ Local<Promise> promise_1 =
+ Local<Promise>::Cast(result_1.ToLocalChecked());
+ Local<Promise> promise_2 =
+ Local<Promise>::Cast(result_2.ToLocalChecked());
+ CHECK_EQ(promise_1->State(), v8::Promise::kRejected);
+ CHECK_EQ(promise_2->State(), v8::Promise::kRejected);
+ CHECK_EQ(promise_1->Result(), failure_module->GetException());
+ CHECK_EQ(promise_2->Result(), failure_module->GetException());
+ } else {
+ CHECK(result_1.IsEmpty() && result_2.IsEmpty());
+ }
+
+ CHECK(!try_catch.HasCaught());
+ }
+ i::FLAG_harmony_top_level_await = prev_top_level_await;
}
TEST(ModuleEvaluationCompletion1) {
+ bool prev_top_level_await = i::FLAG_harmony_top_level_await;
+ for (auto top_level_await : {true, false}) {
+ i::FLAG_harmony_top_level_await = top_level_await;
+
+ Isolate* isolate = CcTest::isolate();
+ HandleScope scope(isolate);
+ LocalContext env;
+ v8::TryCatch try_catch(isolate);
+
+ const char* sources[] = {
+ "",
+ "var a = 1",
+ "import '42'",
+ "export * from '42'",
+ "export {} from '42'",
+ "export {}",
+ "var a = 1; export {a}",
+ "export function foo() {}",
+ "export class C extends null {}",
+ "export let a = 1",
+ "export default 1",
+ "export default function foo() {}",
+ "export default function () {}",
+ "export default (function () {})",
+ "export default class C extends null {}",
+ "export default (class C extends null {})",
+ "for (var i = 0; i < 5; ++i) {}",
+ };
+
+ for (auto src : sources) {
+ Local<String> source_text = v8_str(src);
+ 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());
+
+ // Evaluate twice.
+ Local<Value> result_1 = module->Evaluate(env.local()).ToLocalChecked();
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+ Local<Value> result_2 = module->Evaluate(env.local()).ToLocalChecked();
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+
+ if (i::FLAG_harmony_top_level_await) {
+ Local<Promise> promise = Local<Promise>::Cast(result_1);
+ CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
+ CHECK(promise->Result()->IsUndefined());
+
+ // Second evaluation should return the same promise.
+ Local<Promise> promise_too = Local<Promise>::Cast(result_2);
+ CHECK_EQ(promise, promise_too);
+ CHECK_EQ(promise_too->State(), v8::Promise::kFulfilled);
+ CHECK(promise_too->Result()->IsUndefined());
+ } else {
+ CHECK(result_1->IsUndefined());
+ CHECK(result_2->IsUndefined());
+ }
+ }
+ CHECK(!try_catch.HasCaught());
+ }
+ i::FLAG_harmony_top_level_await = prev_top_level_await;
+}
+
+TEST(ModuleEvaluationCompletion2) {
+ bool prev_top_level_await = i::FLAG_harmony_top_level_await;
+ for (auto top_level_await : {true, false}) {
+ i::FLAG_harmony_top_level_await = top_level_await;
+
+ Isolate* isolate = CcTest::isolate();
+ HandleScope scope(isolate);
+ LocalContext env;
+ v8::TryCatch try_catch(isolate);
+
+ const char* sources[] = {
+ "'gaga'; ",
+ "'gaga'; var a = 1",
+ "'gaga'; import '42'",
+ "'gaga'; export * from '42'",
+ "'gaga'; export {} from '42'",
+ "'gaga'; export {}",
+ "'gaga'; var a = 1; export {a}",
+ "'gaga'; export function foo() {}",
+ "'gaga'; export class C extends null {}",
+ "'gaga'; export let a = 1",
+ "'gaga'; export default 1",
+ "'gaga'; export default function foo() {}",
+ "'gaga'; export default function () {}",
+ "'gaga'; export default (function () {})",
+ "'gaga'; export default class C extends null {}",
+ "'gaga'; export default (class C extends null {})",
+ };
+
+ for (auto src : sources) {
+ Local<String> source_text = v8_str(src);
+ 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());
+
+ Local<Value> result_1 = module->Evaluate(env.local()).ToLocalChecked();
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+
+ Local<Value> result_2 = module->Evaluate(env.local()).ToLocalChecked();
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+ if (i::FLAG_harmony_top_level_await) {
+ Local<Promise> promise = Local<Promise>::Cast(result_1);
+ CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
+ CHECK(promise->Result()->IsUndefined());
+
+ // Second Evaluation should return the same promise.
+ Local<Promise> promise_too = Local<Promise>::Cast(result_2);
+ CHECK_EQ(promise, promise_too);
+ CHECK_EQ(promise_too->State(), v8::Promise::kFulfilled);
+ CHECK(promise_too->Result()->IsUndefined());
+ } else {
+ CHECK(result_1->StrictEquals(v8_str("gaga")));
+ CHECK(result_2->IsUndefined());
+ }
+ }
+ CHECK(!try_catch.HasCaught());
+ }
+ i::FLAG_harmony_top_level_await = prev_top_level_await;
+}
+
+TEST(ModuleNamespace) {
+ bool prev_top_level_await = i::FLAG_harmony_top_level_await;
+ for (auto top_level_await : {true, false}) {
+ i::FLAG_harmony_top_level_await = top_level_await;
+
+ Isolate* isolate = CcTest::isolate();
+ HandleScope scope(isolate);
+ LocalContext env;
+ v8::TryCatch try_catch(isolate);
+
+ Local<v8::Object> ReferenceError =
+ CompileRun("ReferenceError")->ToObject(env.local()).ToLocalChecked();
+
+ Local<String> source_text = v8_str(
+ "import {a, b} from 'export var a = 1; export let b = 2';"
+ "export function geta() {return a};"
+ "export function getb() {return b};"
+ "export let radio = 3;"
+ "export var gaga = 4;");
+ 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());
+ Local<Value> ns = module->GetModuleNamespace();
+ CHECK_EQ(Module::kInstantiated, module->GetStatus());
+ Local<v8::Object> nsobj = ns->ToObject(env.local()).ToLocalChecked();
+ CHECK_EQ(nsobj->CreationContext(), env.local());
+
+ // a, b
+ CHECK(nsobj->Get(env.local(), v8_str("a")).ToLocalChecked()->IsUndefined());
+ CHECK(nsobj->Get(env.local(), v8_str("b")).ToLocalChecked()->IsUndefined());
+
+ // geta
+ {
+ auto geta = nsobj->Get(env.local(), v8_str("geta")).ToLocalChecked();
+ auto a = geta.As<v8::Function>()
+ ->Call(env.local(), geta, 0, nullptr)
+ .ToLocalChecked();
+ CHECK(a->IsUndefined());
+ }
+
+ // getb
+ {
+ v8::TryCatch inner_try_catch(isolate);
+ auto getb = nsobj->Get(env.local(), v8_str("getb")).ToLocalChecked();
+ CHECK(getb.As<v8::Function>()
+ ->Call(env.local(), getb, 0, nullptr)
+ .IsEmpty());
+ CHECK(inner_try_catch.HasCaught());
+ CHECK(inner_try_catch.Exception()
+ ->InstanceOf(env.local(), ReferenceError)
+ .FromJust());
+ }
+
+ // radio
+ {
+ v8::TryCatch inner_try_catch(isolate);
+ // https://bugs.chromium.org/p/v8/issues/detail?id=7235
+ // CHECK(nsobj->Get(env.local(), v8_str("radio")).IsEmpty());
+ CHECK(nsobj->Get(env.local(), v8_str("radio"))
+ .ToLocalChecked()
+ ->IsUndefined());
+ CHECK(inner_try_catch.HasCaught());
+ CHECK(inner_try_catch.Exception()
+ ->InstanceOf(env.local(), ReferenceError)
+ .FromJust());
+ }
+
+ // gaga
+ {
+ auto gaga = nsobj->Get(env.local(), v8_str("gaga")).ToLocalChecked();
+ CHECK(gaga->IsUndefined());
+ }
+
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(Module::kInstantiated, module->GetStatus());
+ module->Evaluate(env.local()).ToLocalChecked();
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+
+ // geta
+ {
+ auto geta = nsobj->Get(env.local(), v8_str("geta")).ToLocalChecked();
+ auto a = geta.As<v8::Function>()
+ ->Call(env.local(), geta, 0, nullptr)
+ .ToLocalChecked();
+ CHECK_EQ(1, a->Int32Value(env.local()).FromJust());
+ }
+
+ // getb
+ {
+ auto getb = nsobj->Get(env.local(), v8_str("getb")).ToLocalChecked();
+ auto b = getb.As<v8::Function>()
+ ->Call(env.local(), getb, 0, nullptr)
+ .ToLocalChecked();
+ CHECK_EQ(2, b->Int32Value(env.local()).FromJust());
+ }
+
+ // radio
+ {
+ auto radio = nsobj->Get(env.local(), v8_str("radio")).ToLocalChecked();
+ CHECK_EQ(3, radio->Int32Value(env.local()).FromJust());
+ }
+
+ // gaga
+ {
+ auto gaga = nsobj->Get(env.local(), v8_str("gaga")).ToLocalChecked();
+ CHECK_EQ(4, gaga->Int32Value(env.local()).FromJust());
+ }
+ CHECK(!try_catch.HasCaught());
+ }
+ i::FLAG_harmony_top_level_await = prev_top_level_await;
+}
+
+TEST(ModuleEvaluationTopLevelAwait) {
+ bool previous_top_level_await_flag_value = i::FLAG_harmony_top_level_await;
+ i::FLAG_harmony_top_level_await = true;
Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
LocalContext env;
v8::TryCatch try_catch(isolate);
-
const char* sources[] = {
- "",
- "var a = 1",
- "import '42'",
- "export * from '42'",
- "export {} from '42'",
- "export {}",
- "var a = 1; export {a}",
- "export function foo() {}",
- "export class C extends null {}",
- "export let a = 1",
- "export default 1",
- "export default function foo() {}",
- "export default function () {}",
- "export default (function () {})",
- "export default class C extends null {}",
- "export default (class C extends null {})",
- "for (var i = 0; i < 5; ++i) {}",
+ "await 42",
+ "import 'await 42';",
+ "import '42'; import 'await 42';",
};
for (auto src : sources) {
@@ -303,41 +685,30 @@ TEST(ModuleEvaluationCompletion1) {
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());
+ Local<Promise> promise =
+ Local<Promise>::Cast(module->Evaluate(env.local()).ToLocalChecked());
CHECK_EQ(Module::kEvaluated, module->GetStatus());
+ CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
+ CHECK(promise->Result()->IsUndefined());
+ CHECK(!try_catch.HasCaught());
}
-
- CHECK(!try_catch.HasCaught());
+ i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value;
}
-TEST(ModuleEvaluationCompletion2) {
+TEST(ModuleEvaluationTopLevelAwaitError) {
+ bool previous_top_level_await_flag_value = i::FLAG_harmony_top_level_await;
+ i::FLAG_harmony_top_level_await = true;
Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
LocalContext env;
- v8::TryCatch try_catch(isolate);
-
const char* sources[] = {
- "'gaga'; ",
- "'gaga'; var a = 1",
- "'gaga'; import '42'",
- "'gaga'; export * from '42'",
- "'gaga'; export {} from '42'",
- "'gaga'; export {}",
- "'gaga'; var a = 1; export {a}",
- "'gaga'; export function foo() {}",
- "'gaga'; export class C extends null {}",
- "'gaga'; export let a = 1",
- "'gaga'; export default 1",
- "'gaga'; export default function foo() {}",
- "'gaga'; export default function () {}",
- "'gaga'; export default (function () {})",
- "'gaga'; export default class C extends null {}",
- "'gaga'; export default (class C extends null {})",
+ "await 42; throw 'boom';",
+ "import 'await 42; throw \"boom\";';",
+ "import '42'; import 'await 42; throw \"boom\";';",
};
for (auto src : sources) {
+ v8::TryCatch try_catch(isolate);
Local<String> source_text = v8_str(src);
ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
ScriptCompiler::Source source(source_text, origin);
@@ -349,126 +720,170 @@ TEST(ModuleEvaluationCompletion2) {
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());
+ Local<Promise> promise =
+ Local<Promise>::Cast(module->Evaluate(env.local()).ToLocalChecked());
+ CHECK_EQ(Module::kErrored, module->GetStatus());
+ CHECK_EQ(promise->State(), v8::Promise::kRejected);
+ CHECK(promise->Result()->StrictEquals(v8_str("boom")));
+ CHECK(module->GetException()->StrictEquals(v8_str("boom")));
+
+ // TODO(joshualitt) I am not sure, but this might not be supposed to throw
+ // because it is async.
+ CHECK(!try_catch.HasCaught());
}
+ i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value;
+}
- CHECK(!try_catch.HasCaught());
+namespace {
+struct DynamicImportData {
+ DynamicImportData(Isolate* isolate_, Local<Promise::Resolver> resolver_,
+ Local<Context> context_, bool should_resolve_)
+ : isolate(isolate_), should_resolve(should_resolve_) {
+ resolver.Reset(isolate, resolver_);
+ context.Reset(isolate, context_);
+ }
+
+ Isolate* isolate;
+ v8::Global<Promise::Resolver> resolver;
+ v8::Global<Context> context;
+ bool should_resolve;
+};
+
+void DoHostImportModuleDynamically(void* import_data) {
+ std::unique_ptr<DynamicImportData> import_data_(
+ static_cast<DynamicImportData*>(import_data));
+ Isolate* isolate(import_data_->isolate);
+ HandleScope handle_scope(isolate);
+
+ Local<Promise::Resolver> resolver(import_data_->resolver.Get(isolate));
+ Local<Context> realm(import_data_->context.Get(isolate));
+ Context::Scope context_scope(realm);
+
+ if (import_data_->should_resolve) {
+ resolver->Resolve(realm, True(isolate)).ToChecked();
+ } else {
+ resolver->Reject(realm, v8_str("boom")).ToChecked();
+ }
}
-TEST(ModuleNamespace) {
+v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallbackResolve(
+ Local<Context> context, Local<v8::ScriptOrModule> referrer,
+ Local<String> specifier) {
+ Isolate* isolate = context->GetIsolate();
+ Local<v8::Promise::Resolver> resolver =
+ v8::Promise::Resolver::New(context).ToLocalChecked();
+
+ DynamicImportData* data =
+ new DynamicImportData(isolate, resolver, context, true);
+ isolate->EnqueueMicrotask(DoHostImportModuleDynamically, data);
+ return resolver->GetPromise();
+}
+
+v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallbackReject(
+ Local<Context> context, Local<v8::ScriptOrModule> referrer,
+ Local<String> specifier) {
+ Isolate* isolate = context->GetIsolate();
+ Local<v8::Promise::Resolver> resolver =
+ v8::Promise::Resolver::New(context).ToLocalChecked();
+
+ DynamicImportData* data =
+ new DynamicImportData(isolate, resolver, context, false);
+ isolate->EnqueueMicrotask(DoHostImportModuleDynamically, data);
+ return resolver->GetPromise();
+}
+
+} // namespace
+
+TEST(ModuleEvaluationTopLevelAwaitDynamicImport) {
+ bool previous_top_level_await_flag_value = i::FLAG_harmony_top_level_await;
+ bool previous_dynamic_import_flag_value = i::FLAG_harmony_dynamic_import;
+ i::FLAG_harmony_top_level_await = true;
+ i::FLAG_harmony_dynamic_import = true;
Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
+ isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
+ isolate->SetHostImportModuleDynamicallyCallback(
+ HostImportModuleDynamicallyCallbackResolve);
LocalContext env;
v8::TryCatch try_catch(isolate);
+ const char* sources[] = {
+ "await import('foo');",
+ "import 'await import(\"foo\");';",
+ "import '42'; import 'await import(\"foo\");';",
+ };
- Local<v8::Object> ReferenceError =
- CompileRun("ReferenceError")->ToObject(env.local()).ToLocalChecked();
-
- Local<String> source_text = v8_str(
- "import {a, b} from 'export var a = 1; export let b = 2';"
- "export function geta() {return a};"
- "export function getb() {return b};"
- "export let radio = 3;"
- "export var gaga = 4;");
- 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());
- Local<Value> ns = module->GetModuleNamespace();
- CHECK_EQ(Module::kInstantiated, module->GetStatus());
- Local<v8::Object> nsobj = ns->ToObject(env.local()).ToLocalChecked();
-
- // a, b
- CHECK(nsobj->Get(env.local(), v8_str("a")).ToLocalChecked()->IsUndefined());
- CHECK(nsobj->Get(env.local(), v8_str("b")).ToLocalChecked()->IsUndefined());
-
- // geta
- {
- auto geta = nsobj->Get(env.local(), v8_str("geta")).ToLocalChecked();
- auto a = geta.As<v8::Function>()
- ->Call(env.local(), geta, 0, nullptr)
- .ToLocalChecked();
- CHECK(a->IsUndefined());
- }
-
- // getb
- {
- v8::TryCatch inner_try_catch(isolate);
- auto getb = nsobj->Get(env.local(), v8_str("getb")).ToLocalChecked();
- CHECK(
- getb.As<v8::Function>()->Call(env.local(), getb, 0, nullptr).IsEmpty());
- CHECK(inner_try_catch.HasCaught());
- CHECK(inner_try_catch.Exception()
- ->InstanceOf(env.local(), ReferenceError)
+ for (auto src : sources) {
+ Local<String> source_text = v8_str(src);
+ 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());
- // radio
- {
- v8::TryCatch inner_try_catch(isolate);
- // https://bugs.chromium.org/p/v8/issues/detail?id=7235
- // CHECK(nsobj->Get(env.local(), v8_str("radio")).IsEmpty());
- CHECK(nsobj->Get(env.local(), v8_str("radio"))
- .ToLocalChecked()
- ->IsUndefined());
- CHECK(inner_try_catch.HasCaught());
- CHECK(inner_try_catch.Exception()
- ->InstanceOf(env.local(), ReferenceError)
- .FromJust());
- }
+ Local<Promise> promise =
+ Local<Promise>::Cast(module->Evaluate(env.local()).ToLocalChecked());
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+ CHECK_EQ(promise->State(), v8::Promise::kPending);
+ CHECK(!try_catch.HasCaught());
- // gaga
- {
- auto gaga = nsobj->Get(env.local(), v8_str("gaga")).ToLocalChecked();
- CHECK(gaga->IsUndefined());
+ isolate->RunMicrotasks();
+ CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
}
+ i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value;
+ i::FLAG_harmony_dynamic_import = previous_dynamic_import_flag_value;
+}
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(Module::kInstantiated, module->GetStatus());
- module->Evaluate(env.local()).ToLocalChecked();
- CHECK_EQ(Module::kEvaluated, module->GetStatus());
-
- // geta
- {
- auto geta = nsobj->Get(env.local(), v8_str("geta")).ToLocalChecked();
- auto a = geta.As<v8::Function>()
- ->Call(env.local(), geta, 0, nullptr)
- .ToLocalChecked();
- CHECK_EQ(1, a->Int32Value(env.local()).FromJust());
- }
+TEST(ModuleEvaluationTopLevelAwaitDynamicImportError) {
+ bool previous_top_level_await_flag_value = i::FLAG_harmony_top_level_await;
+ bool previous_dynamic_import_flag_value = i::FLAG_harmony_dynamic_import;
+ i::FLAG_harmony_top_level_await = true;
+ i::FLAG_harmony_dynamic_import = true;
+ Isolate* isolate = CcTest::isolate();
+ HandleScope scope(isolate);
+ isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
+ isolate->SetHostImportModuleDynamicallyCallback(
+ HostImportModuleDynamicallyCallbackReject);
+ LocalContext env;
+ v8::TryCatch try_catch(isolate);
+ const char* sources[] = {
+ "await import('foo');",
+ "import 'await import(\"foo\");';",
+ "import '42'; import 'await import(\"foo\");';",
+ };
- // getb
- {
- auto getb = nsobj->Get(env.local(), v8_str("getb")).ToLocalChecked();
- auto b = getb.As<v8::Function>()
- ->Call(env.local(), getb, 0, nullptr)
- .ToLocalChecked();
- CHECK_EQ(2, b->Int32Value(env.local()).FromJust());
- }
+ for (auto src : sources) {
+ Local<String> source_text = v8_str(src);
+ 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());
- // radio
- {
- auto radio = nsobj->Get(env.local(), v8_str("radio")).ToLocalChecked();
- CHECK_EQ(3, radio->Int32Value(env.local()).FromJust());
- }
+ Local<Promise> promise =
+ Local<Promise>::Cast(module->Evaluate(env.local()).ToLocalChecked());
+ CHECK_EQ(Module::kEvaluated, module->GetStatus());
+ CHECK_EQ(promise->State(), v8::Promise::kPending);
+ CHECK(!try_catch.HasCaught());
- // gaga
- {
- auto gaga = nsobj->Get(env.local(), v8_str("gaga")).ToLocalChecked();
- CHECK_EQ(4, gaga->Int32Value(env.local()).FromJust());
+ isolate->RunMicrotasks();
+ CHECK_EQ(Module::kErrored, module->GetStatus());
+ CHECK_EQ(promise->State(), v8::Promise::kRejected);
+ CHECK(promise->Result()->StrictEquals(v8_str("boom")));
+ CHECK(module->GetException()->StrictEquals(v8_str("boom")));
+ CHECK(!try_catch.HasCaught());
}
-
- CHECK(!try_catch.HasCaught());
+ i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value;
+ i::FLAG_harmony_dynamic_import = previous_dynamic_import_flag_value;
}
+
} // anonymous namespace