Bug 930414 - Add module importEntries field r=shu

This commit is contained in:
Jon Coppeard 2015-08-24 15:58:35 +01:00
parent 5592c607f8
commit a62f1f731f
5 changed files with 197 additions and 8 deletions

View File

@ -6,10 +6,14 @@
#include "builtin/ModuleObject.h"
#include "gc/Tracer.h"
#include "jsobjinlines.h"
using namespace js;
typedef JS::Rooted<ImportEntryObject*> RootedImportEntry;
template<typename T, Value ValueGetter(T* obj)>
static bool
ModuleValueGetterImpl(JSContext* cx, CallArgs args)
@ -38,6 +42,83 @@ ModuleValueGetter(JSContext* cx, unsigned argc, Value* vp)
return ModuleValueGetter<cls, cls##_##name##Value>(cx, argc, vp); \
}
#define DEFINE_ATOM_ACCESSOR_METHOD(cls, name) \
JSAtom* \
cls::name() \
{ \
Value value = cls##_##name##Value(this); \
return &value.toString()->asAtom(); \
}
///////////////////////////////////////////////////////////////////////////
// ImportEntryObject
/* static */ const Class
ImportEntryObject::class_ = {
"ImportEntry",
JSCLASS_HAS_RESERVED_SLOTS(ImportEntryObject::SlotCount) |
JSCLASS_HAS_CACHED_PROTO(JSProto_ImportEntry) |
JSCLASS_IS_ANONYMOUS |
JSCLASS_IMPLEMENTS_BARRIERS
};
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, moduleRequest, ModuleRequestSlot)
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, importName, ImportNameSlot)
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, localName, LocalNameSlot)
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, moduleRequest)
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, importName)
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, localName)
/* static */ bool
ImportEntryObject::isInstance(HandleValue value)
{
return value.isObject() && value.toObject().is<ImportEntryObject>();
}
/* static */ JSObject*
ImportEntryObject::initClass(JSContext* cx, HandleObject obj)
{
static const JSPropertySpec protoAccessors[] = {
JS_PSG("moduleRequest", ImportEntryObject_moduleRequestGetter, 0),
JS_PSG("importName", ImportEntryObject_importNameGetter, 0),
JS_PSG("localName", ImportEntryObject_localNameGetter, 0),
JS_PS_END
};
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx));
if (!proto)
return nullptr;
if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr))
return nullptr;
global->setPrototype(JSProto_ImportEntry, ObjectValue(*proto));
return proto;
}
JSObject*
js::InitImportEntryClass(JSContext* cx, HandleObject obj)
{
return ImportEntryObject::initClass(cx, obj);
}
/* static */ ImportEntryObject*
ImportEntryObject::create(JSContext* cx,
HandleAtom moduleRequest,
HandleAtom importName,
HandleAtom localName)
{
RootedImportEntry self(cx, NewBuiltinClassInstance<ImportEntryObject>(cx));
if (!self)
return nullptr;
self->initReservedSlot(ModuleRequestSlot, StringValue(moduleRequest));
self->initReservedSlot(ImportNameSlot, StringValue(importName));
self->initReservedSlot(LocalNameSlot, StringValue(localName));
return self;
}
///////////////////////////////////////////////////////////////////////////
// ModuleObject
@ -71,8 +152,7 @@ ModuleObject::class_ = {
}
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, requestedModules, RequestedModulesSlot)
#undef DEFINE_ARRAY_SLOT_ACCESSOR
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, importEntries, ImportEntriesSlot)
/* static */ bool
ModuleObject::isInstance(HandleValue value)
@ -93,9 +173,11 @@ ModuleObject::init(HandleScript script)
}
void
ModuleObject::initImportExportData(HandleArrayObject requestedModules)
ModuleObject::initImportExportData(HandleArrayObject requestedModules,
HandleArrayObject importEntries)
{
initReservedSlot(RequestedModulesSlot, ObjectValue(*requestedModules));
initReservedSlot(ImportEntriesSlot, ObjectValue(*importEntries));
}
JSScript*
@ -114,14 +196,14 @@ ModuleObject::trace(JSTracer* trc, JSObject* obj)
}
DEFINE_GETTER_FUNCTIONS(ModuleObject, requestedModules, RequestedModulesSlot)
#undef DEFINE_GETTER_FUNCTIONS
DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot)
JSObject*
js::InitModuleClass(JSContext* cx, HandleObject obj)
{
static const JSPropertySpec protoAccessors[] = {
JS_PSG("requestedModules", ModuleObject_requestedModulesGetter, 0),
JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0),
JS_PS_END
};
@ -138,12 +220,18 @@ js::InitModuleClass(JSContext* cx, HandleObject obj)
return proto;
}
#undef DEFINE_GETTER_FUNCTIONS
#undef DEFINE_STRING_ACCESSOR_METHOD
#undef DEFINE_ARRAY_SLOT_ACCESSOR
///////////////////////////////////////////////////////////////////////////
// ModuleBuilder
ModuleBuilder::ModuleBuilder(JSContext* cx)
: cx_(cx),
requestedModules_(cx, AtomVector(cx))
requestedModules_(cx, AtomVector(cx)),
importedBoundNames_(cx, AtomVector(cx)),
importEntries_(cx, ImportEntryVector(cx))
{}
bool
@ -182,7 +270,13 @@ ModuleBuilder::buildAndInit(frontend::ParseNode* moduleNode, HandleModuleObject
if (!requestedModules)
return false;
module->initImportExportData(requestedModules);
RootedArrayObject importEntries(cx_, createArray<ImportEntryObject*>(importEntries_));
if (!importEntries)
return false;
module->initImportExportData(requestedModules,
importEntries);
return true;
}
@ -197,6 +291,28 @@ ModuleBuilder::processImport(frontend::ParseNode* pn)
if (!maybeAppendRequestedModule(module))
return false;
for (ParseNode* spec = pn->pn_left->pn_head; spec; spec = spec->pn_next) {
MOZ_ASSERT(spec->isKind(PNK_IMPORT_SPEC));
MOZ_ASSERT(spec->pn_left->isArity(PN_NAME));
MOZ_ASSERT(spec->pn_right->isArity(PN_NAME));
RootedAtom importName(cx_, spec->pn_left->pn_atom);
RootedAtom localName(cx_, spec->pn_right->pn_atom);
if (!importedBoundNames_.append(localName))
return false;
RootedImportEntry importEntry(cx_);
importEntry = ImportEntryObject::create(cx_, module, importName, localName);
if (!importEntry)
return false;
if (!importEntries_.append(importEntry)) {
ReportOutOfMemory(cx_);
return false;
}
}
return true;
}
@ -229,6 +345,12 @@ MakeElementValue(JSString *string)
return StringValue(string);
}
static Value
MakeElementValue(JSObject *object)
{
return ObjectValue(*object);
}
template <typename T>
ArrayObject* ModuleBuilder::createArray(const TraceableVector<T>& vector)
{

View File

@ -19,6 +19,29 @@ namespace frontend {
class ParseNode;
} /* namespace frontend */
class ImportEntryObject : public NativeObject
{
public:
enum
{
ModuleRequestSlot = 0,
ImportNameSlot,
LocalNameSlot,
SlotCount
};
static const Class class_;
static JSObject* initClass(JSContext* cx, HandleObject obj);
static bool isInstance(HandleValue value);
static ImportEntryObject* create(JSContext* cx,
HandleAtom moduleRequest,
HandleAtom importName,
HandleAtom localName);
JSAtom* moduleRequest();
JSAtom* importName();
JSAtom* localName();
};
class ModuleObject : public NativeObject
{
public:
@ -26,6 +49,7 @@ class ModuleObject : public NativeObject
{
ScriptSlot = 0,
RequestedModulesSlot,
ImportEntriesSlot,
SlotCount
};
@ -35,10 +59,12 @@ class ModuleObject : public NativeObject
static ModuleObject* create(ExclusiveContext* cx);
void init(HandleScript script);
void initImportExportData(HandleArrayObject requestedModules);
void initImportExportData(HandleArrayObject requestedModules,
HandleArrayObject importEntries);
JSScript* script() const;
ArrayObject& requestedModules() const;
ArrayObject& importEntries() const;
private:
static void trace(JSTracer* trc, JSObject* obj);
@ -59,9 +85,13 @@ class MOZ_STACK_CLASS ModuleBuilder
private:
using AtomVector = TraceableVector<JSAtom*>;
using RootedAtomVector = JS::Rooted<AtomVector>;
using ImportEntryVector = TraceableVector<ImportEntryObject*>;
using RootedImportEntryVector = JS::Rooted<ImportEntryVector>;
JSContext* cx_;
RootedAtomVector requestedModules_;
RootedAtomVector importedBoundNames_;
RootedImportEntryVector importEntries_;
bool processImport(frontend::ParseNode* pn);
bool processExportFrom(frontend::ParseNode* pn);
@ -73,6 +103,7 @@ class MOZ_STACK_CLASS ModuleBuilder
};
JSObject* InitModuleClass(JSContext* cx, HandleObject obj);
JSObject* InitImportEntryClass(JSContext* cx, HandleObject obj);
} // namespace js

