a209dcf6a1
V8 now takes care of recording a module's status, as proposed in https://github.com/tc39/ecma262/pull/916. R=adamk@chromium.org Bug: v8:1569, chromium:594639 Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng Change-Id: Id884f1c817e1dc3eea79a5d5a7f5cd996db1dbb0 Reviewed-on: https://chromium-review.googlesource.com/548500 Commit-Queue: Georg Neis <neis@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/master@{#46293}
285 lines
10 KiB
C++
285 lines
10 KiB
C++
// 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.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::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;
|
|
}
|
|
|
|
MaybeLocal<Module> FailAlwaysResolveCallback(Local<Context> context,
|
|
Local<String> specifier,
|
|
Local<Module> referrer) {
|
|
Isolate* isolate = context->GetIsolate();
|
|
isolate->ThrowException(v8_str("boom"));
|
|
return MaybeLocal<Module>();
|
|
}
|
|
|
|
static int g_count = 0;
|
|
MaybeLocal<Module> FailOnSecondCallResolveCallback(Local<Context> context,
|
|
Local<String> specifier,
|
|
Local<Module> referrer) {
|
|
Isolate* isolate = CcTest::isolate();
|
|
if (g_count++ > 0) {
|
|
isolate->ThrowException(v8_str("booom"));
|
|
return MaybeLocal<Module>();
|
|
}
|
|
Local<String> source_text = v8_str("");
|
|
ScriptOrigin origin = ModuleOrigin(v8_str("module.js"), isolate);
|
|
ScriptCompiler::Source source(source_text, origin);
|
|
return ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
|
}
|
|
|
|
TEST(ModuleInstantiationFailures) {
|
|
Isolate* isolate = CcTest::isolate();
|
|
HandleScope scope(isolate);
|
|
LocalContext env;
|
|
v8::TryCatch try_catch(isolate);
|
|
|
|
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);
|
|
Local<Module> module =
|
|
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
|
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
|
|
CHECK_EQ(2, module->GetModuleRequestsLength());
|
|
CHECK(v8_str("./foo.js")->StrictEquals(module->GetModuleRequest(0)));
|
|
v8::Location loc = module->GetModuleRequestLocation(0);
|
|
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(), FailAlwaysResolveCallback)
|
|
.IsNothing());
|
|
CHECK(inner_try_catch.HasCaught());
|
|
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
|
|
CHECK_EQ(Module::kErrored, module->GetStatus());
|
|
Local<Value> exception = module->GetException();
|
|
CHECK(exception->StrictEquals(v8_str("boom")));
|
|
// TODO(neis): Check object identity.
|
|
}
|
|
|
|
// Start over again...
|
|
module = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
|
|
|
// Instantiation should fail if a sub-module fails to resolve.
|
|
g_count = 0;
|
|
{
|
|
v8::TryCatch inner_try_catch(isolate);
|
|
CHECK(
|
|
module->InstantiateModule(env.local(), FailOnSecondCallResolveCallback)
|
|
.IsNothing());
|
|
CHECK(inner_try_catch.HasCaught());
|
|
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("booom")));
|
|
CHECK_EQ(Module::kErrored, module->GetStatus());
|
|
Local<Value> exception = module->GetException();
|
|
CHECK(exception->StrictEquals(v8_str("booom")));
|
|
}
|
|
|
|
CHECK(!try_catch.HasCaught());
|
|
}
|
|
|
|
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) {
|
|
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());
|
|
CHECK(!module->Evaluate(env.local()).IsEmpty());
|
|
CHECK_EQ(Module::kEvaluated, module->GetStatus());
|
|
ExpectInt32("Object.expando", 10);
|
|
|
|
CHECK(!try_catch.HasCaught());
|
|
}
|
|
|
|
TEST(ModuleEvaluationError) {
|
|
Isolate* isolate = CcTest::isolate();
|
|
HandleScope scope(isolate);
|
|
LocalContext env;
|
|
v8::TryCatch try_catch(isolate);
|
|
|
|
Local<String> source_text =
|
|
v8_str("Object.x = (Object.x || 0) + 1; throw 'boom';");
|
|
ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
|
|
ScriptCompiler::Source source(source_text, origin);
|
|
Local<Module> module =
|
|
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
|
CHECK_EQ(Module::kUninstantiated, module->GetStatus());
|
|
CHECK(module
|
|
->InstantiateModule(env.local(),
|
|
CompileSpecifierAsModuleResolveCallback)
|
|
.FromJust());
|
|
CHECK_EQ(Module::kInstantiated, module->GetStatus());
|
|
|
|
{
|
|
v8::TryCatch inner_try_catch(isolate);
|
|
CHECK(module->Evaluate(env.local()).IsEmpty());
|
|
CHECK(inner_try_catch.HasCaught());
|
|
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
|
|
CHECK_EQ(Module::kErrored, module->GetStatus());
|
|
Local<Value> exception = module->GetException();
|
|
CHECK(exception->StrictEquals(v8_str("boom")));
|
|
ExpectInt32("Object.x", 1);
|
|
}
|
|
|
|
{
|
|
v8::TryCatch inner_try_catch(isolate);
|
|
CHECK(module->Evaluate(env.local()).IsEmpty());
|
|
CHECK(inner_try_catch.HasCaught());
|
|
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
|
|
CHECK_EQ(Module::kErrored, module->GetStatus());
|
|
Local<Value> exception = module->GetException();
|
|
CHECK(exception->StrictEquals(v8_str("boom")));
|
|
ExpectInt32("Object.x", 1);
|
|
}
|
|
|
|
CHECK(!try_catch.HasCaught());
|
|
}
|
|
|
|
TEST(ModuleEvaluationCompletion1) {
|
|
Isolate* isolate = CcTest::isolate();
|
|
HandleScope scope(isolate);
|
|
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());
|
|
CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
|
|
CHECK_EQ(Module::kEvaluated, module->GetStatus());
|
|
CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
|
|
CHECK_EQ(Module::kEvaluated, module->GetStatus());
|
|
}
|
|
|
|
CHECK(!try_catch.HasCaught());
|
|
}
|
|
|
|
TEST(ModuleEvaluationCompletion2) {
|
|
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());
|
|
CHECK(module->Evaluate(env.local())
|
|
.ToLocalChecked()
|
|
->StrictEquals(v8_str("gaga")));
|
|
CHECK_EQ(Module::kEvaluated, module->GetStatus());
|
|
CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
|
|
CHECK_EQ(Module::kEvaluated, module->GetStatus());
|
|
}
|
|
|
|
CHECK(!try_catch.HasCaught());
|
|
}
|
|
|
|
} // anonymous namespace
|