2016-09-20 23:38:58 +00:00
|
|
|
// 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.
|
|
|
|
|
2019-05-24 13:51:59 +00:00
|
|
|
#include "src/flags/flags.h"
|
2016-09-20 23:38:58 +00:00
|
|
|
|
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
|
2016-09-22 21:03:19 +00:00
|
|
|
namespace {
|
|
|
|
|
2016-09-20 23:38:58 +00:00
|
|
|
using v8::Context;
|
|
|
|
using v8::HandleScope;
|
|
|
|
using v8::Isolate;
|
|
|
|
using v8::Local;
|
|
|
|
using v8::MaybeLocal;
|
|
|
|
using v8::Module;
|
2019-09-13 15:20:47 +00:00
|
|
|
using v8::Promise;
|
2016-09-20 23:38:58 +00:00
|
|
|
using v8::ScriptCompiler;
|
|
|
|
using v8::ScriptOrigin;
|
|
|
|
using v8::String;
|
|
|
|
using v8::Value;
|
|
|
|
|
2017-01-19 06:59:20 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-08 08:46:01 +00:00
|
|
|
static Local<Module> dep1;
|
|
|
|
static Local<Module> dep2;
|
|
|
|
MaybeLocal<Module> ResolveCallback(Local<Context> context,
|
|
|
|
Local<String> specifier,
|
|
|
|
Local<Module> referrer) {
|
2017-04-19 18:28:09 +00:00
|
|
|
Isolate* isolate = CcTest::isolate();
|
2017-12-08 08:46:01 +00:00
|
|
|
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"));
|
2017-04-19 18:28:09 +00:00
|
|
|
return MaybeLocal<Module>();
|
|
|
|
}
|
2016-09-20 23:38:58 +00:00
|
|
|
}
|
|
|
|
|
2017-12-08 08:46:01 +00:00
|
|
|
TEST(ModuleInstantiationFailures1) {
|
2016-09-20 23:38:58 +00:00
|
|
|
Isolate* isolate = CcTest::isolate();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
LocalContext env;
|
2017-04-19 18:28:09 +00:00
|
|
|
v8::TryCatch try_catch(isolate);
|
2016-09-20 23:38:58 +00:00
|
|
|
|
2017-12-08 08:46:01 +00:00
|
|
|
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());
|
|
|
|
}
|
2016-09-20 23:38:58 +00:00
|
|
|
|
|
|
|
// Instantiation should fail.
|
2017-04-19 18:28:09 +00:00
|
|
|
{
|
|
|
|
v8::TryCatch inner_try_catch(isolate);
|
2017-12-08 08:46:01 +00:00
|
|
|
CHECK(module->InstantiateModule(env.local(), ResolveCallback).IsNothing());
|
2017-04-19 18:28:09 +00:00
|
|
|
CHECK(inner_try_catch.HasCaught());
|
|
|
|
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
|
2017-12-08 08:46:01 +00:00
|
|
|
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
|
2017-04-19 18:28:09 +00:00
|
|
|
}
|
2016-09-20 23:38:58 +00:00
|
|
|
|
|
|
|
// Start over again...
|
2017-12-08 08:46:01 +00:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
2016-09-20 23:38:58 +00:00
|
|
|
|
2017-12-08 08:46:01 +00:00
|
|
|
// 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.
|
2017-04-19 18:28:09 +00:00
|
|
|
{
|
|
|
|
v8::TryCatch inner_try_catch(isolate);
|
2017-12-08 08:46:01 +00:00
|
|
|
CHECK(module->InstantiateModule(env.local(), ResolveCallback).IsNothing());
|
2017-04-19 18:28:09 +00:00
|
|
|
CHECK(inner_try_catch.HasCaught());
|
2017-12-08 08:46:01 +00:00
|
|
|
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
|
|
|
|
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
|
2017-04-19 18:28:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(!try_catch.HasCaught());
|
2016-09-20 23:38:58 +00:00
|
|
|
}
|
|
|
|
|
2017-12-08 08:46:01 +00:00
|
|
|
TEST(ModuleInstantiationFailures2) {
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-20 23:38:58 +00:00
|
|
|
static MaybeLocal<Module> CompileSpecifierAsModuleResolveCallback(
|
2016-10-11 19:22:03 +00:00
|
|
|
Local<Context> context, Local<String> specifier, Local<Module> referrer) {
|
2017-01-19 06:59:20 +00:00
|
|
|
ScriptOrigin origin = ModuleOrigin(v8_str("module.js"), CcTest::isolate());
|
2016-09-20 23:38:58 +00:00
|
|
|
ScriptCompiler::Source source(specifier, origin);
|
|
|
|
return ScriptCompiler::CompileModule(CcTest::isolate(), &source)
|
|
|
|
.ToLocalChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ModuleEvaluation) {
|
2019-09-13 15:20:47 +00:00
|
|
|
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;
|
2019-09-11 16:58:40 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
Isolate* isolate = CcTest::isolate();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
LocalContext env;
|
|
|
|
v8::TryCatch try_catch(isolate);
|
2019-09-11 16:58:40 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
Local<String> source_text = v8_str(
|
|
|
|
"import 'Object.expando = 5';"
|
|
|
|
"import 'Object.expando *= 2';");
|
2017-02-28 10:11:54 +00:00
|
|
|
ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
|
|
|
|
ScriptCompiler::Source source(source_text, origin);
|
|
|
|
Local<Module> module =
|
|
|
|
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
2017-06-28 14:19:39 +00:00
|
|
|
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
|
2017-05-29 11:57:50 +00:00
|
|
|
CHECK(module
|
|
|
|
->InstantiateModule(env.local(),
|
|
|
|
CompileSpecifierAsModuleResolveCallback)
|
|
|
|
.FromJust());
|
2017-06-28 14:19:39 +00:00
|
|
|
CHECK_EQ(Module::kInstantiated, module->GetStatus());
|
2019-09-13 15:20:47 +00:00
|
|
|
|
|
|
|
MaybeLocal<Value> result = module->Evaluate(env.local());
|
2017-06-28 14:19:39 +00:00
|
|
|
CHECK_EQ(Module::kEvaluated, module->GetStatus());
|
2019-09-13 15:20:47 +00:00
|
|
|
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());
|
2017-02-28 10:11:54 +00:00
|
|
|
}
|
2019-09-13 15:20:47 +00:00
|
|
|
i::FLAG_harmony_top_level_await = prev_top_level_await;
|
2019-09-11 16:58:40 +00:00
|
|
|
}
|
2019-09-11 13:20:41 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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);
|
2017-02-28 10:11:54 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
Local<String> source_text =
|
|
|
|
v8_str("Object.x = (Object.x || 0) + 1; throw 'boom';");
|
2017-02-28 10:11:54 +00:00
|
|
|
ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
|
|
|
|
ScriptCompiler::Source source(source_text, origin);
|
|
|
|
Local<Module> module =
|
|
|
|
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
2017-06-28 14:19:39 +00:00
|
|
|
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
|
2017-05-29 11:57:50 +00:00
|
|
|
CHECK(module
|
|
|
|
->InstantiateModule(env.local(),
|
|
|
|
CompileSpecifierAsModuleResolveCallback)
|
|
|
|
.FromJust());
|
2017-06-28 14:19:39 +00:00
|
|
|
CHECK_EQ(Module::kInstantiated, module->GetStatus());
|
2019-09-11 16:58:40 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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;
|
2019-09-11 13:20:41 +00:00
|
|
|
}
|
2017-12-21 14:49:09 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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;
|
2017-12-21 14:49:09 +00:00
|
|
|
}
|
2019-09-13 15:20:47 +00:00
|
|
|
}
|
2017-12-21 14:49:09 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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)
|
2019-09-11 16:58:40 +00:00
|
|
|
.FromJust());
|
2019-09-13 15:20:47 +00:00
|
|
|
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());
|
2017-12-21 14:49:09 +00:00
|
|
|
}
|
2019-09-13 15:20:47 +00:00
|
|
|
i::FLAG_harmony_top_level_await = prev_top_level_await;
|
|
|
|
}
|
2017-12-21 14:49:09 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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());
|
2019-09-11 16:58:40 +00:00
|
|
|
}
|
2019-09-13 15:20:47 +00:00
|
|
|
i::FLAG_harmony_top_level_await = prev_top_level_await;
|
|
|
|
}
|
2017-12-21 14:49:09 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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());
|
2019-09-11 16:58:40 +00:00
|
|
|
}
|
2019-09-13 15:20:47 +00:00
|
|
|
i::FLAG_harmony_top_level_await = prev_top_level_await;
|
|
|
|
}
|
2017-12-21 14:49:09 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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;
|
2017-12-21 14:49:09 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
Isolate* isolate = CcTest::isolate();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
LocalContext env;
|
|
|
|
v8::TryCatch try_catch(isolate);
|
2019-09-11 16:58:40 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
Local<v8::Object> ReferenceError =
|
|
|
|
CompileRun("ReferenceError")->ToObject(env.local()).ToLocalChecked();
|
2017-12-21 14:49:09 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
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)
|
|
|
|
.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());
|
2019-09-11 16:58:40 +00:00
|
|
|
|
2019-09-13 15:20:47 +00:00
|
|
|
// 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());
|
2017-12-21 14:49:09 +00:00
|
|
|
}
|
2019-09-13 15:20:47 +00:00
|
|
|
i::FLAG_harmony_top_level_await = prev_top_level_await;
|
2017-12-21 14:49:09 +00:00
|
|
|
}
|
2016-09-22 21:03:19 +00:00
|
|
|
} // anonymous namespace
|