[modules] Implement the new semantics of instantiation and evaluation.

This implements the changes proposed at
https://github.com/tc39/ecma262/pull/916.
The API will be extended in a follow-up CL.

R=adamk@chromium.org

Bug: v8:1569
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I79476b5b674c924fea390dff1b9bee7f86a111c6
Reviewed-on: https://chromium-review.googlesource.com/544970
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46289}
This commit is contained in:
Georg Neis 2017-06-28 14:56:11 +02:00 committed by Commit Bot
parent e027a3ee23
commit d02cb6f0ff
16 changed files with 361 additions and 69 deletions

View File

@ -2181,7 +2181,7 @@ MaybeLocal<Value> Module::Evaluate(Local<Context> context) {
i::Handle<i::Module> self = Utils::OpenHandle(this);
// It's an API error to call Evaluate before Instantiate.
CHECK(self->instantiated());
CHECK_GE(self->status(), i::Module::kInstantiated);
Local<Value> result;
has_pending_exception = !ToLocal(i::Module::Evaluate(self), &result);

View File

@ -2019,9 +2019,10 @@ Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code) {
module->set_module_namespace(isolate()->heap()->undefined_value());
module->set_requested_modules(*requested_modules);
module->set_script(Script::cast(code->script()));
module->set_status(Module::kUnprepared);
DCHECK(!module->instantiated());
DCHECK(!module->evaluated());
module->set_status(Module::kUninstantiated);
module->set_exception(isolate()->heap()->the_hole_value());
module->set_dfs_index(-1);
module->set_dfs_ancestor_index(-1);
return module;
}

View File

