mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 23:07:22 +00:00
5d360f5c45
- Bug 1198572 - Add telemetry for how often HSTS would fix mixed content problems r=smaug r=tanvi (1abeb434a4) - Bug 1181683 - Mark ping and beacon as blockable mixed content instead of optionally blockable. r=smaug (ab4b612439) - Bug 1148732 - When checking a document's scheme, check the innermost uri. r=dveditz, smaug (f03eef9b3a) - put back source RegExp (112cbc1797) - Bug 1026520 - CSP: Inline report sending into allows - csp changes (r=dveditz) (f835967ad3) - Bug 1026520 - CSP: Inline report sending into allows - callsite updates (r=dveditz) (39b200f027) - Bug 1026520 - CSP: Inline report sending into allows - test updates (r=dveditz) (6a9dd4d859) - Bug 1201822 - Update web-platform-tests expected data to revision d0571e01e1a2e4b8c5f696af2f81cbc1be9a5842, a=testonly (851485e4f9) - Bug 1026520 - CSP: Inline report sending into allows - web platform test updates (r=deveditz) (0fbb9ce2c7) - Bug 1612470 - Remove Document.hasScriptsBlockedBySandbox and Document.inlineScriptAllowedByCSP. r=bzbarsky (840ec6ebfb) - Bug 1192333 - Use channel->ascynOpen2 in dom/xslt/xslt/txMozillaStyleheetCompiler.cpp (r=sicking) (73989dc9d2) - Bug 1186843 - Don't recreate message manager. r=smaug (d4e2e28136) - Bug 1209361 - Add missing includes to dom/base. r=mccr8 (702a9b0c21) - Bug 1209621 - Add a way to get the TabParent for the content-primary tab, r=mconley (7d8a7e501f) - Bug 1209001 - Fix OOM handling when creating ModuleObject r=terrence (e5b9fc8db3) - Bug 1183289 - Run fewer CGC tests r=sfink (d529983340) - Bug 1204692 - Add arm64-sim variant to the autospider.sh script. r=sstangl (8f46c42105) - Bug 1183289 - Partially revert previous patch so jstests get run with default jitflags only r=me (97d1721e43) - Bug 1210924 - Do not fire read barriers when using ReadBarriered in a boolean context; r=sfink (697885508c) - code style and reshuffle (1b55c0f721) - Bug 1207821 - Change the initialized length of an unboxed array in some places without triggering pre barriers, r=jandem. (92452a2db0) - Bug 1074935 - Add SPS pseudo frames for JSRope flattening; r=jandem (5589064dc1) - Bug 1184423 - Properly report OOM when initializing the RematerizedFrameTable fails; r=shu (60d964e1ca) - Bug 1201575 - Give copied FrameIter::Data the cx of the current frame. (r=jimb) (af5e59d95a) - Bug 1204725 - IonMonkey: Check result when copying frame iter data, r=nbp (7de175e301) - Bug 1184423 - Properly report OOM when adding a rematerialized frame to the current JitActivation fails; r=shu (a00c310833) - Bug 1210391 - Module scopes are currently not cacheable r=jandem (b42adeb292) - pointer style (30f967d1ee) - Bug 1199221 - Implement JS::ubi::Node::size for js::ObjectGroup referents; r=sfink (364cbff290) - Bug 1199219 - Implement JS::ubi::Node::size for js::Shape referents; r=sfink (683d11d589) - Bug 1199220 - Implement JS::ubi::Node::size for js::BaseShape referents; r=sfink (a9e1c02cbc) - Bug 1200482: Make Debugger respect 'enabled' flag when setting allocation tracking hook on debuggee compartments, and check that it does. r=fitzgen (cf203e12e0) - Bug 1177508 - Truncate the stack more aggressively in adoptAsyncStack. r=fitzgen (c335f6dcd5) - Bug 1209989 - Implicitly attach a PRThread to native threads when first used as a PRThread in the PosixNSPR implementation. r=terrence (c9d771fb47) - Bug 1206640: Fix an implicit constructor in PosixNSPR.cpp; r=nbp (178312c0f2) - Bug 1204863 - Ignore frames from self-hosted scripts; r=shu (4b8cd11832) - Bug 1180047: Debugger.prototype.findObjects should not return objects that must not be exposed to JS. r=fitzgen (634f19195b) - Bug 1208908 - Fix a conditional statement in BytecodeRangeWithPosition::updatePosition(); r=ejpbruel (e58c656255) - some profiler and crash import (d5b8b4f798) - Bug 1185532: Turn on the NPAPI process sandbox for Windows 64-bit flash by default. r=bsmedberg (5aa8fa8a6e) - Bug 1194488: Whitelist specific plugins for async init; r=jimm (7c78723689) - Bug 1200698: Rename async plugin init pref; r=bsmedberg (df37e5833e) - Bug 1184068: Ensure that mShutdown is not incorrectly set from true to false if plugin crashes during CallNP_Shutdown; r=jimm Bug 1202024: Initialize plugin details and quirks in parent on first run for async init. r=aklotz (934d877d8c) - missing bit of Bug 1119878 Part 2 (3a0dd8afc1) - Bug 1209351 (part 6) - Optimize nsTHashTable::RemoveEntry() usage in toolkit/. r=froydnj. (810fbbab89) - Bug 1209351 (part 1) - Add an overloading of nsTHashTable::RemoveEntry() that takes an already-found entry. r=froydnj. (45d6181461) - Bug 1209351 (part 2) - Optimize nsTHashTable::RemoveEntry() usage in dom/. r=bz. (bdb19ed49f) - Bug 1209351 (part 3) - Optimize nsTHashTable::RemoveEntry() usage in gfx/. r=jrmuizel. (dc29a2b97f) - Bug 1209351 (part 4) - Optimize nsTHashTable::RemoveEntry() usage in netwerk/. r=michal.novotny. (3be1f09b5c) - Bug 1209351 (part 5) - Optimize nsTHashTable::RemoveEntry() usage in security/. r=keeler. (47999463fe)
761 lines
26 KiB
C++
761 lines
26 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "builtin/ModuleObject.h"
|
|
|
|
#include "frontend/ParseNode.h"
|
|
#include "frontend/SharedContext.h"
|
|
#include "gc/Tracer.h"
|
|
|
|
#include "jsobjinlines.h"
|
|
|
|
using namespace js;
|
|
using namespace js::frontend;
|
|
|
|
typedef JS::Rooted<ImportEntryObject*> RootedImportEntry;
|
|
typedef JS::Rooted<ExportEntryObject*> RootedExportEntry;
|
|
|
|
template<typename T, Value ValueGetter(T* obj)>
|
|
static bool
|
|
ModuleValueGetterImpl(JSContext* cx, const CallArgs& args)
|
|
{
|
|
args.rval().set(ValueGetter(&args.thisv().toObject().as<T>()));
|
|
return true;
|
|
}
|
|
|
|
template<typename T, Value ValueGetter(T* obj)>
|
|
static bool
|
|
ModuleValueGetter(JSContext* cx, unsigned argc, Value* vp)
|
|
{
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
return CallNonGenericMethod<T::isInstance, ModuleValueGetterImpl<T, ValueGetter>>(cx, args);
|
|
}
|
|
|
|
#define DEFINE_GETTER_FUNCTIONS(cls, name, slot) \
|
|
static Value \
|
|
cls##_##name##Value(cls* obj) { \
|
|
return obj->getFixedSlot(cls::slot); \
|
|
} \
|
|
\
|
|
static bool \
|
|
cls##_##name##Getter(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(); \
|
|
}
|
|
|
|
#define DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(cls, name) \
|
|
JSAtom* \
|
|
cls::name() \
|
|
{ \
|
|
Value value = cls##_##name##Value(this); \
|
|
if (value.isNull()) \
|
|
return nullptr; \
|
|
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
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// ExportEntryObject
|
|
|
|
/* static */ const Class
|
|
ExportEntryObject::class_ = {
|
|
"ExportEntry",
|
|
JSCLASS_HAS_RESERVED_SLOTS(ExportEntryObject::SlotCount) |
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_ExportEntry) |
|
|
JSCLASS_IS_ANONYMOUS
|
|
};
|
|
|
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, exportName, ExportNameSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, importName, ImportNameSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, localName, LocalNameSlot)
|
|
|
|
DEFINE_ATOM_ACCESSOR_METHOD(ExportEntryObject, exportName)
|
|
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, moduleRequest)
|
|
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, importName)
|
|
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, localName)
|
|
|
|
/* static */ bool
|
|
ExportEntryObject::isInstance(HandleValue value)
|
|
{
|
|
return value.isObject() && value.toObject().is<ExportEntryObject>();
|
|
}
|
|
|
|
/* static */ JSObject*
|
|
ExportEntryObject::initClass(JSContext* cx, HandleObject obj)
|
|
{
|
|
static const JSPropertySpec protoAccessors[] = {
|
|
JS_PSG("exportName", ExportEntryObject_exportNameGetter, 0),
|
|
JS_PSG("moduleRequest", ExportEntryObject_moduleRequestGetter, 0),
|
|
JS_PSG("importName", ExportEntryObject_importNameGetter, 0),
|
|
JS_PSG("localName", ExportEntryObject_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_ExportEntry, ObjectValue(*proto));
|
|
return proto;
|
|
}
|
|
|
|
JSObject*
|
|
js::InitExportEntryClass(JSContext* cx, HandleObject obj)
|
|
{
|
|
return ExportEntryObject::initClass(cx, obj);
|
|
}
|
|
|
|
static Value
|
|
StringOrNullValue(JSString* maybeString)
|
|
{
|
|
return maybeString ? StringValue(maybeString) : NullValue();
|
|
}
|
|
|
|
/* static */ ExportEntryObject*
|
|
ExportEntryObject::create(JSContext* cx,
|
|
HandleAtom maybeExportName,
|
|
HandleAtom maybeModuleRequest,
|
|
HandleAtom maybeImportName,
|
|
HandleAtom maybeLocalName)
|
|
{
|
|
RootedExportEntry self(cx, NewBuiltinClassInstance<ExportEntryObject>(cx));
|
|
if (!self)
|
|
return nullptr;
|
|
self->initReservedSlot(ExportNameSlot, StringOrNullValue(maybeExportName));
|
|
self->initReservedSlot(ModuleRequestSlot, StringOrNullValue(maybeModuleRequest));
|
|
self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
|
|
self->initReservedSlot(LocalNameSlot, StringOrNullValue(maybeLocalName));
|
|
return self;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// IndirectBinding
|
|
|
|
IndirectBinding::IndirectBinding(Handle<ModuleEnvironmentObject*> environment, HandleId localName)
|
|
: environment(environment), localName(localName)
|
|
{}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// ModuleObject
|
|
|
|
/* static */ const Class
|
|
ModuleObject::class_ = {
|
|
"Module",
|
|
JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) |
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Module) |
|
|
JSCLASS_IS_ANONYMOUS,
|
|
nullptr, /* addProperty */
|
|
nullptr, /* delProperty */
|
|
nullptr, /* getProperty */
|
|
nullptr, /* setProperty */
|
|
nullptr, /* enumerate */
|
|
nullptr, /* resolve */
|
|
nullptr, /* mayResolve */
|
|
nullptr, /* finalize */
|
|
nullptr, /* call */
|
|
nullptr, /* hasInstance */
|
|
nullptr, /* construct */
|
|
ModuleObject::trace
|
|
};
|
|
|
|
#define DEFINE_ARRAY_SLOT_ACCESSOR(cls, name, slot) \
|
|
ArrayObject& \
|
|
cls::name() const \
|
|
{ \
|
|
return getFixedSlot(cls::slot).toObject().as<ArrayObject>(); \
|
|
}
|
|
|
|
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, requestedModules, RequestedModulesSlot)
|
|
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, importEntries, ImportEntriesSlot)
|
|
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, localExportEntries, LocalExportEntriesSlot)
|
|
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, indirectExportEntries, IndirectExportEntriesSlot)
|
|
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, starExportEntries, StarExportEntriesSlot)
|
|
|
|
/* static */ bool
|
|
ModuleObject::isInstance(HandleValue value)
|
|
{
|
|
return value.isObject() && value.toObject().is<ModuleObject>();
|
|
}
|
|
|
|
/* static */ ModuleObject*
|
|
ModuleObject::create(ExclusiveContext* cx)
|
|
{
|
|
Rooted<ModuleObject*> self(cx, NewBuiltinClassInstance<ModuleObject>(cx, TenuredObject));
|
|
if (!self)
|
|
return nullptr;
|
|
|
|
IndirectBindingMap* bindings = cx->new_<IndirectBindingMap>();
|
|
if (!bindings || !bindings->init()) {
|
|
ReportOutOfMemory(cx);
|
|
return nullptr;
|
|
}
|
|
|
|
self->setReservedSlot(ImportBindingsSlot, PrivateValue(bindings));
|
|
|
|
return self;
|
|
}
|
|
|
|
/* static */ void
|
|
ModuleObject::finalize(js::FreeOp* fop, JSObject* obj)
|
|
{
|
|
ModuleObject* self = &obj->as<ModuleObject>();
|
|
if (!self->getReservedSlot(ImportBindingsSlot).isUndefined())
|
|
fop->delete_(&self->importBindings());
|
|
}
|
|
|
|
ModuleEnvironmentObject*
|
|
ModuleObject::environment() const
|
|
{
|
|
Value value = getReservedSlot(EnvironmentSlot);
|
|
if (value.isUndefined())
|
|
return nullptr;
|
|
|
|
return &value.toObject().as<ModuleEnvironmentObject>();
|
|
}
|
|
|
|
IndirectBindingMap&
|
|
ModuleObject::importBindings()
|
|
{
|
|
return *static_cast<IndirectBindingMap*>(getReservedSlot(ImportBindingsSlot).toPrivate());
|
|
}
|
|
|
|
void
|
|
ModuleObject::init(HandleScript script)
|
|
{
|
|
MOZ_ASSERT(!script->enclosingStaticScope());
|
|
initReservedSlot(ScriptSlot, PrivateValue(script));
|
|
initReservedSlot(EvaluatedSlot, BooleanValue(false));
|
|
}
|
|
|
|
void
|
|
ModuleObject::setInitialEnvironment(HandleModuleEnvironmentObject initialEnvironment)
|
|
{
|
|
initReservedSlot(InitialEnvironmentSlot, ObjectValue(*initialEnvironment));
|
|
}
|
|
|
|
void
|
|
ModuleObject::initImportExportData(HandleArrayObject requestedModules,
|
|
HandleArrayObject importEntries,
|
|
HandleArrayObject localExportEntries,
|
|
HandleArrayObject indirectExportEntries,
|
|
HandleArrayObject starExportEntries)
|
|
{
|
|
initReservedSlot(RequestedModulesSlot, ObjectValue(*requestedModules));
|
|
initReservedSlot(ImportEntriesSlot, ObjectValue(*importEntries));
|
|
initReservedSlot(LocalExportEntriesSlot, ObjectValue(*localExportEntries));
|
|
initReservedSlot(IndirectExportEntriesSlot, ObjectValue(*indirectExportEntries));
|
|
initReservedSlot(StarExportEntriesSlot, ObjectValue(*starExportEntries));
|
|
}
|
|
|
|
bool
|
|
ModuleObject::hasScript() const
|
|
{
|
|
// When modules are parsed via the Reflect.parse() API, the module object
|
|
// doesn't have a script.
|
|
return !getReservedSlot(ScriptSlot).isUndefined();
|
|
}
|
|
|
|
JSScript*
|
|
ModuleObject::script() const
|
|
{
|
|
return static_cast<JSScript*>(getReservedSlot(ScriptSlot).toPrivate());
|
|
}
|
|
|
|
bool
|
|
ModuleObject::evaluated() const
|
|
{
|
|
return getReservedSlot(EvaluatedSlot).toBoolean();
|
|
}
|
|
|
|
ModuleEnvironmentObject&
|
|
ModuleObject::initialEnvironment() const
|
|
{
|
|
return getReservedSlot(InitialEnvironmentSlot).toObject().as<ModuleEnvironmentObject>();
|
|
}
|
|
|
|
JSObject*
|
|
ModuleObject::enclosingStaticScope() const
|
|
{
|
|
// A ModuleObject is always the last thing on the scope chain before the global.
|
|
// TODO: This may no longer be true when we get top-level lexical scopes.
|
|
MOZ_ASSERT_IF(hasScript(), !script()->enclosingStaticScope());
|
|
return nullptr;
|
|
}
|
|
|
|
/* static */ void
|
|
ModuleObject::trace(JSTracer* trc, JSObject* obj)
|
|
{
|
|
ModuleObject& module = obj->as<ModuleObject>();
|
|
if (module.hasScript()) {
|
|
JSScript* script = module.script();
|
|
TraceManuallyBarrieredEdge(trc, &script, "Module script");
|
|
module.setReservedSlot(ScriptSlot, PrivateValue(script));
|
|
}
|
|
|
|
IndirectBindingMap& bindings = module.importBindings();
|
|
for (IndirectBindingMap::Enum e(bindings); !e.empty(); e.popFront()) {
|
|
IndirectBinding& b = e.front().value();
|
|
TraceEdge(trc, &b.environment, "module import environment");
|
|
TraceEdge(trc, &b.localName, "module import local name");
|
|
jsid bindingName = e.front().key();
|
|
TraceManuallyBarrieredEdge(trc, &bindingName, "module import binding name");
|
|
MOZ_ASSERT(bindingName == e.front().key());
|
|
}
|
|
}
|
|
|
|
void
|
|
ModuleObject::createEnvironment()
|
|
{
|
|
// The environment has already been created, we just neet to set it in the
|
|
// right slot.
|
|
MOZ_ASSERT(!getReservedSlot(InitialEnvironmentSlot).isUndefined());
|
|
MOZ_ASSERT(getReservedSlot(EnvironmentSlot).isUndefined());
|
|
setReservedSlot(EnvironmentSlot, getReservedSlot(InitialEnvironmentSlot));
|
|
}
|
|
|
|
void
|
|
ModuleObject::setEvaluated()
|
|
{
|
|
MOZ_ASSERT(!evaluated());
|
|
setReservedSlot(EvaluatedSlot, TrueHandleValue);
|
|
}
|
|
|
|
bool
|
|
ModuleObject::evaluate(JSContext* cx, MutableHandleValue rval)
|
|
{
|
|
RootedScript script(cx, this->script());
|
|
return JS_ExecuteScript(cx, script, rval);
|
|
}
|
|
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, initialEnvironment, InitialEnvironmentSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, environment, EnvironmentSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, evaluated, EvaluatedSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, requestedModules, RequestedModulesSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, localExportEntries, LocalExportEntriesSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries, IndirectExportEntriesSlot)
|
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, starExportEntries, StarExportEntriesSlot)
|
|
|
|
JSObject*
|
|
js::InitModuleClass(JSContext* cx, HandleObject obj)
|
|
{
|
|
static const JSPropertySpec protoAccessors[] = {
|
|
JS_PSG("initialEnvironment", ModuleObject_initialEnvironmentGetter, 0),
|
|
JS_PSG("environment", ModuleObject_environmentGetter, 0),
|
|
JS_PSG("evaluated", ModuleObject_evaluatedGetter, 0),
|
|
JS_PSG("requestedModules", ModuleObject_requestedModulesGetter, 0),
|
|
JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0),
|
|
JS_PSG("localExportEntries", ModuleObject_localExportEntriesGetter, 0),
|
|
JS_PSG("indirectExportEntries", ModuleObject_indirectExportEntriesGetter, 0),
|
|
JS_PSG("starExportEntries", ModuleObject_starExportEntriesGetter, 0),
|
|
JS_PS_END
|
|
};
|
|
|
|
static const JSFunctionSpec protoFunctions[] = {
|
|
JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 3, 0),
|
|
JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleDeclarationInstantiation", 0, 0),
|
|
JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluation", 0, 0),
|
|
JS_FS_END
|
|
};
|
|
|
|
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
|
|
|
RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx));
|
|
if (!proto)
|
|
return nullptr;
|
|
|
|
if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, protoFunctions))
|
|
return nullptr;
|
|
|
|
global->setPrototype(JSProto_Module, ObjectValue(*proto));
|
|
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)),
|
|
importedBoundNames_(cx, AtomVector(cx)),
|
|
importEntries_(cx, ImportEntryVector(cx)),
|
|
exportEntries_(cx, ExportEntryVector(cx)),
|
|
localExportEntries_(cx, ExportEntryVector(cx)),
|
|
indirectExportEntries_(cx, ExportEntryVector(cx)),
|
|
starExportEntries_(cx, ExportEntryVector(cx))
|
|
{}
|
|
|
|
bool
|
|
ModuleBuilder::buildAndInit(frontend::ParseNode* moduleNode, HandleModuleObject module)
|
|
{
|
|
MOZ_ASSERT(moduleNode->isKind(PNK_MODULE));
|
|
|
|
ParseNode* stmtsNode = moduleNode->pn_expr;
|
|
MOZ_ASSERT(stmtsNode->isKind(PNK_STATEMENTLIST));
|
|
MOZ_ASSERT(stmtsNode->isArity(PN_LIST));
|
|
|
|
for (ParseNode* pn = stmtsNode->pn_head; pn; pn = pn->pn_next) {
|
|
switch (pn->getKind()) {
|
|
case PNK_IMPORT:
|
|
if (!processImport(pn))
|
|
return false;
|
|
break;
|
|
|
|
case PNK_EXPORT:
|
|
case PNK_EXPORT_DEFAULT:
|
|
if (!processExport(pn))
|
|
return false;
|
|
break;
|
|
|
|
case PNK_EXPORT_FROM:
|
|
if (!processExportFrom(pn))
|
|
return false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (const auto& e : exportEntries_) {
|
|
RootedExportEntry exp(cx_, e);
|
|
if (!exp->moduleRequest()) {
|
|
RootedImportEntry importEntry(cx_, importEntryFor(exp->localName()));
|
|
if (!importEntry) {
|
|
if (!localExportEntries_.append(exp))
|
|
return false;
|
|
} else {
|
|
if (importEntry->importName() == cx_->names().star) {
|
|
if (!localExportEntries_.append(exp))
|
|
return false;
|
|
} else {
|
|
RootedAtom exportName(cx_, exp->exportName());
|
|
RootedAtom moduleRequest(cx_, importEntry->moduleRequest());
|
|
RootedAtom importName(cx_, importEntry->importName());
|
|
RootedExportEntry exportEntry(cx_);
|
|
exportEntry = ExportEntryObject::create(cx_,
|
|
exportName,
|
|
moduleRequest,
|
|
importName,
|
|
nullptr);
|
|
if (!exportEntry || !indirectExportEntries_.append(exportEntry))
|
|
return false;
|
|
}
|
|
}
|
|
} else if (exp->importName() == cx_->names().star) {
|
|
if (!starExportEntries_.append(exp))
|
|
return false;
|
|
} else {
|
|
if (!indirectExportEntries_.append(exp))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
RootedArrayObject requestedModules(cx_, createArray<JSAtom*>(requestedModules_));
|
|
if (!requestedModules)
|
|
return false;
|
|
|
|
RootedArrayObject importEntries(cx_, createArray<ImportEntryObject*>(importEntries_));
|
|
if (!importEntries)
|
|
return false;
|
|
|
|
RootedArrayObject localExportEntries(cx_, createArray<ExportEntryObject*>(localExportEntries_));
|
|
if (!localExportEntries)
|
|
return false;
|
|
|
|
RootedArrayObject indirectExportEntries(cx_);
|
|
indirectExportEntries = createArray<ExportEntryObject*>(indirectExportEntries_);
|
|
if (!indirectExportEntries)
|
|
return false;
|
|
|
|
RootedArrayObject starExportEntries(cx_, createArray<ExportEntryObject*>(starExportEntries_));
|
|
if (!starExportEntries)
|
|
return false;
|
|
|
|
module->initImportExportData(requestedModules,
|
|
importEntries,
|
|
localExportEntries,
|
|
indirectExportEntries,
|
|
starExportEntries);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ModuleBuilder::processImport(frontend::ParseNode* pn)
|
|
{
|
|
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
|
MOZ_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
|
|
MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
|
|
|
|
RootedAtom module(cx_, pn->pn_right->pn_atom);
|
|
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 || !importEntries_.append(importEntry))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ModuleBuilder::processExport(frontend::ParseNode* pn)
|
|
{
|
|
MOZ_ASSERT(pn->getArity() == pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY);
|
|
|
|
bool isDefault = pn->getKind() == PNK_EXPORT_DEFAULT;
|
|
ParseNode* kid = isDefault ? pn->pn_left : pn->pn_kid;
|
|
|
|
switch (kid->getKind()) {
|
|
case PNK_EXPORT_SPEC_LIST:
|
|
MOZ_ASSERT(!isDefault);
|
|
for (ParseNode* spec = kid->pn_head; spec; spec = spec->pn_next) {
|
|
MOZ_ASSERT(spec->isKind(PNK_EXPORT_SPEC));
|
|
RootedAtom localName(cx_, spec->pn_left->pn_atom);
|
|
RootedAtom exportName(cx_, spec->pn_right->pn_atom);
|
|
if (!appendLocalExportEntry(exportName, localName))
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case PNK_FUNCTION: {
|
|
RootedFunction func(cx_, kid->pn_funbox->function());
|
|
RootedAtom localName(cx_, func->atom());
|
|
RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
|
|
if (!appendLocalExportEntry(exportName, localName))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case PNK_CLASS: {
|
|
const ClassNode& cls = kid->as<ClassNode>();
|
|
MOZ_ASSERT(cls.names());
|
|
RootedAtom localName(cx_, cls.names()->innerBinding()->pn_atom);
|
|
RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
|
|
if (!appendLocalExportEntry(exportName, localName))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case PNK_VAR:
|
|
case PNK_CONST:
|
|
case PNK_LET: {
|
|
MOZ_ASSERT(kid->isArity(PN_LIST));
|
|
for (ParseNode* var = kid->pn_head; var; var = var->pn_next) {
|
|
if (var->isKind(PNK_ASSIGN))
|
|
var = var->pn_left;
|
|
MOZ_ASSERT(var->isKind(PNK_NAME));
|
|
RootedAtom localName(cx_, var->pn_atom);
|
|
RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
|
|
if (!appendLocalExportEntry(exportName, localName))
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
MOZ_ASSERT(isDefault);
|
|
RootedAtom localName(cx_, cx_->names().starDefaultStar);
|
|
RootedAtom exportName(cx_, cx_->names().default_);
|
|
if (!appendLocalExportEntry(exportName, localName))
|
|
return false;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ModuleBuilder::processExportFrom(frontend::ParseNode* pn)
|
|
{
|
|
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
|
MOZ_ASSERT(pn->pn_left->isKind(PNK_EXPORT_SPEC_LIST));
|
|
MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
|
|
|
|
RootedAtom module(cx_, pn->pn_right->pn_atom);
|
|
if (!maybeAppendRequestedModule(module))
|
|
return false;
|
|
|
|
for (ParseNode* spec = pn->pn_left->pn_head; spec; spec = spec->pn_next) {
|
|
if (spec->isKind(PNK_EXPORT_SPEC)) {
|
|
RootedAtom bindingName(cx_, spec->pn_left->pn_atom);
|
|
RootedAtom exportName(cx_, spec->pn_right->pn_atom);
|
|
if (!appendIndirectExportEntry(exportName, module, bindingName))
|
|
return false;
|
|
} else {
|
|
MOZ_ASSERT(spec->isKind(PNK_EXPORT_BATCH_SPEC));
|
|
RootedAtom importName(cx_, cx_->names().star);
|
|
if (!appendIndirectExportEntry(nullptr, module, importName))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ImportEntryObject*
|
|
ModuleBuilder::importEntryFor(JSAtom* localName)
|
|
{
|
|
for (auto import : importEntries_) {
|
|
if (import->localName() == localName)
|
|
return import;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool
|
|
ModuleBuilder::appendLocalExportEntry(HandleAtom exportName, HandleAtom localName)
|
|
{
|
|
Rooted<ExportEntryObject*> exportEntry(cx_);
|
|
exportEntry = ExportEntryObject::create(cx_, exportName, nullptr, nullptr, localName);
|
|
return exportEntry && exportEntries_.append(exportEntry);
|
|
}
|
|
|
|
bool
|
|
ModuleBuilder::appendIndirectExportEntry(HandleAtom exportName, HandleAtom moduleRequest,
|
|
HandleAtom importName)
|
|
{
|
|
Rooted<ExportEntryObject*> exportEntry(cx_);
|
|
exportEntry = ExportEntryObject::create(cx_, exportName, moduleRequest, importName, nullptr);
|
|
return exportEntry && exportEntries_.append(exportEntry);
|
|
}
|
|
|
|
bool
|
|
ModuleBuilder::maybeAppendRequestedModule(HandleAtom module)
|
|
{
|
|
for (auto m : requestedModules_) {
|
|
if (m == module)
|
|
return true;
|
|
}
|
|
return requestedModules_.append(module);
|
|
}
|
|
|
|
static Value
|
|
MakeElementValue(JSString *string)
|
|
{
|
|
return StringValue(string);
|
|
}
|
|
|
|
static Value
|
|
MakeElementValue(JSObject *object)
|
|
{
|
|
return ObjectValue(*object);
|
|
}
|
|
|
|
template <typename T>
|
|
ArrayObject* ModuleBuilder::createArray(const TraceableVector<T>& vector)
|
|
{
|
|
uint32_t length = vector.length();
|
|
RootedArrayObject array(cx_, NewDenseFullyAllocatedArray(cx_, length));
|
|
if (!array)
|
|
return nullptr;
|
|
|
|
array->setDenseInitializedLength(length);
|
|
for (uint32_t i = 0; i < length; i++)
|
|
array->initDenseElement(i, MakeElementValue(vector[i]));
|
|
if (!JS_FreezeObject(cx_, array))
|
|
return nullptr;
|
|
|
|
return array;
|
|
}
|