summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/ModuleObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/ModuleObject.cpp')
-rw-r--r--js/src/builtin/ModuleObject.cpp163
1 files changed, 150 insertions, 13 deletions
diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp
index 0be9aec17b..b9db9bf02d 100644
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -20,7 +20,7 @@
#include "gc/Tracer.h"
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin, JS::LimitedColumnNumberOneOrigin
#include "js/friend/ErrorMessages.h" // JSMSG_*
-#include "js/Modules.h" // JS::GetModulePrivate, JS::ModuleDynamicImportHook
+#include "js/Modules.h" // JS::GetModulePrivate, JS::ModuleDynamicImportHook, JS::ModuleType
#include "vm/EqualityOperations.h" // js::SameValue
#include "vm/Interpreter.h" // Execute, Lambda, ReportRuntimeLexicalError
#include "vm/ModuleBuilder.h" // js::ModuleBuilder
@@ -31,6 +31,7 @@
#include "builtin/HandlerFunction-inl.h" // js::ExtraValueFromHandler, js::NewHandler{,WithExtraValue}, js::TargetFromHandler
#include "gc/GCContext-inl.h"
+#include "vm/EnvironmentObject-inl.h" // EnvironmentObject::setAliasedBinding
#include "vm/JSObject-inl.h"
#include "vm/JSScript-inl.h"
#include "vm/List-inl.h"
@@ -184,8 +185,8 @@ ResolvedBindingObject* ResolvedBindingObject::create(
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ModuleRequestObject, specifier,
SpecifierSlot)
-ArrayObject* ModuleRequestObject::assertions() const {
- JSObject* obj = getReservedSlot(AssertionSlot).toObjectOrNull();
+ArrayObject* ModuleRequestObject::attributes() const {
+ JSObject* obj = getReservedSlot(AttributesSlot).toObjectOrNull();
if (!obj) {
return nullptr;
}
@@ -193,6 +194,52 @@ ArrayObject* ModuleRequestObject::assertions() const {
return &obj->as<ArrayObject>();
}
+bool ModuleRequestObject::hasAttributes() const {
+ return !getReservedSlot(ModuleRequestObject::AttributesSlot)
+ .isNullOrUndefined();
+}
+
+/* static */
+bool ModuleRequestObject::getModuleType(
+ JSContext* cx, const Handle<ModuleRequestObject*> moduleRequest,
+ JS::ModuleType& moduleType) {
+ if (!moduleRequest->hasAttributes()) {
+ moduleType = JS::ModuleType::JavaScript;
+ return true;
+ }
+
+ Rooted<ArrayObject*> attributesArray(cx, moduleRequest->attributes());
+ RootedObject attributeObject(cx);
+ RootedId typeId(cx, NameToId(cx->names().type));
+ RootedValue value(cx);
+
+ uint32_t numberOfAttributes = attributesArray->length();
+ for (uint32_t i = 0; i < numberOfAttributes; i++) {
+ attributeObject = &attributesArray->getDenseElement(i).toObject();
+
+ if (!GetProperty(cx, attributeObject, attributeObject, typeId, &value)) {
+ continue;
+ }
+
+ int32_t isJsonString;
+ if (!js::CompareStrings(cx, cx->names().json, value.toString(),
+ &isJsonString)) {
+ return false;
+ }
+
+ if (isJsonString == 0) {
+ moduleType = JS::ModuleType::JSON;
+ return true;
+ }
+
+ moduleType = JS::ModuleType::Unknown;
+ return true;
+ }
+
+ moduleType = JS::ModuleType::JavaScript;
+ return true;
+}
+
/* static */
bool ModuleRequestObject::isInstance(HandleValue value) {
return value.isObject() && value.toObject().is<ModuleRequestObject>();
@@ -201,7 +248,7 @@ bool ModuleRequestObject::isInstance(HandleValue value) {
/* static */
ModuleRequestObject* ModuleRequestObject::create(
JSContext* cx, Handle<JSAtom*> specifier,
- Handle<ArrayObject*> maybeAssertions) {
+ Handle<ArrayObject*> maybeAttributes) {
ModuleRequestObject* self =
NewObjectWithGivenProto<ModuleRequestObject>(cx, nullptr);
if (!self) {
@@ -209,7 +256,7 @@ ModuleRequestObject* ModuleRequestObject::create(
}
self->initReservedSlot(SpecifierSlot, StringOrNullValue(specifier));
- self->initReservedSlot(AssertionSlot, ObjectOrNullValue(maybeAssertions));
+ self->initReservedSlot(AttributesSlot, ObjectOrNullValue(maybeAttributes));
return self;
}
@@ -618,6 +665,21 @@ void ModuleNamespaceObject::ProxyHandler::finalize(JS::GCContext* gcx,
}
///////////////////////////////////////////////////////////////////////////
+// SyntheticModuleFields
+
+// The fields of a synthetic module record, as described in:
+// https://tc39.es/proposal-json-modules/#sec-synthetic-module-records
+class js::SyntheticModuleFields {
+ public:
+ ExportNameVector exportNames;
+
+ public:
+ void trace(JSTracer* trc);
+};
+
+void SyntheticModuleFields::trace(JSTracer* trc) { exportNames.trace(trc); }
+
+///////////////////////////////////////////////////////////////////////////
// CyclicModuleFields
// The fields of a cyclic module record, as described in:
@@ -857,6 +919,10 @@ Span<const ExportEntry> ModuleObject::starExportEntries() const {
return cyclicModuleFields()->starExportEntries();
}
+const ExportNameVector& ModuleObject::syntheticExportNames() const {
+ return syntheticModuleFields()->exportNames;
+}
+
void ModuleObject::initFunctionDeclarations(
UniquePtr<FunctionDeclarationVector> decls) {
cyclicModuleFields()->functionDeclarations = std::move(decls);
@@ -883,12 +949,39 @@ ModuleObject* ModuleObject::create(JSContext* cx) {
}
/* static */
+ModuleObject* ModuleObject::createSynthetic(
+ JSContext* cx, MutableHandle<ExportNameVector> exportNames) {
+ Rooted<UniquePtr<SyntheticModuleFields>> syntheticFields(cx);
+ syntheticFields = cx->make_unique<SyntheticModuleFields>();
+ if (!syntheticFields) {
+ return nullptr;
+ }
+
+ Rooted<ModuleObject*> self(
+ cx, NewObjectWithGivenProto<ModuleObject>(cx, nullptr));
+ if (!self) {
+ return nullptr;
+ }
+
+ InitReservedSlot(self, SyntheticModuleFieldsSlot, syntheticFields.release(),
+ MemoryUse::ModuleSyntheticFields);
+
+ self->syntheticModuleFields()->exportNames = std::move(exportNames.get());
+
+ return self;
+}
+
+/* static */
void ModuleObject::finalize(JS::GCContext* gcx, JSObject* obj) {
ModuleObject* self = &obj->as<ModuleObject>();
if (self->hasCyclicModuleFields()) {
gcx->delete_(obj, self->cyclicModuleFields(),
MemoryUse::ModuleCyclicFields);
}
+ if (self->hasSyntheticModuleFields()) {
+ gcx->delete_(obj, self->syntheticModuleFields(),
+ MemoryUse::ModuleSyntheticFields);
+ }
}
ModuleEnvironmentObject& ModuleObject::initialEnvironment() const {
@@ -960,6 +1053,7 @@ void ModuleObject::setAsyncEvaluating() {
void ModuleObject::initScriptSlots(HandleScript script) {
MOZ_ASSERT(script);
MOZ_ASSERT(script->sourceObject());
+ MOZ_ASSERT(script->filename());
initReservedSlot(ScriptSlot, PrivateGCThingValue(script));
cyclicModuleFields()->scriptSourceObject = script->sourceObject();
}
@@ -1021,10 +1115,12 @@ static inline void AssertValidModuleStatus(ModuleStatus status) {
}
ModuleStatus ModuleObject::status() const {
- // TODO: When implementing synthetic module records it may be convenient to
- // make this method always return a ModuleStatus::Evaluated for such a module
- // so we can assert a module's status without checking which kind it is, even
- // though synthetic modules don't have this field according to the spec.
+ // Always return `ModuleStatus::Evaluated` so we can assert a module's status
+ // without checking which kind it is, even though synthetic modules don't have
+ // this field according to the spec.
+ if (hasSyntheticModuleFields()) {
+ return ModuleStatus::Evaluated;
+ }
ModuleStatus status = cyclicModuleFields()->status;
AssertValidModuleStatus(status);
@@ -1161,6 +1257,22 @@ ModuleObject* ModuleObject::getCycleRoot() const {
return cyclicModuleFields()->cycleRoot;
}
+bool ModuleObject::hasSyntheticModuleFields() const {
+ bool result = !getReservedSlot(SyntheticModuleFieldsSlot).isUndefined();
+ MOZ_ASSERT_IF(result, !hasCyclicModuleFields());
+ return result;
+}
+
+SyntheticModuleFields* ModuleObject::syntheticModuleFields() {
+ MOZ_ASSERT(!hasCyclicModuleFields());
+ void* ptr = getReservedSlot(SyntheticModuleFieldsSlot).toPrivate();
+ MOZ_ASSERT(ptr);
+ return static_cast<SyntheticModuleFields*>(ptr);
+}
+const SyntheticModuleFields* ModuleObject::syntheticModuleFields() const {
+ return const_cast<ModuleObject*>(this)->syntheticModuleFields();
+}
+
bool ModuleObject::hasTopLevelCapability() const {
return cyclicModuleFields()->topLevelCapability;
}
@@ -1206,6 +1318,9 @@ void ModuleObject::trace(JSTracer* trc, JSObject* obj) {
if (module.hasCyclicModuleFields()) {
module.cyclicModuleFields()->trace(trc);
}
+ if (module.hasSyntheticModuleFields()) {
+ module.syntheticModuleFields()->trace(trc);
+ }
}
/* static */
@@ -1328,6 +1443,27 @@ bool ModuleObject::createEnvironment(JSContext* cx,
return true;
}
+/*static*/
+bool ModuleObject::createSyntheticEnvironment(JSContext* cx,
+ Handle<ModuleObject*> self,
+ Handle<GCVector<Value>> values) {
+ Rooted<ModuleEnvironmentObject*> env(
+ cx, ModuleEnvironmentObject::createSynthetic(cx, self));
+ if (!env) {
+ return false;
+ }
+
+ MOZ_ASSERT(env->shape()->propMapLength() == values.length());
+
+ for (uint32_t i = 0; i < values.length(); i++) {
+ env->setAliasedBinding(env->firstSyntheticValueSlot() + i, values[i]);
+ }
+
+ self->setInitialEnvironment(env);
+
+ return true;
+}
+
///////////////////////////////////////////////////////////////////////////
// ModuleBuilder
@@ -2542,10 +2678,11 @@ static bool OnResolvedDynamicModule(JSContext* cx, unsigned argc, Value* vp) {
return RejectPromiseWithPendingError(cx, promise);
}
- MOZ_ASSERT(module->getCycleRoot()
- ->topLevelCapability()
- ->as<PromiseObject>()
- .state() == JS::PromiseState::Fulfilled);
+ MOZ_ASSERT_IF(module->hasCyclicModuleFields(),
+ module->getCycleRoot()
+ ->topLevelCapability()
+ ->as<PromiseObject>()
+ .state() == JS::PromiseState::Fulfilled);
RootedObject ns(cx, GetOrCreateModuleNamespace(cx, module));
if (!ns) {