@ -1250,27 +1250,26 @@ void Module::ModuleVerify() {
VerifyPointer(module_namespace());
VerifyPointer(requested_modules());
VerifyPointer(script());
VerifyPointer(exception());
VerifySmiField(kHashOffset);
VerifySmiField(kStatusOffset);
CHECK((!instantiated() && code()->IsSharedFunctionInfo()) ||
(instantiated() && !evaluated() && code()->IsJSFunction()) ||
(instantiated() && evaluated() && code()->IsModuleInfo()));
CHECK((status() < kInstantiating && code()->IsSharedFunctionInfo()) ||
(status() < kEvaluating && code()->IsJSFunction()) ||
code()->IsModuleInfo());
CHECK_EQ(status() == kErrored, !exception()->IsTheHole(GetIsolate()));
CHECK(module_namespace()->IsUndefined(GetIsolate()) ||
module_namespace()->IsJSModuleNamespace());
if (module_namespace()->IsJSModuleNamespace()) {
CHECK(instantiated());
CHECK_LE(kInstantiating, status());
CHECK_EQ(JSModuleNamespace::cast(module_namespace())->module(), this);
}
CHECK_EQ(requested_modules()->length(), info()->module_requests()->length());
CHECK_NE(hash(), 0);
CHECK_LE(kUnprepared, status());
CHECK_LE(status(), kPrepared);
CHECK_IMPLIES(instantiated(), status() == kPrepared);
}
void PrototypeInfo::PrototypeInfoVerify() {

View File

@ -4621,23 +4621,17 @@ ACCESSORS(Module, regular_imports, FixedArray, kRegularImportsOffset)
ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset)
ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset)
ACCESSORS(Module, script, Script, kScriptOffset)
ACCESSORS(Module, exception, Object, kExceptionOffset)
SMI_ACCESSORS(Module, status, kStatusOffset)
SMI_ACCESSORS(Module, dfs_index, kDfsIndexOffset)
SMI_ACCESSORS(Module, dfs_ancestor_index, kDfsAncestorIndexOffset)
SMI_ACCESSORS(Module, hash, kHashOffset)
bool Module::evaluated() const { return code()->IsModuleInfo(); }
void Module::set_evaluated() {
DCHECK(instantiated());
DCHECK(!evaluated());
return set_code(
JSFunction::cast(code())->shared()->scope_info()->ModuleDescriptorInfo());
}
bool Module::instantiated() const { return !code()->IsSharedFunctionInfo(); }
ModuleInfo* Module::info() const {
if (evaluated()) return ModuleInfo::cast(code());
ScopeInfo* scope_info = instantiated()
if (status() >= kEvaluating) {
return ModuleInfo::cast(code());
}
ScopeInfo* scope_info = status() >= kInstantiating
? JSFunction::cast(code())->shared()->scope_info()
: SharedFunctionInfo::cast(code())->scope_info();
return scope_info->ModuleDescriptorInfo();

View File

@ -1299,7 +1299,7 @@ void ModuleInfoEntry::ModuleInfoEntryPrint(std::ostream& os) { // NOLINT
void Module::ModulePrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Module");
// TODO(neis): Simplify once modules have a script field.
if (!evaluated()) {
if (status() < kEvaluating) {
SharedFunctionInfo* shared = code()->IsSharedFunctionInfo()
? SharedFunctionInfo::cast(code())
: JSFunction::cast(code())->shared();
@ -1310,8 +1310,8 @@ void Module::ModulePrint(std::ostream& os) { // NOLINT
os << "\n - exports: " << Brief(exports());
os << "\n - requested_modules: " << Brief(requested_modules());
os << "\n - script: " << Brief(script());
os << "\n - instantiated, evaluated: " << instantiated() << ", "
<< evaluated();
os << "\n - status: " << status();
os << "\n - exception: " << Brief(exception());
os << "\n";
}

View File

@ -19512,6 +19512,48 @@ void Module::StoreVariable(Handle<Module> module, int cell_index,
module->GetCell(cell_index)->set_value(*value);
}
void Module::SetStatus(Status new_status) {
DisallowHeapAllocation no_alloc;
DCHECK_LE(status(), new_status);
DCHECK_NE(new_status, Module::kErrored);
set_status(new_status);
}
void Module::RecordError() {
DisallowHeapAllocation no_alloc;
Isolate* isolate = GetIsolate();
Object* the_exception = isolate->pending_exception();
DCHECK(!the_exception->IsTheHole(isolate));
switch (status()) {
case Module::kUninstantiated:
case Module::kPreInstantiating:
case Module::kInstantiating:
case Module::kEvaluating:
break;
case Module::kErrored:
DCHECK_EQ(exception(), the_exception);
return;
default:
UNREACHABLE();
}
set_code(info());
DCHECK(exception()->IsTheHole(isolate));
set_status(Module::kErrored);
set_exception(the_exception);
}
Object* Module::GetException() {
DisallowHeapAllocation no_alloc;
DCHECK_EQ(status(), Module::kErrored);
Object* the_exception = exception();
DCHECK(!the_exception->IsTheHole(GetIsolate()));
return the_exception;
}
MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
Handle<String> name, int module_request,
MessageLocation loc, bool must_resolve,
@ -19519,15 +19561,23 @@ MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
Isolate* isolate = module->GetIsolate();
Handle<Module> requested_module(
Module::cast(module->requested_modules()->get(module_request)), isolate);
return Module::ResolveExport(requested_module, name, loc, must_resolve,
resolve_set);
MaybeHandle<Cell> result = Module::ResolveExport(requested_module, name, loc,
must_resolve, resolve_set);
if (isolate->has_pending_exception()) {
DCHECK(result.is_null());
module->RecordError();
}
return result;
}
MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
Handle<String> name,
MessageLocation loc, bool must_resolve,
Module::ResolveSet* resolve_set) {
DCHECK_EQ(module->status(), kPrepared);
DCHECK_NE(module->status(), kErrored);
DCHECK_NE(module->status(), kEvaluating);
DCHECK_GE(module->status(), kPreInstantiating);
Isolate* isolate = module->GetIsolate();
Handle<Object> object(module->exports()->Lookup(name), isolate);
if (object->IsCell()) {
@ -19649,14 +19699,39 @@ MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
v8::Module::ResolveCallback callback) {
return PrepareInstantiate(module, context, callback) &&
FinishInstantiate(module, context);
Isolate* isolate = module->GetIsolate();
if (module->status() == kErrored) {
isolate->Throw(module->GetException());
return false;
}
if (!PrepareInstantiate(module, context, callback)) {
return false;
}
Zone zone(isolate->allocator(), ZONE_NAME);
ZoneForwardList<Handle<Module>> stack(&zone);
unsigned dfs_index = 0;
if (!FinishInstantiate(module, &stack, &dfs_index)) {
for (auto& descendant : stack) {
descendant->RecordError();
}
DCHECK_EQ(module->GetException(), isolate->pending_exception());
return false;
}
DCHECK(module->status() == kInstantiated || module->status() == kEvaluated);
DCHECK(stack.empty());
return true;
}
bool Module::PrepareInstantiate(Handle<Module> module,
v8::Local<v8::Context> context,
v8::Module::ResolveCallback callback) {
if (module->status() == kPrepared) return true;
DCHECK_NE(module->status(), kErrored);
DCHECK_NE(module->status(), kEvaluating);
DCHECK_NE(module->status(), kInstantiating);
if (module->status() >= kPreInstantiating) return true;
module->SetStatus(kPreInstantiating);
// Obtain requested modules.
Isolate* isolate = module->GetIsolate();
@ -19670,18 +19745,29 @@ bool Module::PrepareInstantiate(Handle<Module> module,
v8::Utils::ToLocal(module))
.ToLocal(&api_requested_module)) {
isolate->PromoteScheduledException();
module->RecordError();
return false;
}
Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
if (requested_module->status() == kErrored) {
// TODO(neis): Move this into callback?
isolate->Throw(requested_module->GetException());
module->RecordError();
DCHECK_EQ(module->GetException(), requested_module->GetException());
return false;
}
requested_modules->set(i, *requested_module);
}
// Recurse.
module->set_status(kPrepared);
for (int i = 0, length = requested_modules->length(); i < length; ++i) {
Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
isolate);
if (!PrepareInstantiate(requested_module, context, callback)) return false;
if (!PrepareInstantiate(requested_module, context, callback)) {
module->RecordError();
DCHECK_EQ(module->GetException(), requested_module->GetException());
return false;
}
}
// Set up local exports.
@ -19707,34 +19793,79 @@ bool Module::PrepareInstantiate(Handle<Module> module,
CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
}
DCHECK_EQ(module->status(), kPrepared);
DCHECK(!module->instantiated());
DCHECK_EQ(module->status(), kPreInstantiating);
return true;
}
bool Module::FinishInstantiate(Handle<Module> module,
v8::Local<v8::Context> context) {
DCHECK_EQ(module->status(), kPrepared);
if (module->instantiated()) return true;
void Module::MaybeTransitionComponent(Handle<Module> module,
ZoneForwardList<Handle<Module>>* stack,
Status new_status) {
DCHECK(new_status == kInstantiated || new_status == kEvaluated);
SLOW_DCHECK(
// {module} is on the {stack}.
std::count_if(stack->begin(), stack->end(),
[&](Handle<Module> m) { return *m == *module; }) == 1);
DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index());
if (module->dfs_ancestor_index() == module->dfs_index()) {
// This is the root of its strongly connected component.
Handle<Module> ancestor;
do {
ancestor = stack->front();
stack->pop_front();
DCHECK_EQ(ancestor->status(),
new_status == kInstantiated ? kInstantiating : kEvaluating);
ancestor->SetStatus(new_status);
} while (*ancestor != *module);
}
}
// Instantiate SharedFunctionInfo and mark module as instantiated for
bool Module::FinishInstantiate(Handle<Module> module,
ZoneForwardList<Handle<Module>>* stack,
unsigned* dfs_index) {
DCHECK_NE(module->status(), kErrored);
DCHECK_NE(module->status(), kEvaluating);
if (module->status() >= kInstantiating) return true;
DCHECK_EQ(module->status(), kPreInstantiating);
// Instantiate SharedFunctionInfo and mark module as instantiating for
// the recursion.
Isolate* isolate = module->GetIsolate();
Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
isolate);
Handle<JSFunction> function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared,
handle(Utils::OpenHandle(*context)->native_context(), isolate));
shared, isolate->native_context());
module->set_code(*function);
DCHECK(module->instantiated());
module->SetStatus(kInstantiating);
module->set_dfs_index(*dfs_index);
module->set_dfs_ancestor_index(*dfs_index);
stack->push_front(module);
(*dfs_index)++;
// Recurse.
Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
for (int i = 0, length = requested_modules->length(); i < length; ++i) {
Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
isolate);
if (!FinishInstantiate(requested_module, context)) return false;
if (!FinishInstantiate(requested_module, stack, dfs_index)) {
return false;
}
DCHECK_NE(requested_module->status(), kErrored);
DCHECK_NE(requested_module->status(), kEvaluating);
DCHECK_GE(requested_module->status(), kInstantiating);
SLOW_DCHECK(
// {requested_module} is instantiating iff it's on the {stack}.
(requested_module->status() == kInstantiating) ==
std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
return *m == *requested_module;
}));
if (requested_module->status() == kInstantiating) {
module->set_dfs_ancestor_index(
std::min(module->dfs_ancestor_index(),
requested_module->dfs_ancestor_index()));
}
}
Zone zone(isolate->allocator(), ZONE_NAME);
@ -19780,17 +19911,53 @@ bool Module::FinishInstantiate(Handle<Module> module,
}
}
MaybeTransitionComponent(module, stack, kInstantiated);
return true;
}
MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
DCHECK(module->instantiated());
// Each module can only be evaluated once.
Isolate* isolate = module->GetIsolate();
if (module->evaluated()) return isolate->factory()->undefined_value();
if (module->status() == kErrored) {
isolate->Throw(module->GetException());
return MaybeHandle<Object>();
}
DCHECK_NE(module->status(), kEvaluating);
DCHECK_GE(module->status(), kInstantiated);
Zone zone(isolate->allocator(), ZONE_NAME);
ZoneForwardList<Handle<Module>> stack(&zone);
unsigned dfs_index = 0;
Handle<Object> result;
if (!Evaluate(module, &stack, &dfs_index).ToHandle(&result)) {
for (auto& descendant : stack) {
DCHECK_EQ(descendant->status(), kEvaluating);
descendant->RecordError();
}
DCHECK_EQ(module->GetException(), isolate->pending_exception());
return MaybeHandle<Object>();
}
DCHECK_EQ(module->status(), kEvaluated);
DCHECK(stack.empty());
return result;
}
MaybeHandle<Object> Module::Evaluate(Handle<Module> module,
ZoneForwardList<Handle<Module>>* stack,
unsigned* dfs_index) {
Isolate* isolate = module->GetIsolate();
DCHECK_NE(module->status(), kErrored);
if (module->status() >= kEvaluating) {
return isolate->factory()->undefined_value();
}
DCHECK_EQ(module->status(), kInstantiated);
Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
module->set_evaluated();
module->set_code(function->shared()->scope_info()->ModuleDescriptorInfo());
module->SetStatus(kEvaluating);
module->set_dfs_index(*dfs_index);
module->set_dfs_ancestor_index(*dfs_index);
stack->push_front(module);
(*dfs_index)++;
// Initialization.
DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
@ -19805,8 +19972,25 @@ MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
// Recursion.
Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
for (int i = 0, length = requested_modules->length(); i < length; ++i) {
Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
isolate);
RETURN_ON_EXCEPTION(isolate, Evaluate(requested_module, stack, dfs_index),
Object);
DCHECK_GE(requested_module->status(), kEvaluating);
DCHECK_NE(requested_module->status(), kErrored);
SLOW_DCHECK(
// {requested_module} is evaluating iff it's on the {stack}.
(requested_module->status() == kEvaluating) ==
std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
return *m == *requested_module;
}));
if (requested_module->status() == kEvaluating) {
module->set_dfs_ancestor_index(
std::min(module->dfs_ancestor_index(),
requested_module->dfs_ancestor_index()));
}
}
// Evaluation of module body.
@ -19819,6 +20003,8 @@ MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
DCHECK(static_cast<JSIteratorResult*>(JSObject::cast(*result))
->done()
->BooleanValue());
MaybeTransitionComponent(module, stack, kEvaluated);
return handle(
static_cast<JSIteratorResult*>(JSObject::cast(*result))->value(),
isolate);
@ -19828,7 +20014,8 @@ namespace {
void FetchStarExports(Handle<Module> module, Zone* zone,
UnorderedModuleSet* visited) {
DCHECK(module->instantiated());
DCHECK_NE(module->status(), Module::kErrored);
DCHECK_GE(module->status(), Module::kInstantiated);
bool cycle = !visited->insert(module).second;
if (cycle) return;

View File

@ -959,6 +959,8 @@ class FeedbackVector;
class WeakCell;
class TransitionArray;
class TemplateList;
template <typename T>
class ZoneForwardList;
// A template-ized version of the IsXXX functions.
template <class C> inline bool Is(Object* obj);
@ -4852,9 +4854,21 @@ class Module : public Struct {
// Hash for this object (a random non-zero Smi).
DECL_INT_ACCESSORS(hash)
// Internal instantiation status.
// Status.
DECL_INT_ACCESSORS(status)
enum InstantiationStatus { kUnprepared, kPrepared };
enum Status {
// Order matters!
kUninstantiated,
kPreInstantiating,
kInstantiating,
kInstantiated,
kEvaluating,
kEvaluated,
kErrored
};
// The exception in the case {status} is kErrored.
Object* GetException();
// The namespace object (or undefined).
DECL_ACCESSORS(module_namespace, HeapObject)
@ -4870,9 +4884,6 @@ class Module : public Struct {
// Get the ModuleInfo associated with the code.
inline ModuleInfo* info() const;
inline bool instantiated() const;
inline bool evaluated() const;
// Implementation of spec operation ModuleDeclarationInstantiation.
// Returns false if an exception occurred during instantiation, true
// otherwise. (In the case where the callback throws an exception, that
@ -4907,10 +4918,23 @@ class Module : public Struct {
static const int kRequestedModulesOffset =
kModuleNamespaceOffset + kPointerSize;
static const int kStatusOffset = kRequestedModulesOffset + kPointerSize;
static const int kScriptOffset = kStatusOffset + kPointerSize;
static const int kDfsIndexOffset = kStatusOffset + kPointerSize;
static const int kDfsAncestorIndexOffset = kDfsIndexOffset + kPointerSize;
static const int kExceptionOffset = kDfsAncestorIndexOffset + kPointerSize;
static const int kScriptOffset = kExceptionOffset + kPointerSize;
static const int kSize = kScriptOffset + kPointerSize;
private:
friend class Factory;
DECL_ACCESSORS(exception, Object)
// TODO(neis): Don't store those in the module object?
DECL_INT_ACCESSORS(dfs_index)
DECL_INT_ACCESSORS(dfs_ancestor_index)
// Helpers for Instantiate and Evaluate.
static void CreateExport(Handle<Module> module, int cell_index,
Handle<FixedArray> names);
static void CreateIndirectExport(Handle<Module> module, Handle<String> name,
@ -4937,13 +4961,23 @@ class Module : public Struct {
Handle<Module> module, Handle<String> name, MessageLocation loc,
bool must_resolve, ResolveSet* resolve_set);
inline void set_evaluated();
static MUST_USE_RESULT bool PrepareInstantiate(
Handle<Module> module, v8::Local<v8::Context> context,
v8::Module::ResolveCallback callback);
static MUST_USE_RESULT bool FinishInstantiate(Handle<Module> module,
v8::Local<v8::Context> context);
static MUST_USE_RESULT bool FinishInstantiate(
Handle<Module> module, ZoneForwardList<Handle<Module>>* stack,
unsigned* dfs_index);
static MUST_USE_RESULT MaybeHandle<Object> Evaluate(
Handle<Module> module, ZoneForwardList<Handle<Module>>* stack,
unsigned* dfs_index);
static void MaybeTransitionComponent(Handle<Module> module,
ZoneForwardList<Handle<Module>>* stack,
Status new_status);
// To set status to kErrored, RecordError should be used.
void SetStatus(Status status);
void RecordError();
DISALLOW_IMPLICIT_CONSTRUCTORS(Module);
};

View File

@ -6,6 +6,7 @@
#define V8_SRC_ZONE_ZONE_CONTAINERS_H_
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <queue>
@ -44,7 +45,7 @@ class ZoneVector : public std::vector<T, ZoneAllocator<T>> {
: std::vector<T, ZoneAllocator<T>>(first, last, ZoneAllocator<T>(zone)) {}
};
// A wrapper subclass std::deque to make it easy to construct one
// A wrapper subclass for std::deque to make it easy to construct one
// that uses a zone allocator.
template <typename T>
class ZoneDeque : public std::deque<T, RecyclingZoneAllocator<T>> {
@ -55,7 +56,7 @@ class ZoneDeque : public std::deque<T, RecyclingZoneAllocator<T>> {
RecyclingZoneAllocator<T>(zone)) {}
};
// A wrapper subclass std::list to make it easy to construct one
// A wrapper subclass for std::list to make it easy to construct one
// that uses a zone allocator.
// TODO(mstarzinger): This should be renamed to ZoneList once we got rid of our
// own home-grown ZoneList that actually is a ZoneVector.
@ -67,7 +68,17 @@ class ZoneLinkedList : public std::list<T, ZoneAllocator<T>> {
: std::list<T, ZoneAllocator<T>>(ZoneAllocator<T>(zone)) {}
};
// A wrapper subclass std::priority_queue to make it easy to construct one
// A wrapper subclass for std::forward_list to make it easy to construct one
// that uses a zone allocator.
template <typename T>
class ZoneForwardList : public std::forward_list<T, ZoneAllocator<T>> {
public:
// Constructs an empty list.
explicit ZoneForwardList(Zone* zone)
: std::forward_list<T, ZoneAllocator<T>>(ZoneAllocator<T>(zone)) {}
};
// A wrapper subclass for std::priority_queue to make it easy to construct one
// that uses a zone allocator.
template <typename T, typename Compare = std::less<T>>
class ZonePriorityQueue

View File

@ -104,7 +104,6 @@ i::Handle<i::BytecodeArray>
BytecodeExpectationsPrinter::GetBytecodeArrayForModule(
v8::Local<v8::Module> module) const {
i::Handle<i::Module> i_module = v8::Utils::OpenHandle(*module);
CHECK(!i_module->instantiated());
return i::handle(SharedFunctionInfo::cast(i_module->code())->bytecode_array(),
i_isolate());
}

View File

@ -0,0 +1,13 @@
// Copyright 2017 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.
// Flags: --allow-natives-syntax --harmony-dynamic-import
var error1, error2;
import('modules-skip-12.js').catch(e => error1 = e);
import('modules-skip-12.js').catch(e => error2 = e);
%RunMicrotasks();
assertEquals(error1, error2);
assertInstanceof(error1, SyntaxError);

View File

@ -0,0 +1,13 @@
// Copyright 2017 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.
// Flags: --allow-natives-syntax --harmony-dynamic-import
var error1, error2;
import('modules-skip-11.js').catch(e => error1 = e);
import('modules-skip-11.js').catch(e => error2 = e);
%RunMicrotasks();
assertEquals(error1, error2);
assertEquals(typeof error1, "symbol");

View File

@ -0,0 +1,13 @@
// Copyright 2017 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.
// Flags: --allow-natives-syntax --harmony-dynamic-import
var error1, error2;
import('no-such-file').catch(e => error1 = e);
import('no-such-file').catch(e => error2 = e);
%RunMicrotasks();
assertEquals(error1, error2);
assertEquals(typeof error1, "string");

View File

@ -0,0 +1,13 @@
// Copyright 2017 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.
// Flags: --allow-natives-syntax --harmony-dynamic-import
var error1, error2;
import('modules-skip-10.js').catch(e => error1 = e);
import('modules-skip-10.js').catch(e => error2 = e);
%RunMicrotasks();
assertEquals(error1, error2);
assertInstanceof(error1, SyntaxError);

View File

@ -0,0 +1,5 @@
// Copyright 2017 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.
import {x} from "./modules-skip-10.js"

View File

@ -0,0 +1,5 @@
// Copyright 2017 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.
throw Symbol();

View File

@ -0,0 +1,5 @@
// Copyright 2017 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.
$^#$%@#@^^%^%$^#%%#!#$%!#$@#$%