View File

@ -14,6 +14,7 @@
#include "jsgc.h"
#include "jsprf.h"
#include "builtin/ModuleObject.h"
#include "gc/GCInternals.h"
#include "jit/IonCode.h"
#include "js/SliceBudget.h"
@ -369,6 +370,7 @@ AssertRootMarkingPhase(JSTracer* trc)
D(ScriptSourceObject*) \
D(SharedArrayBufferObject*) \
D(SharedTypedArrayObject*) \
D(ImportEntryObject*) \
D(JSScript*) \
D(LazyScript*) \
D(Shape*) \

View File

@ -0,0 +1,33 @@
// Test importEntries property
function testImportEntries(source, expected) {
var module = parseModule(source);
var actual = module.importEntries;
assertEq(actual.length, expected.length);
for (var i = 0; i < actual.length; i++) {
for (var property in expected[i]) {
assertEq(actual[i][property], expected[i][property]);
}
}
}
testImportEntries('', []);
testImportEntries('import v from "mod";',
[{moduleRequest: 'mod', importName: 'default', localName: 'v'}]);
testImportEntries('import * as ns from "mod";',
[{moduleRequest: 'mod', importName: '*', localName: 'ns'}]);
testImportEntries('import {x} from "mod";',
[{moduleRequest: 'mod', importName: 'x', localName: 'x'}]);
testImportEntries('import {x as v} from "mod";',
[{moduleRequest: 'mod', importName: 'x', localName: 'v'}]);
testImportEntries('import "mod";',
[]);
testImportEntries('import {x} from "a"; import {y} from "b";',
[{moduleRequest: 'a', importName: 'x', localName: 'x'},
{moduleRequest: 'b', importName: 'y', localName: 'y'}]);

View File

@ -114,6 +114,7 @@ IF_SAB(real,imaginary)(Atomics, 53, InitAtomicsClass, OCLASP
real(SavedFrame, 54, InitViaClassSpec, &js::SavedFrame::class_) \
real(Reflect, 55, InitReflect, nullptr) \
real(Module, 56, InitModuleClass, OCLASP(Module)) \
real(ImportEntry, 57, InitImportEntryClass, OCLASP(ImportEntry)) \
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)