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) {
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);
......
......@@ -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;
}
......
......@@ -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() {
......
......@@ -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();
......
......@@ -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";
}
......
This diff is collapsed.
......@@ -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);
};
......
......@@ -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
......
......@@ -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());
}
......
// 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