Commit d02cb6f0 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[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/544970Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46289}
parent e027a3ee
...@@ -2181,7 +2181,7 @@ MaybeLocal<Value> Module::Evaluate(Local<Context> context) { ...@@ -2181,7 +2181,7 @@ MaybeLocal<Value> Module::Evaluate(Local<Context> context) {
i::Handle<i::Module> self = Utils::OpenHandle(this); i::Handle<i::Module> self = Utils::OpenHandle(this);
// It's an API error to call Evaluate before Instantiate. // It's an API error to call Evaluate before Instantiate.
CHECK(self->instantiated()); CHECK_GE(self->status(), i::Module::kInstantiated);
Local<Value> result; Local<Value> result;
has_pending_exception = !ToLocal(i::Module::Evaluate(self), &result); has_pending_exception = !ToLocal(i::Module::Evaluate(self), &result);
......
...@@ -2019,9 +2019,10 @@ Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code) { ...@@ -2019,9 +2019,10 @@ Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code) {
module->set_module_namespace(isolate()->heap()->undefined_value()); module->set_module_namespace(isolate()->heap()->undefined_value());
module->set_requested_modules(*requested_modules); module->set_requested_modules(*requested_modules);
module->set_script(Script::cast(code->script())); module->set_script(Script::cast(code->script()));
module->set_status(Module::kUnprepared); module->set_status(Module::kUninstantiated);
DCHECK(!module->instantiated()); module->set_exception(isolate()->heap()->the_hole_value());
DCHECK(!module->evaluated()); module->set_dfs_index(-1);
module->set_dfs_ancestor_index(-1);
return module; return module;
} }
......
...@@ -1250,27 +1250,26 @@ void Module::ModuleVerify() { ...@@ -1250,27 +1250,26 @@ void Module::ModuleVerify() {
VerifyPointer(module_namespace()); VerifyPointer(module_namespace());
VerifyPointer(requested_modules()); VerifyPointer(requested_modules());
VerifyPointer(script()); VerifyPointer(script());
VerifyPointer(exception());
VerifySmiField(kHashOffset); VerifySmiField(kHashOffset);
VerifySmiField(kStatusOffset); VerifySmiField(kStatusOffset);
CHECK((!instantiated() && code()->IsSharedFunctionInfo()) || CHECK((status() < kInstantiating && code()->IsSharedFunctionInfo()) ||
(instantiated() && !evaluated() && code()->IsJSFunction()) || (status() < kEvaluating && code()->IsJSFunction()) ||
(instantiated() && evaluated() && code()->IsModuleInfo())); code()->IsModuleInfo());
CHECK_EQ(status() == kErrored, !exception()->IsTheHole(GetIsolate()));
CHECK(module_namespace()->IsUndefined(GetIsolate()) || CHECK(module_namespace()->IsUndefined(GetIsolate()) ||
module_namespace()->IsJSModuleNamespace()); module_namespace()->IsJSModuleNamespace());
if (module_namespace()->IsJSModuleNamespace()) { if (module_namespace()->IsJSModuleNamespace()) {
CHECK(instantiated()); CHECK_LE(kInstantiating, status());
CHECK_EQ(JSModuleNamespace::cast(module_namespace())->module(), this); CHECK_EQ(JSModuleNamespace::cast(module_namespace())->module(), this);
} }
CHECK_EQ(requested_modules()->length(), info()->module_requests()->length()); CHECK_EQ(requested_modules()->length(), info()->module_requests()->length());
CHECK_NE(hash(), 0); CHECK_NE(hash(), 0);
CHECK_LE(kUnprepared, status());
CHECK_LE(status(), kPrepared);
CHECK_IMPLIES(instantiated(), status() == kPrepared);
} }
void PrototypeInfo::PrototypeInfoVerify() { void PrototypeInfo::PrototypeInfoVerify() {
......
...@@ -4621,23 +4621,17 @@ ACCESSORS(Module, regular_imports, FixedArray, kRegularImportsOffset) ...@@ -4621,23 +4621,17 @@ ACCESSORS(Module, regular_imports, FixedArray, kRegularImportsOffset)
ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset) ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset)
ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset) ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset)
ACCESSORS(Module, script, Script, kScriptOffset) ACCESSORS(Module, script, Script, kScriptOffset)
ACCESSORS(Module, exception, Object, kExceptionOffset)
SMI_ACCESSORS(Module, status, kStatusOffset) SMI_ACCESSORS(Module, status, kStatusOffset)
SMI_ACCESSORS(Module, dfs_index, kDfsIndexOffset)
SMI_ACCESSORS(Module, dfs_ancestor_index, kDfsAncestorIndexOffset)
SMI_ACCESSORS(Module, hash, kHashOffset) 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 { ModuleInfo* Module::info() const {
if (evaluated()) return ModuleInfo::cast(code()); if (status() >= kEvaluating) {
ScopeInfo* scope_info = instantiated() return ModuleInfo::cast(code());
}
ScopeInfo* scope_info = status() >= kInstantiating
? JSFunction::cast(code())->shared()->scope_info() ? JSFunction::cast(code())->shared()->scope_info()
: SharedFunctionInfo::cast(code())->scope_info(); : SharedFunctionInfo::cast(code())->scope_info();
return scope_info->ModuleDescriptorInfo(); return scope_info->ModuleDescriptorInfo();
......
...@@ -1299,7 +1299,7 @@ void ModuleInfoEntry::ModuleInfoEntryPrint(std::ostream& os) { // NOLINT ...@@ -1299,7 +1299,7 @@ void ModuleInfoEntry::ModuleInfoEntryPrint(std::ostream& os) { // NOLINT
void Module::ModulePrint(std::ostream& os) { // NOLINT void Module::ModulePrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Module"); HeapObject::PrintHeader(os, "Module");
// TODO(neis): Simplify once modules have a script field. // TODO(neis): Simplify once modules have a script field.
if (!evaluated()) { if (status() < kEvaluating) {
SharedFunctionInfo* shared = code()->IsSharedFunctionInfo() SharedFunctionInfo* shared = code()->IsSharedFunctionInfo()
? SharedFunctionInfo::cast(code()) ? SharedFunctionInfo::cast(code())
: JSFunction::cast(code())->shared(); : JSFunction::cast(code())->shared();
...@@ -1310,8 +1310,8 @@ void Module::ModulePrint(std::ostream& os) { // NOLINT ...@@ -1310,8 +1310,8 @@ void Module::ModulePrint(std::ostream& os) { // NOLINT
os << "\n - exports: " << Brief(exports()); os << "\n - exports: " << Brief(exports());
os << "\n - requested_modules: " << Brief(requested_modules()); os << "\n - requested_modules: " << Brief(requested_modules());
os << "\n - script: " << Brief(script()); os << "\n - script: " << Brief(script());
os << "\n - instantiated, evaluated: " << instantiated() << ", " os << "\n - status: " << status();
<< evaluated(); os << "\n - exception: " << Brief(exception());
os << "\n"; os << "\n";
} }
......
This diff is collapsed.
...@@ -959,6 +959,8 @@ class FeedbackVector; ...@@ -959,6 +959,8 @@ class FeedbackVector;
class WeakCell; class WeakCell;
class TransitionArray; class TransitionArray;
class TemplateList; class TemplateList;
template <typename T>
class ZoneForwardList;
// A template-ized version of the IsXXX functions. // A template-ized version of the IsXXX functions.
template <class C> inline bool Is(Object* obj); template <class C> inline bool Is(Object* obj);
...@@ -4852,9 +4854,21 @@ class Module : public Struct { ...@@ -4852,9 +4854,21 @@ class Module : public Struct {
// Hash for this object (a random non-zero Smi). // Hash for this object (a random non-zero Smi).
DECL_INT_ACCESSORS(hash) DECL_INT_ACCESSORS(hash)
// Internal instantiation status. // Status.
DECL_INT_ACCESSORS(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). // The namespace object (or undefined).
DECL_ACCESSORS(module_namespace, HeapObject) DECL_ACCESSORS(module_namespace, HeapObject)
...@@ -4870,9 +4884,6 @@ class Module : public Struct { ...@@ -4870,9 +4884,6 @@ class Module : public Struct {
// Get the ModuleInfo associated with the code. // Get the ModuleInfo associated with the code.
inline ModuleInfo* info() const; inline ModuleInfo* info() const;
inline bool instantiated() const;
inline bool evaluated() const;
// Implementation of spec operation ModuleDeclarationInstantiation. // Implementation of spec operation ModuleDeclarationInstantiation.
// Returns false if an exception occurred during instantiation, true // Returns false if an exception occurred during instantiation, true
// otherwise. (In the case where the callback throws an exception, that // otherwise. (In the case where the callback throws an exception, that
...@@ -4907,10 +4918,23 @@ class Module : public Struct { ...@@ -4907,10 +4918,23 @@ class Module : public Struct {
static const int kRequestedModulesOffset = static const int kRequestedModulesOffset =
kModuleNamespaceOffset + kPointerSize; kModuleNamespaceOffset + kPointerSize;
static const int kStatusOffset = kRequestedModulesOffset + 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; static const int kSize = kScriptOffset + kPointerSize;
private: 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, static void CreateExport(Handle<Module> module, int cell_index,
Handle<FixedArray> names); Handle<FixedArray> names);
static void CreateIndirectExport(Handle<Module> module, Handle<String> name, static void CreateIndirectExport(Handle<Module> module, Handle<String> name,
...@@ -4937,13 +4961,23 @@ class Module : public Struct { ...@@ -4937,13 +4961,23 @@ class Module : public Struct {
Handle<Module> module, Handle<String> name, MessageLocation loc, Handle<Module> module, Handle<String> name, MessageLocation loc,
bool must_resolve, ResolveSet* resolve_set); bool must_resolve, ResolveSet* resolve_set);
inline void set_evaluated();
static MUST_USE_RESULT bool PrepareInstantiate( static MUST_USE_RESULT bool PrepareInstantiate(
Handle<Module> module, v8::Local<v8::Context> context, Handle<Module> module, v8::Local<v8::Context> context,
v8::Module::ResolveCallback callback); v8::Module::ResolveCallback callback);
static MUST_USE_RESULT bool FinishInstantiate(Handle<Module> module, static MUST_USE_RESULT bool FinishInstantiate(
v8::Local<v8::Context> context); 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); DISALLOW_IMPLICIT_CONSTRUCTORS(Module);
}; };
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define V8_SRC_ZONE_ZONE_CONTAINERS_H_ #define V8_SRC_ZONE_ZONE_CONTAINERS_H_
#include <deque> #include <deque>
#include <forward_list>
#include <list> #include <list>
#include <map> #include <map>
#include <queue> #include <queue>
...@@ -44,7 +45,7 @@ class ZoneVector : public std::vector<T, ZoneAllocator<T>> { ...@@ -44,7 +45,7 @@ class ZoneVector : public std::vector<T, ZoneAllocator<T>> {
: std::vector<T, ZoneAllocator<T>>(first, last, ZoneAllocator<T>(zone)) {} : 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. // that uses a zone allocator.
template <typename T> template <typename T>
class ZoneDeque : public std::deque<T, RecyclingZoneAllocator<T>> { class ZoneDeque : public std::deque<T, RecyclingZoneAllocator<T>> {
...@@ -55,7 +56,7 @@ class ZoneDeque : public std::deque<T, RecyclingZoneAllocator<T>> { ...@@ -55,7 +56,7 @@ class ZoneDeque : public std::deque<T, RecyclingZoneAllocator<T>> {
RecyclingZoneAllocator<T>(zone)) {} 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. // that uses a zone allocator.
// TODO(mstarzinger): This should be renamed to ZoneList once we got rid of our // TODO(mstarzinger): This should be renamed to ZoneList once we got rid of our
// own home-grown ZoneList that actually is a ZoneVector. // own home-grown ZoneList that actually is a ZoneVector.
...@@ -67,7 +68,17 @@ class ZoneLinkedList : public std::list<T, ZoneAllocator<T>> { ...@@ -67,7 +68,17 @@ class ZoneLinkedList : public std::list<T, ZoneAllocator<T>> {
: std::list<T, ZoneAllocator<T>>(ZoneAllocator<T>(zone)) {} : 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. // that uses a zone allocator.
template <typename T, typename Compare = std::less<T>> template <typename T, typename Compare = std::less<T>>
class ZonePriorityQueue class ZonePriorityQueue
......
...@@ -104,7 +104,6 @@ i::Handle<i::BytecodeArray> ...@@ -104,7 +104,6 @@ i::Handle<i::BytecodeArray>
BytecodeExpectationsPrinter::GetBytecodeArrayForModule( BytecodeExpectationsPrinter::GetBytecodeArrayForModule(
v8::Local<v8::Module> module) const { v8::Local<v8::Module> module) const {
i::Handle<i::Module> i_module = v8::Utils::OpenHandle(*module); i::Handle<i::Module> i_module = v8::Utils::OpenHandle(*module);
CHECK(!i_module->instantiated());
return i::handle(SharedFunctionInfo::cast(i_module->code())->bytecode_array(), return i::handle(SharedFunctionInfo::cast(i_module->code())->bytecode_array(),
i_isolate()); i_isolate());
} }
......
// 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);
// 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");
// 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");
// 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);
// 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"
// 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();
// 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.
$^#$%@#@^^%^%$^#%%#!#$%!#$@#$%
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment