[modules] Implement namespace imports.

This implements namespace imports (import * as foo from "bar"), except for the
@@iterator property on namespace objects (to be done later).

R=adamk@chromium.org
BUG=v8:1569

Review-Url: https://codereview.chromium.org/2388153003
Cr-Commit-Position: refs/heads/master@{#40096}
This commit is contained in:
neis 2016-10-07 12:37:04 -07:00 committed by Commit bot
parent 707934cf9e
commit 57ba0ae10e
25 changed files with 554 additions and 14 deletions

View File

@ -202,6 +202,68 @@ Handle<AccessorInfo> Accessors::ArrayLengthInfo(
attributes);
}
//
// Accessors::ModuleNamespaceToStringTag
//
void Accessors::ModuleNamespaceToStringTagGetter(
v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
info.GetReturnValue().Set(
Utils::ToLocal(isolate->factory()->NewStringFromAsciiChecked("Module")));
}
Handle<AccessorInfo> Accessors::ModuleNamespaceToStringTagInfo(
Isolate* isolate, PropertyAttributes attributes) {
Handle<Name> name = isolate->factory()->to_string_tag_symbol();
return MakeAccessor(isolate, name, &ModuleNamespaceToStringTagGetter, nullptr,
attributes);
}
//
// Accessors::ModuleNamespaceEntry
//
void Accessors::ModuleNamespaceEntryGetter(
v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
JSModuleNamespace* holder =
JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
Handle<Object> result;
if (!holder->GetExport(Handle<String>::cast(Utils::OpenHandle(*name)))
.ToHandle(&result)) {
isolate->OptionalRescheduleException(false);
} else {
info.GetReturnValue().Set(Utils::ToLocal(result));
}
}
void Accessors::ModuleNamespaceEntrySetter(
v8::Local<v8::Name> name, v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
Factory* factory = isolate->factory();
Handle<JSModuleNamespace> holder =
Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder()));
if (info.ShouldThrowOnError()) {
isolate->Throw(*factory->NewTypeError(
MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
i::Object::TypeOf(isolate, holder), holder));
isolate->OptionalRescheduleException(false);
} else {
info.GetReturnValue().Set(Utils::ToLocal(factory->ToBoolean(false)));
}
}
Handle<AccessorInfo> Accessors::ModuleNamespaceEntryInfo(
Isolate* isolate, Handle<String> name, PropertyAttributes attributes) {
return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
&ModuleNamespaceEntrySetter, attributes);
}
//
// Accessors::StringLength

View File

@ -30,6 +30,7 @@ class AccessorInfo;
V(FunctionName) \
V(FunctionLength) \
V(FunctionPrototype) \
V(ModuleNamespaceToStringTag) \
V(ScriptColumnOffset) \
V(ScriptCompilationType) \
V(ScriptContextData) \
@ -48,10 +49,11 @@ class AccessorInfo;
V(StringLength)
#define ACCESSOR_SETTER_LIST(V) \
V(ReconfigureToDataProperty) \
V(ArrayLengthSetter) \
V(ErrorStackSetter) \
V(FunctionPrototypeSetter)
V(FunctionPrototypeSetter) \
V(ModuleNamespaceEntrySetter) \
V(ReconfigureToDataProperty)
// Accessors contains all predefined proxy accessors.
@ -74,6 +76,12 @@ class Accessors : public AllStatic {
ACCESSOR_SETTER_LIST(ACCESSOR_SETTER_DECLARATION)
#undef ACCESSOR_SETTER_DECLARATION
static void ModuleNamespaceEntryGetter(
v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info);
static Handle<AccessorInfo> ModuleNamespaceEntryInfo(
Isolate* isolate, Handle<String> name, PropertyAttributes attributes);
enum DescriptorId {
#define ACCESSOR_INFO_DECLARATION(name) \
k##name##Getter, \

View File

@ -208,6 +208,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) {
case JS_DATE_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_MODULE_NAMESPACE_TYPE:
case JS_ARRAY_BUFFER_TYPE:
case JS_ARRAY_TYPE:
case JS_REGEXP_TYPE: // TODO(rossberg): there should be a RegExp type.

View File

@ -2102,6 +2102,25 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Context::JS_SET_FUN_INDEX);
}
{ // -- J S M o d u l e N a m e s p a c e
Handle<Map> map =
factory->NewMap(JS_MODULE_NAMESPACE_TYPE, JSModuleNamespace::kSize);
Map::SetPrototype(map, isolate->factory()->null_value());
native_context()->set_js_module_namespace_map(*map);
// Install @@toStringTag.
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
Handle<AccessorInfo> toStringTag =
Accessors::ModuleNamespaceToStringTagInfo(isolate, attribs);
AccessorConstantDescriptor d(factory->to_string_tag_symbol(), toStringTag,
attribs);
Map::EnsureDescriptorSlack(map, 1);
map->AppendDescriptor(&d);
// TODO(neis): Implement and install @@iterator.
}
{ // -- I t e r a t o r R e s u l t
Handle<Map> map =
factory->NewMap(JS_OBJECT_TYPE, JSIteratorResult::kSize);

View File

@ -203,6 +203,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case JS_DATE_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_MODULE_NAMESPACE_TYPE:
case JS_ARRAY_BUFFER_TYPE:
case JS_ARRAY_TYPE:
case JS_REGEXP_TYPE: // TODO(rossberg): there should be a RegExp type.

View File

@ -177,6 +177,7 @@ enum ContextLookupFlags {
js_array_fast_holey_double_elements_map_index) \
V(JS_MAP_FUN_INDEX, JSFunction, js_map_fun) \
V(JS_MAP_MAP_INDEX, Map, js_map_map) \
V(JS_MODULE_NAMESPACE_MAP, Map, js_module_namespace_map) \
V(JS_SET_FUN_INDEX, JSFunction, js_set_fun) \
V(JS_SET_MAP_INDEX, Map, js_set_map) \
V(JS_WEAK_MAP_FUN_INDEX, JSFunction, js_weak_map_fun) \

View File

@ -1735,6 +1735,10 @@ void Factory::NewJSArrayStorage(Handle<JSArray> array,
array->set_length(Smi::FromInt(length));
}
Handle<JSModuleNamespace> Factory::NewJSModuleNamespace() {
Handle<Map> map = isolate()->js_module_namespace_map();
return Handle<JSModuleNamespace>::cast(NewJSObjectFromMap(map));
}
Handle<JSGeneratorObject> Factory::NewJSGeneratorObject(
Handle<JSFunction> function) {
@ -1765,10 +1769,11 @@ Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code) {
Handle<Module> module = Handle<Module>::cast(NewStruct(MODULE_TYPE));
module->set_code(*code);
module->set_exports(*exports);
module->set_requested_modules(*requested_modules);
module->set_flags(0);
module->set_embedder_data(isolate()->heap()->undefined_value());
module->set_exports(*exports);
module->set_flags(0);
module->set_module_namespace(isolate()->heap()->undefined_value());
module->set_requested_modules(*requested_modules);
return module;
}

View File

@ -486,6 +486,8 @@ class Factory final {
Handle<JSGeneratorObject> NewJSGeneratorObject(Handle<JSFunction> function);
Handle<JSModuleNamespace> NewJSModuleNamespace();
Handle<Module> NewModule(Handle<SharedFunctionInfo> code);
Handle<JSArrayBuffer> NewJSArrayBuffer(

View File

@ -107,6 +107,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_ARGUMENTS_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_MODULE_NAMESPACE_TYPE:
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:

View File

@ -678,6 +678,9 @@ void BytecodeGenerator::GenerateBytecodeBody() {
// Visit declarations within the function scope.
VisitDeclarations(scope()->declarations());
// Emit initializing assignments for module namespace imports (if any).
VisitModuleNamespaceImports();
// Perform a stack-check before the body.
builder()->StackCheck(info()->literal()->start_position());
@ -877,6 +880,24 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
}
}
void BytecodeGenerator::VisitModuleNamespaceImports() {
if (!scope()->is_module_scope()) return;
RegisterAllocationScope register_scope(this);
Register module_request = register_allocator()->NewRegister();
ModuleDescriptor* descriptor = scope()->AsModuleScope()->module();
for (auto entry : descriptor->namespace_imports()) {
builder()
->LoadLiteral(Smi::FromInt(entry->module_request))
.StoreAccumulatorInRegister(module_request)
.CallRuntime(Runtime::kGetModuleNamespace, module_request);
Variable* var = scope()->LookupLocal(entry->local_name);
DCHECK_NOT_NULL(var);
VisitVariableAssignment(var, Token::INIT, FeedbackVectorSlot::Invalid());
}
}
void BytecodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
RegisterAllocationScope register_scope(this);

View File

@ -143,6 +143,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
ObjectLiteralProperty* property,
Register value_out);
void VisitForInAssignment(Expression* expr, FeedbackVectorSlot slot);
void VisitModuleNamespaceImports();
// Visit the header/body of a loop iteration.
void VisitIterationHeader(IterationStatement* stmt,

View File

@ -468,6 +468,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) {
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
case JS_MODULE_NAMESPACE_TYPE:
case JS_TYPED_ARRAY_TYPE:
case JS_DATA_VIEW_TYPE:
case JS_SET_TYPE:

View File

@ -140,6 +140,9 @@ void HeapObject::HeapObjectVerify() {
case JS_ARRAY_TYPE:
JSArray::cast(this)->JSArrayVerify();
break;
case JS_MODULE_NAMESPACE_TYPE:
JSModuleNamespace::cast(this)->JSModuleNamespaceVerify();
break;
case JS_SET_TYPE:
JSSet::cast(this)->JSSetVerify();
break;
@ -919,7 +922,13 @@ void PromiseContainer::PromiseContainerVerify() {
after_debug_event()->ObjectVerify();
}
void JSModuleNamespace::JSModuleNamespaceVerify() {
CHECK(IsJSModuleNamespace());
module()->ObjectVerify();
}
void Module::ModuleVerify() {
Isolate* isolate = GetIsolate();
CHECK(IsModule());
CHECK(code()->IsSharedFunctionInfo() || code()->IsJSFunction());
code()->ObjectVerify();
@ -928,6 +937,8 @@ void Module::ModuleVerify() {
VerifySmiField(kFlagsOffset);
embedder_data()->ObjectVerify();
CHECK(shared()->name()->IsSymbol());
CHECK(module_namespace()->IsUndefined(isolate) ||
module_namespace()->IsJSModuleNamespace());
// TODO(neis): Check more.
}

View File

@ -3277,6 +3277,7 @@ CAST_ACCESSOR(JSGlobalProxy)
CAST_ACCESSOR(JSMap)
CAST_ACCESSOR(JSMapIterator)
CAST_ACCESSOR(JSMessageObject)
CAST_ACCESSOR(JSModuleNamespace)
CAST_ACCESSOR(JSObject)
CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(JSReceiver)
@ -5706,8 +5707,11 @@ BOOL_ACCESSORS(PrototypeInfo, bit_field, should_be_fast_map, kShouldBeFastBit)
ACCESSORS(ContextExtension, scope_info, ScopeInfo, kScopeInfoOffset)
ACCESSORS(ContextExtension, extension, Object, kExtensionOffset)
ACCESSORS(JSModuleNamespace, module, Module, kModuleOffset)
ACCESSORS(Module, code, Object, kCodeOffset)
ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset)
ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset)
ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset)
SMI_ACCESSORS(Module, flags, kFlagsOffset)
BOOL_ACCESSORS(Module, flags, evaluated, kEvaluatedBit)
@ -6664,6 +6668,8 @@ bool JSGeneratorObject::is_executing() const {
return continuation() == kGeneratorExecuting;
}
TYPE_CHECKER(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE)
ACCESSORS(JSValue, value, Object, kValueOffset)

View File

@ -6556,7 +6556,7 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
key, desc, should_throw);
}
// TODO(jkummerow): Support Modules (ES6 9.4.6.6)
// TODO(neis): Special case for JSModuleNamespace?
// OrdinaryDefineOwnProperty, by virtue of calling
// DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
@ -18218,6 +18218,9 @@ Object* ObjectHashTable::Lookup(Handle<Object> key) {
return Lookup(isolate, key, Smi::cast(hash)->value());
}
Object* ObjectHashTable::ValueAt(int entry) {
return get(EntryToValueIndex(entry));
}
Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
return Lookup(GetIsolate(), key, hash);
@ -19565,6 +19568,23 @@ bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
return false;
}
MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
Isolate* isolate = name->GetIsolate();
Handle<Object> object(module()->exports()->Lookup(name), isolate);
if (object->IsTheHole(isolate)) {
return isolate->factory()->undefined_value();
}
Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
if (value->IsTheHole(isolate)) {
THROW_NEW_ERROR(
isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
}
return value;
}
namespace {
template <typename T>
@ -19596,6 +19616,35 @@ class UnorderedStringSet
StringHandleEqual(), zone_allocator<Handle<String>>(zone)) {}
};
class UnorderedModuleSet
: public std::unordered_set<Handle<Module>, HandleValueHash<Module>,
ModuleHandleEqual,
zone_allocator<Handle<Module>>> {
public:
explicit UnorderedModuleSet(Zone* zone)
: std::unordered_set<Handle<Module>, HandleValueHash<Module>,
ModuleHandleEqual, zone_allocator<Handle<Module>>>(
2 /* bucket count */, HandleValueHash<Module>(),
ModuleHandleEqual(), zone_allocator<Handle<Module>>(zone)) {}
};
class UnorderedStringMap
: public std::unordered_map<
Handle<String>, Handle<Object>, HandleValueHash<String>,
StringHandleEqual,
zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> {
public:
explicit UnorderedStringMap(Zone* zone)
: std::unordered_map<
Handle<String>, Handle<Object>, HandleValueHash<String>,
StringHandleEqual,
zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>(
2 /* bucket count */, HandleValueHash<String>(),
StringHandleEqual(),
zone_allocator<std::pair<const Handle<String>, Handle<Object>>>(
zone)) {}
};
} // anonymous namespace
class Module::ResolveSet
@ -19919,5 +19968,138 @@ MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
return Execution::Call(isolate, resume, generator, 0, nullptr);
}
namespace {
void FetchStarExports(Handle<Module> module, Zone* zone,
UnorderedModuleSet* visited) {
DCHECK(module->code()->IsJSFunction()); // Instantiated.
bool cycle = !visited->insert(module).second;
if (cycle) return;
Isolate* isolate = module->GetIsolate();
Handle<ObjectHashTable> exports(module->exports(), isolate);
UnorderedStringMap more_exports(zone);
// TODO(neis): Only allocate more_exports if there are star exports.
// Maybe split special_exports into indirect_exports and star_exports.
Handle<FixedArray> special_exports(module->info()->special_exports(),
isolate);
for (int i = 0, n = special_exports->length(); i < n; ++i) {
Handle<ModuleInfoEntry> entry(
ModuleInfoEntry::cast(special_exports->get(i)), isolate);
if (!entry->export_name()->IsUndefined(isolate)) {
continue; // Indirect export.
}
int module_request = Smi::cast(entry->module_request())->value();
Handle<Module> requested_module(
Module::cast(module->requested_modules()->get(module_request)),
isolate);
// Recurse.
FetchStarExports(requested_module, zone, visited);
// Collect all of [requested_module]'s exports that must be added to
// [module]'s exports (i.e. to [exports]). We record these in
// [more_exports]. Ambiguities (conflicting exports) are marked by mapping
// the name to undefined instead of a Cell.
Handle<ObjectHashTable> requested_exports(requested_module->exports(),
isolate);
for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
Handle<Object> key(requested_exports->KeyAt(i), isolate);
if (!requested_exports->IsKey(isolate, *key)) continue;
Handle<String> name = Handle<String>::cast(key);
if (name->Equals(isolate->heap()->default_string())) continue;
if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
auto insert_result = more_exports.insert(std::make_pair(name, cell));
if (!insert_result.second) {
auto it = insert_result.first;
if (*it->second == *cell || it->second->IsUndefined(isolate)) {
// We already recorded this mapping before, or the name is already
// known to be ambiguous. In either case, there's nothing to do.
} else {
DCHECK(it->second->IsCell());
// Different star exports provide different cells for this name, hence
// mark the name as ambiguous.
it->second = isolate->factory()->undefined_value();
}
}
}
}
// Copy [more_exports] into [exports].
for (const auto& elem : more_exports) {
if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
DCHECK(elem.second->IsCell());
exports = ObjectHashTable::Put(exports, elem.first, elem.second);
}
module->set_exports(*exports);
}
} // anonymous namespace
Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
int module_request) {
Isolate* isolate = module->GetIsolate();
Handle<Module> requested_module(
Module::cast(module->requested_modules()->get(module_request)), isolate);
return Module::GetModuleNamespace(requested_module);
}
Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
Isolate* isolate = module->GetIsolate();
Handle<HeapObject> object(module->module_namespace(), isolate);
if (!object->IsUndefined(isolate)) {
// Namespace object already exists.
return Handle<JSModuleNamespace>::cast(object);
}
// Create the namespace object (initially empty).
Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
ns->set_module(*module);
module->set_module_namespace(*ns);
// Collect the export names.
Zone zone(isolate->allocator());
UnorderedModuleSet visited(&zone);
FetchStarExports(module, &zone, &visited);
Handle<ObjectHashTable> exports(module->exports(), isolate);
ZoneVector<Handle<String>> names(&zone);
names.reserve(exports->NumberOfElements());
for (int i = 0, n = exports->Capacity(); i < n; ++i) {
Handle<Object> key(exports->KeyAt(i), isolate);
if (!exports->IsKey(isolate, *key)) continue;
DCHECK(exports->ValueAt(i)->IsCell());
names.push_back(Handle<String>::cast(key));
}
DCHECK_EQ(names.size(), exports->NumberOfElements());
// Sort them alphabetically.
struct {
bool operator()(Handle<String> a, Handle<String> b) {
return String::Compare(a, b) == ComparisonResult::kLessThan;
}
} StringLess;
std::sort(names.begin(), names.end(), StringLess);
// Create the corresponding properties in the namespace object.
PropertyAttributes attr = DONT_DELETE;
for (const auto& name : names) {
JSObject::SetAccessor(
ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
.Check();
}
JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
return ns;
}
} // namespace internal
} // namespace v8

View File

@ -71,6 +71,7 @@
// - JSValue
// - JSDate
// - JSMessageObject
// - JSModuleNamespace
// - JSProxy
// - FixedArrayBase
// - ByteArray
@ -416,6 +417,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(JS_ARGUMENTS_TYPE) \
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
V(JS_GENERATOR_OBJECT_TYPE) \
V(JS_MODULE_NAMESPACE_TYPE) \
V(JS_GLOBAL_OBJECT_TYPE) \
V(JS_GLOBAL_PROXY_TYPE) \
V(JS_API_OBJECT_TYPE) \
@ -717,6 +719,7 @@ enum InstanceType {
JS_ARGUMENTS_TYPE,
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
JS_GENERATOR_OBJECT_TYPE,
JS_MODULE_NAMESPACE_TYPE,
JS_ARRAY_TYPE,
JS_ARRAY_BUFFER_TYPE,
JS_TYPED_ARRAY_TYPE,
@ -886,6 +889,7 @@ class LayoutDescriptor;
class LiteralsArray;
class LookupIterator;
class FieldType;
class Module;
class ModuleDescriptor;
class ModuleInfoEntry;
class ModuleInfo;
@ -970,6 +974,7 @@ template <class C> inline bool Is(Object* obj);
V(JSObject) \
V(JSContextExtensionObject) \
V(JSGeneratorObject) \
V(JSModuleNamespace) \
V(Map) \
V(DescriptorArray) \
V(FrameArray) \
@ -3951,6 +3956,9 @@ class ObjectHashTable: public HashTable<ObjectHashTable,
Object* Lookup(Handle<Object> key, int32_t hash);
Object* Lookup(Isolate* isolate, Handle<Object> key, int32_t hash);
// Returns the value at entry.
Object* ValueAt(int entry);
// Adds (or overwrites) the value associated with the given key.
static Handle<ObjectHashTable> Put(Handle<ObjectHashTable> table,
Handle<Object> key,
@ -7863,6 +7871,29 @@ class JSGeneratorObject: public JSObject {
DISALLOW_IMPLICIT_CONSTRUCTORS(JSGeneratorObject);
};
// When importing a module namespace (import * as foo from "bar"), a
// JSModuleNamespace object (representing module "bar") is created and bound to
// the declared variable (foo). A module can have at most one namespace object.
class JSModuleNamespace : public JSObject {
public:
DECLARE_CAST(JSModuleNamespace)
DECLARE_VERIFIER(JSModuleNamespace)
// The actual module whose namespace is being represented.
DECL_ACCESSORS(module, Module)
// Retrieve the value exported by [module] under the given [name]. If there is
// no such export, return Just(undefined). If the export is uninitialized,
// schedule an exception and return Nothing.
MUST_USE_RESULT MaybeHandle<Object> GetExport(Handle<String> name);
static const int kModuleOffset = JSObject::kHeaderSize;
static const int kSize = kModuleOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSModuleNamespace);
};
// A Module object is a mapping from export names to cells
// This is still very much in flux.
class Module : public Struct {
@ -7871,13 +7902,15 @@ class Module : public Struct {
DECLARE_VERIFIER(Module)
DECLARE_PRINTER(Module)
// The code representing this Module, either a
// SharedFunctionInfo or a JSFunction depending
// on whether it's been instantiated.
// The code representing this Module, either a SharedFunctionInfo or a
// JSFunction depending on whether it's been instantiated.
DECL_ACCESSORS(code, Object)
DECL_ACCESSORS(exports, ObjectHashTable)
// The namespace object (or undefined).
DECL_ACCESSORS(module_namespace, HeapObject)
// [[RequestedModules]]: Modules imported or re-exported by this module.
// Corresponds 1-to-1 to the module specifier strings in
// ModuleInfo::module_requests.
@ -7887,7 +7920,7 @@ class Module : public Struct {
// are only evaluated a single time.
DECL_BOOLEAN_ACCESSORS(evaluated)
// Storage for [[Evaluated]]
// Storage for [[Evaluated]].
DECL_INT_ACCESSORS(flags)
// Embedder-specified data
@ -7920,12 +7953,18 @@ class Module : public Struct {
static Handle<Object> LoadImport(Handle<Module> module, Handle<String> name,
int module_request);
// Get the namespace object for [module_request] of [module]. If it doesn't
// exist yet, it is created.
static Handle<JSModuleNamespace> GetModuleNamespace(Handle<Module> module,
int module_request);
static const int kCodeOffset = HeapObject::kHeaderSize;
static const int kExportsOffset = kCodeOffset + kPointerSize;
static const int kRequestedModulesOffset = kExportsOffset + kPointerSize;
static const int kFlagsOffset = kRequestedModulesOffset + kPointerSize;
static const int kEmbedderDataOffset = kFlagsOffset + kPointerSize;
static const int kSize = kEmbedderDataOffset + kPointerSize;
static const int kModuleNamespaceOffset = kEmbedderDataOffset + kPointerSize;
static const int kSize = kModuleNamespaceOffset + kPointerSize;
private:
enum { kEvaluatedBit };
@ -7934,6 +7973,10 @@ class Module : public Struct {
static void CreateIndirectExport(Handle<Module> module, Handle<String> name,
Handle<ModuleInfoEntry> entry);
// Get the namespace object for [module]. If it doesn't exist yet, it is
// created.
static Handle<JSModuleNamespace> GetModuleNamespace(Handle<Module> module);
// The [must_resolve] argument indicates whether or not an exception should be
// thrown in case the module does not provide an export named [name]
// (including when a cycle is detected). An exception is always thrown in the

View File

@ -960,6 +960,14 @@ RUNTIME_FUNCTION(Runtime_CreateDataProperty) {
return *value;
}
RUNTIME_FUNCTION(Runtime_GetModuleNamespace) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_SMI_ARG_CHECKED(module_request, 0);
Handle<Module> module(isolate->context()->module());
return *Module::GetModuleNamespace(module, module_request);
}
RUNTIME_FUNCTION(Runtime_LoadModuleExport) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
@ -972,9 +980,9 @@ RUNTIME_FUNCTION(Runtime_LoadModuleImport) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
CONVERT_ARG_HANDLE_CHECKED(Smi, module_request, 1);
CONVERT_SMI_ARG_CHECKED(module_request, 1);
Handle<Module> module(isolate->context()->module());
return *Module::LoadImport(module, name, module_request->value());
return *Module::LoadImport(module, name, module_request);
}
RUNTIME_FUNCTION(Runtime_StoreModuleExport) {

View File

@ -420,6 +420,7 @@ namespace internal {
F(CreateIterResultObject, 2, 1) \
F(IsAccessCheckNeeded, 1, 1) \
F(CreateDataProperty, 3, 1) \
F(GetModuleNamespace, 1, 1) \
F(LoadModuleExport, 1, 1) \
F(LoadModuleImport, 2, 1) \
F(StoreModuleExport, 2, 1)

View File

@ -78,7 +78,7 @@ bytecodes: [
/* 15 S> */ B(LdrUndefined), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(9),
B(Star), R(1),
B(CallJSRuntime), U8(141), R(0), U8(2),
B(CallJSRuntime), U8(142), R(0), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [

View File

@ -0,0 +1,82 @@
// 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.
//
// MODULE
let ja = 42;
export {ja as yo};
export const bla = "blaa";
export {foo as foo_again};
// See further below for the actual star import that declares "foo".
// The object itself.
assertEquals("object", typeof foo);
assertThrows(() => foo = 666, TypeError);
assertFalse(Reflect.isExtensible(foo));
assertTrue(Reflect.preventExtensions(foo));
assertThrows(() => Reflect.apply(foo, {}, []));
assertThrows(() => Reflect.construct(foo, {}, []));
assertSame(null, Reflect.getPrototypeOf(foo));
// TODO(neis): The next one should be False.
assertTrue(Reflect.setPrototypeOf(foo, null));
assertFalse(Reflect.setPrototypeOf(foo, {}));
assertSame(null, Reflect.getPrototypeOf(foo));
// TODO(neis): The next one should include @@iterator at the end.
assertEquals(
["bla", "foo_again", "yo", Symbol.toStringTag],
Reflect.ownKeys(foo));
// Its "yo" property.
assertEquals(
{value: 42, enumerable: true, configurable: false, writable: true},
Reflect.getOwnPropertyDescriptor(foo, "yo"));
assertFalse(Reflect.deleteProperty(foo, "yo"));
assertTrue(Reflect.has(foo, "yo"));
// TODO(neis): The next three should be False.
assertTrue(Reflect.set(foo, "yo", true));
assertTrue(Reflect.defineProperty(foo, "yo",
Reflect.getOwnPropertyDescriptor(foo, "yo")));
assertTrue(Reflect.defineProperty(foo, "yo", {}));
assertFalse(Reflect.defineProperty(foo, "yo", {get() {return 1}}));
assertEquals(42, Reflect.get(foo, "yo"));
assertEquals(43, (ja++, foo.yo));
// Its "foo_again" property.
assertSame(foo, foo.foo_again);
// Its @@toStringTag property.
assertTrue(Reflect.has(foo, Symbol.toStringTag));
assertEquals("string", typeof Reflect.get(foo, Symbol.toStringTag));
assertEquals(
{value: "Module", configurable: true, writable: false, enumerable: false},
Reflect.getOwnPropertyDescriptor(foo, Symbol.toStringTag));
// TODO(neis): Its @@iterator property.
// assertTrue(Reflect.has(foo, Symbol.iterator));
// assertEquals("function", typeof Reflect.get(foo, Symbol.iterator));
// assertEquals(["bla", "yo"], [...foo]);
// assertThrows(() => (42, foo[Symbol.iterator])(), TypeError);
// assertSame(foo[Symbol.iterator]().__proto__,
// ([][Symbol.iterator]()).__proto__.__proto__);
// TODO(neis): Clarify spec w.r.t. other symbols.
// Nonexistant properties.
let nonexistant = ["gaga", 123, Symbol('')];
for (let key of nonexistant) {
assertSame(undefined, Reflect.getOwnPropertyDescriptor(foo, key));
assertTrue(Reflect.deleteProperty(foo, key));
assertFalse(Reflect.set(foo, key, true));
assertSame(undefined, Reflect.get(foo, key));
assertFalse(Reflect.defineProperty(foo, key, {get() {return 1}}));
assertFalse(Reflect.has(foo, key));
}
// The actual star import that we are testing. Namespace imports are
// initialized before evaluation
import * as foo from "modules-namespace1.js";
// There can be only one namespace object.
import * as bar from "modules-namespace1.js";
assertSame(foo, bar);

View File

@ -0,0 +1,22 @@
// 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.
//
// MODULE
// TODO(neis): Symbol.iterator
assertEquals(
["b", "c", "get_a", "ns2", "set_a", "zzz", Symbol.toStringTag],
Reflect.ownKeys(ns));
// assertEquals(["b", "c", "get_a", "ns2", "set_a", "zzz"], [...ns]);
import * as foo from "modules-skip-1.js";
assertSame(foo.a, ns.b);
assertSame(foo.a, ns.c);
assertSame(foo.get_a, ns.get_a);
assertSame(foo.set_a, ns.set_a);
assertEquals(123, ns.zzz);
assertSame(ns, ns.ns2.ns);
import * as ns from "modules-skip-namespace.js";
export {ns};

View File

@ -0,0 +1,11 @@
// 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.
//
// MODULE
import * as foo from "modules-namespace3.js";
export * from "modules-namespace3.js";
export var bar;
assertEquals(["bar", "default"], Object.getOwnPropertyNames(foo));
export default function() {};

View File

@ -0,0 +1,37 @@
// 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.
//
// MODULE
import * as foo from "modules-namespace4.js";
assertSame(undefined, a);
assertThrows(() => b, ReferenceError);
assertThrows(() => c, ReferenceError);
assertEquals(45, d());
assertSame(undefined, foo.a);
assertThrows(() => foo.b, ReferenceError);
assertThrows(() => foo.c, ReferenceError);
assertEquals(45, foo.d());
assertThrows(() => foo.default, ReferenceError);
assertSame(undefined, foo.doesnotexist);
export var a = 42;
export let b = 43;
export const c = 44;
export function d() { return 45 };
export default 46;
assertEquals(42, a);
assertEquals(43, b);
assertEquals(44, c);
assertEquals(45, d());
assertEquals(42, foo.a);
assertEquals(43, foo.b);
assertEquals(44, foo.c);
assertEquals(45, foo.d());
assertEquals(46, foo.default);
assertSame(undefined, foo.doesnotexist);

View File

@ -5,3 +5,4 @@
export {a as b, default} from "modules-skip-1.js";
import {a as tmp} from "modules-skip-1.js";
export {tmp as c};
export const zzz = 999;

View File

@ -0,0 +1,13 @@
// 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.
//assertEquals(
// ["ns", Symbol.toStringTag, Symbol.iterator], Reflect.ownKeys(ns2));
//assertEquals(["ns"], [...ns2]);
export * from "modules-skip-4.js";
export * from "modules-skip-5.js";
export var zzz = 123;
export {ns2};
import * as ns2 from "modules-namespace2.js";