| // Copyright 2016 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/flags/flags.h" |
| |
| #include "test/cctest/cctest.h" |
| |
| namespace { |
| |
| using v8::Context; |
| using v8::HandleScope; |
| using v8::Isolate; |
| using v8::Local; |
| using v8::MaybeLocal; |
| using v8::Module; |
| using v8::Promise; |
| using v8::ScriptCompiler; |
| using v8::ScriptOrigin; |
| using v8::String; |
| using v8::Value; |
| |
| ScriptOrigin ModuleOrigin(Local<v8::Value> resource_name, Isolate* isolate) { |
| ScriptOrigin origin(resource_name, Local<v8::Integer>(), Local<v8::Integer>(), |
| Local<v8::Boolean>(), Local<v8::Integer>(), |
| Local<v8::Value>(), Local<v8::Boolean>(), |
| Local<v8::Boolean>(), True(isolate)); |
| return origin; |
| } |
| |
| static Local<Module> dep1; |
| static Local<Module> dep2; |
| MaybeLocal<Module> ResolveCallback(Local<Context> context, |
| Local<String> specifier, |
| Local<Module> referrer) { |
| Isolate* isolate = CcTest::isolate(); |
| if (specifier->StrictEquals(v8_str("./dep1.js"))) { |
| return dep1; |
| } else if (specifier->StrictEquals(v8_str("./dep2.js"))) { |
| return dep2; |
| } else { |
| isolate->ThrowException(v8_str("boom")); |
| return MaybeLocal<Module>(); |
| } |
| } |
| |
| TEST(ModuleInstantiationFailures1) { |
| 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<Module> module; |
| { |
| Local<String> source_text = v8_str( |
| "import './foo.js';\n" |
| "export {} from './bar.js';"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| 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); |
| CHECK_EQ(0, loc.GetLineNumber()); |
| CHECK_EQ(7, loc.GetColumnNumber()); |
| CHECK(v8_str("./bar.js")->StrictEquals(module->GetModuleRequest(1))); |
| loc = module->GetModuleRequestLocation(1); |
| CHECK_EQ(1, loc.GetLineNumber()); |
| CHECK_EQ(15, loc.GetColumnNumber()); |
| } |
| |
| // Instantiation should fail. |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| CHECK( |
| module->InstantiateModule(env.local(), ResolveCallback).IsNothing()); |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK_EQ(Module::kUninstantiated, module->GetStatus()); |
| } |
| |
| // Start over again... |
| { |
| Local<String> source_text = v8_str( |
| "import './dep1.js';\n" |
| "export {} from './bar.js';"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| module = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| } |
| |
| // dep1.js |
| { |
| Local<String> source_text = v8_str(""); |
| ScriptOrigin origin = ModuleOrigin(v8_str("dep1.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| dep1 = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| } |
| |
| // Instantiation should fail because a sub-module fails to resolve. |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| CHECK( |
| module->InstantiateModule(env.local(), ResolveCallback).IsNothing()); |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK_EQ(Module::kUninstantiated, module->GetStatus()); |
| } |
| |
| CHECK(!try_catch.HasCaught()); |
| } |
| i::FLAG_harmony_top_level_await = prev_top_level_await; |
| } |
| |
| TEST(ModuleInstantiationFailures2) { |
| 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); |
| |
| // root1.js |
| Local<Module> root; |
| { |
| Local<String> source_text = |
| v8_str("import './dep1.js'; import './dep2.js'"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("root1.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| root = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| } |
| |
| // dep1.js |
| { |
| Local<String> source_text = v8_str("export let x = 42"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("dep1.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| dep1 = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| } |
| |
| // dep2.js |
| { |
| Local<String> source_text = v8_str("import {foo} from './dep3.js'"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("dep2.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| dep2 = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| } |
| |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| CHECK(root->InstantiateModule(env.local(), ResolveCallback).IsNothing()); |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK_EQ(Module::kUninstantiated, root->GetStatus()); |
| CHECK_EQ(Module::kUninstantiated, dep1->GetStatus()); |
| CHECK_EQ(Module::kUninstantiated, dep2->GetStatus()); |
| } |
| |
| // Change dep2.js |
| { |
| Local<String> source_text = v8_str("import {foo} from './dep2.js'"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("dep2.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| dep2 = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| } |
| |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| CHECK(root->InstantiateModule(env.local(), ResolveCallback).IsNothing()); |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(!inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK_EQ(Module::kUninstantiated, root->GetStatus()); |
| CHECK_EQ(Module::kInstantiated, dep1->GetStatus()); |
| CHECK_EQ(Module::kUninstantiated, dep2->GetStatus()); |
| } |
| |
| // Change dep2.js again |
| { |
| Local<String> source_text = v8_str("import {foo} from './dep3.js'"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("dep2.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| dep2 = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| } |
| |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| CHECK(root->InstantiateModule(env.local(), ResolveCallback).IsNothing()); |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK_EQ(Module::kUninstantiated, root->GetStatus()); |
| CHECK_EQ(Module::kInstantiated, dep1->GetStatus()); |
| CHECK_EQ(Module::kUninstantiated, dep2->GetStatus()); |
| } |
| } |
| i::FLAG_harmony_top_level_await = prev_top_level_await; |
| } |
| |
| static MaybeLocal<Module> CompileSpecifierAsModuleResolveCallback( |
| Local<Context> context, Local<String> specifier, Local<Module> referrer) { |
| ScriptOrigin origin = ModuleOrigin(v8_str("module.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(specifier, origin); |
| return ScriptCompiler::CompileModule(CcTest::isolate(), &source) |
| .ToLocalChecked(); |
| } |
| |
| TEST(ModuleEvaluation) { |
| 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> 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(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; |
| |
| 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); |
| MaybeLocal<Value> result = 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 throw and errored evaluation returns |
| // a rejected promise with the exception. |
| CHECK(!inner_try_catch.HasCaught()); |
| Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked()); |
| CHECK_EQ(promise->State(), v8::Promise::kRejected); |
| CHECK_EQ(promise->Result(), module->GetException()); |
| } else { |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK(result.IsEmpty()); |
| } |
| } |
| |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| MaybeLocal<Value> result = 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 throw and errored evaluation returns |
| // a rejected promise with the exception. |
| CHECK(!inner_try_catch.HasCaught()); |
| Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked()); |
| CHECK_EQ(promise->State(), v8::Promise::kRejected); |
| CHECK_EQ(promise->Result(), module->GetException()); |
| } else { |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK(result.IsEmpty()); |
| } |
| } |
| |
| CHECK(!try_catch.HasCaught()); |
| } |
| i::FLAG_harmony_top_level_await = prev_top_level_await; |
| } |
| |
| 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; |
| } |
| } |
| |
| 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()); |
| |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| MaybeLocal<Value> result = failure_module->Evaluate(env.local()); |
| CHECK_EQ(Module::kErrored, failure_module->GetStatus()); |
| Local<Value> exception = failure_module->GetException(); |
| CHECK(exception->StrictEquals(v8_str("boom"))); |
| |
| if (i::FLAG_harmony_top_level_await) { |
| // With top level await, we do not throw and errored evaluation returns |
| // a rejected promise with the exception. |
| CHECK(!inner_try_catch.HasCaught()); |
| Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked()); |
| CHECK_EQ(promise->State(), v8::Promise::kRejected); |
| CHECK_EQ(promise->Result(), failure_module->GetException()); |
| } else { |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK(result.IsEmpty()); |
| } |
| } |
| |
| 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()); |
| |
| { |
| v8::TryCatch inner_try_catch(isolate); |
| MaybeLocal<Value> result = 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 throw and errored evaluation returns |
| // a rejected promise with the exception. |
| CHECK(!inner_try_catch.HasCaught()); |
| Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked()); |
| CHECK_EQ(promise->State(), v8::Promise::kRejected); |
| CHECK_EQ(promise->Result(), failure_module->GetException()); |
| } else { |
| CHECK(inner_try_catch.HasCaught()); |
| CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); |
| CHECK(result.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[] = { |
| "await 42", |
| "import 'await 42';", |
| "import '42'; import 'await 42';", |
| }; |
| |
| 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<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()); |
| } |
| i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value; |
| } |
| |
| 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; |
| const char* sources[] = { |
| "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); |
| 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<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(cbruni) 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; |
| } |
| |
| 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(); |
| } |
| } |
| |
| 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; |
| i::FLAG_harmony_top_level_await = 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\");';", |
| }; |
| |
| 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<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()); |
| |
| isolate->PerformMicrotaskCheckpoint(); |
| CHECK_EQ(promise->State(), v8::Promise::kFulfilled); |
| } |
| i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value; |
| } |
| |
| TEST(ModuleEvaluationTopLevelAwaitDynamicImportError) { |
| 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); |
| 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\");';", |
| }; |
| |
| 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<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()); |
| |
| isolate->PerformMicrotaskCheckpoint(); |
| 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()); |
| } |
| i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value; |
| } |
| |
| TEST(TerminateExecutionTopLevelAwaitSync) { |
| 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); |
| |
| env.local() |
| ->Global() |
| ->Set(env.local(), v8_str("terminate"), |
| v8::Function::New(env.local(), |
| [](const v8::FunctionCallbackInfo<Value>& info) { |
| info.GetIsolate()->TerminateExecution(); |
| }) |
| .ToLocalChecked()) |
| .ToChecked(); |
| |
| Local<String> source_text = v8_str("terminate(); while (true) {}"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| Local<Module> module = |
| ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| CHECK(module |
| ->InstantiateModule(env.local(), |
| CompileSpecifierAsModuleResolveCallback) |
| .FromJust()); |
| |
| CHECK(module->Evaluate(env.local()).IsEmpty()); |
| CHECK(try_catch.HasCaught()); |
| CHECK(try_catch.HasTerminated()); |
| CHECK_EQ(module->GetStatus(), Module::kErrored); |
| CHECK_EQ(module->GetException(), v8::Null(isolate)); |
| |
| i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value; |
| } |
| |
| TEST(TerminateExecutionTopLevelAwaitAsync) { |
| 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); |
| |
| env.local() |
| ->Global() |
| ->Set(env.local(), v8_str("terminate"), |
| v8::Function::New(env.local(), |
| [](const v8::FunctionCallbackInfo<Value>& info) { |
| info.GetIsolate()->TerminateExecution(); |
| }) |
| .ToLocalChecked()) |
| .ToChecked(); |
| |
| Local<Promise::Resolver> eval_promise = |
| Promise::Resolver::New(env.local()).ToLocalChecked(); |
| env.local() |
| ->Global() |
| ->Set(env.local(), v8_str("evalPromise"), eval_promise) |
| .ToChecked(); |
| |
| Local<String> source_text = |
| v8_str("await evalPromise; terminate(); while (true) {}"); |
| ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| Local<Module> module = |
| ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| CHECK(module |
| ->InstantiateModule(env.local(), |
| CompileSpecifierAsModuleResolveCallback) |
| .FromJust()); |
| |
| Local<Promise> promise = |
| Local<Promise>::Cast(module->Evaluate(env.local()).ToLocalChecked()); |
| CHECK_EQ(module->GetStatus(), Module::kEvaluated); |
| CHECK_EQ(promise->State(), Promise::PromiseState::kPending); |
| CHECK(!try_catch.HasCaught()); |
| CHECK(!try_catch.HasTerminated()); |
| |
| eval_promise->Resolve(env.local(), v8::Undefined(isolate)).ToChecked(); |
| |
| CHECK(try_catch.HasCaught()); |
| CHECK(try_catch.HasTerminated()); |
| CHECK_EQ(promise->State(), Promise::PromiseState::kPending); |
| |
| // The termination exception doesn't trigger the module's |
| // catch handler, so the module isn't transitioned to kErrored. |
| CHECK_EQ(module->GetStatus(), Module::kEvaluated); |
| |
| i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value; |
| } |
| |
| static Local<Module> async_leaf_module; |
| static Local<Module> sync_leaf_module; |
| static Local<Module> cycle_self_module; |
| static Local<Module> cycle_one_module; |
| static Local<Module> cycle_two_module; |
| MaybeLocal<Module> ResolveCallbackForIsGraphAsyncTopLevelAwait( |
| Local<Context> context, Local<String> specifier, Local<Module> referrer) { |
| if (specifier->StrictEquals(v8_str("./async_leaf.js"))) { |
| return async_leaf_module; |
| } else if (specifier->StrictEquals(v8_str("./sync_leaf.js"))) { |
| return sync_leaf_module; |
| } else if (specifier->StrictEquals(v8_str("./cycle_self.js"))) { |
| return cycle_self_module; |
| } else if (specifier->StrictEquals(v8_str("./cycle_one.js"))) { |
| return cycle_one_module; |
| } else { |
| CHECK(specifier->StrictEquals(v8_str("./cycle_two.js"))); |
| return cycle_two_module; |
| } |
| } |
| |
| TEST(IsGraphAsyncTopLevelAwait) { |
| 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; |
| |
| { |
| Local<String> source_text = v8_str("await notExecuted();"); |
| ScriptOrigin origin = |
| ModuleOrigin(v8_str("async_leaf.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| async_leaf_module = |
| ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| CHECK(async_leaf_module |
| ->InstantiateModule(env.local(), |
| ResolveCallbackForIsGraphAsyncTopLevelAwait) |
| .FromJust()); |
| CHECK(async_leaf_module->IsGraphAsync()); |
| } |
| |
| { |
| Local<String> source_text = v8_str("notExecuted();"); |
| ScriptOrigin origin = |
| ModuleOrigin(v8_str("sync_leaf.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| sync_leaf_module = |
| ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| CHECK(sync_leaf_module |
| ->InstantiateModule(env.local(), |
| ResolveCallbackForIsGraphAsyncTopLevelAwait) |
| .FromJust()); |
| CHECK(!sync_leaf_module->IsGraphAsync()); |
| } |
| |
| { |
| Local<String> source_text = v8_str("import './async_leaf.js'"); |
| ScriptOrigin origin = |
| ModuleOrigin(v8_str("import_async.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| Local<Module> module = |
| ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| CHECK(module |
| ->InstantiateModule(env.local(), |
| ResolveCallbackForIsGraphAsyncTopLevelAwait) |
| .FromJust()); |
| CHECK(module->IsGraphAsync()); |
| } |
| |
| { |
| Local<String> source_text = v8_str("import './sync_leaf.js'"); |
| ScriptOrigin origin = |
| ModuleOrigin(v8_str("import_sync.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| Local<Module> module = |
| ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| CHECK(module |
| ->InstantiateModule(env.local(), |
| ResolveCallbackForIsGraphAsyncTopLevelAwait) |
| .FromJust()); |
| CHECK(!module->IsGraphAsync()); |
| } |
| |
| { |
| Local<String> source_text = v8_str( |
| "import './cycle_self.js'\n" |
| "import './async_leaf.js'"); |
| ScriptOrigin origin = |
| ModuleOrigin(v8_str("cycle_self.js"), CcTest::isolate()); |
| ScriptCompiler::Source source(source_text, origin); |
| cycle_self_module = |
| ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); |
| CHECK(cycle_self_module |
| ->InstantiateModule(env.local(), |
| ResolveCallbackForIsGraphAsyncTopLevelAwait) |
| .FromJust()); |
| CHECK(cycle_self_module->IsGraphAsync()); |
| } |
| |
| { |
| Local<String> source_text1 = v8_str("import './cycle_two.js'"); |
| ScriptOrigin origin1 = |
| ModuleOrigin(v8_str("cycle_one.js"), CcTest::isolate()); |
| ScriptCompiler::Source source1(source_text1, origin1); |
| cycle_one_module = |
| ScriptCompiler::CompileModule(isolate, &source1).ToLocalChecked(); |
| Local<String> source_text2 = v8_str( |
| "import './cycle_one.js'\n" |
| "import './async_leaf.js'"); |
| ScriptOrigin origin2 = |
| ModuleOrigin(v8_str("cycle_two.js"), CcTest::isolate()); |
| ScriptCompiler::Source source2(source_text2, origin2); |
| cycle_two_module = |
| ScriptCompiler::CompileModule(isolate, &source2).ToLocalChecked(); |
| CHECK(cycle_one_module |
| ->InstantiateModule(env.local(), |
| ResolveCallbackForIsGraphAsyncTopLevelAwait) |
| .FromJust()); |
| CHECK(cycle_one_module->IsGraphAsync()); |
| CHECK(cycle_two_module->IsGraphAsync()); |
| } |
| |
| i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value; |
| } |
| |
| } // anonymous namespace |