/* * Copyright (c) 2021-2025, Andreas Kling * Copyright (c) 2022, David Tuin * Copyright (c) 2023, networkException * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include namespace JS { GC_DEFINE_ALLOCATOR(Module); GC_DEFINE_ALLOCATOR(GraphLoadingState); Module::Module(Realm& realm, ByteString filename, Script::HostDefined* host_defined) : m_realm(realm) , m_host_defined(host_defined) , m_filename(move(filename)) { } Module::~Module() = default; void Module::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_realm); visitor.visit(m_environment); visitor.visit(m_namespace); if (m_host_defined) m_host_defined->visit_host_defined_self(visitor); } // 16.2.1.5.1 EvaluateModuleSync ( module ), https://tc39.es/ecma262/#sec-EvaluateModuleSync ThrowCompletionOr Module::evaluate_module_sync(VM& vm) { // 1. Assert: module is not a Cyclic Module Record. // 2. Let promise be module.Evaluate(). auto promise = TRY(evaluate(vm)); // 3. Assert: promise.[[PromiseState]] is either FULFILLED or REJECTED. VERIFY(first_is_one_of(promise->state(), Promise::State::Fulfilled, Promise::State::Rejected)); // 4. If promise.[[PromiseState]] is REJECTED, then if (promise->state() == Promise::State::Rejected) { // a. If promise.[[PromiseIsHandled]] is false, perform HostPromiseRejectionTracker(promise, "handle"). if (!promise->is_handled()) vm.host_promise_rejection_tracker(promise, Promise::RejectionOperation::Handle); // b. Set promise.[[PromiseIsHandled]] to true. promise->set_is_handled(); // c. Return ThrowCompletion(promise.[[PromiseResult]]). return throw_completion(promise->result()); } // 5. Return UNUSED. return {}; } // 16.2.1.5.1.1 InnerModuleLinking ( module, stack, index ), https://tc39.es/ecma262/#sec-InnerModuleLinking ThrowCompletionOr Module::inner_module_linking(VM& vm, Vector&, u32 index) { // 1. If module is not a Cyclic Module Record, then // a. Perform ? module.Link(). TRY(link(vm)); // b. Return index. return index; } // 16.2.1.5.2.1 InnerModuleEvaluation ( module, stack, index ), https://tc39.es/ecma262/#sec-innermoduleevaluation ThrowCompletionOr Module::inner_module_evaluation(VM& vm, Vector&, u32 index) { // 1. If module is not a Cyclic Module Record, then // a. Perform ? EvaluateModuleSync(module). TRY(evaluate_module_sync(vm)); // b. Return index. return index; } // 16.2.1.9 FinishLoadingImportedModule ( referrer, specifier, payload, result ), https://tc39.es/ecma262/#sec-FinishLoadingImportedModule void finish_loading_imported_module(ImportedModuleReferrer referrer, ModuleRequest const& module_request, ImportedModulePayload payload, ThrowCompletionOr> const& result) { // 1. If result is a normal completion, then if (!result.is_error()) { // NOTE: Only Script and CyclicModule referrers have the [[LoadedModules]] internal slot. if (referrer.has>() || referrer.has>()) { auto& loaded_modules = referrer.visit( [](GC::Ref&) -> Vector& { VERIFY_NOT_REACHED(); __builtin_unreachable(); }, [](auto& script_or_module) -> Vector& { return script_or_module->loaded_modules(); }); bool found_record = false; // a. If referrer.[[LoadedModules]] contains a Record whose [[Specifier]] is specifier, then for (auto const& record : loaded_modules) { if (record.specifier == module_request.module_specifier) { // i. Assert: That Record's [[Module]] is result.[[Value]]. VERIFY(record.module == result.value()); found_record = true; } } // b. Else, if (!found_record) { auto module = result.value(); // i. Append the Record { [[Specifier]]: specifier, [[Module]]: result.[[Value]] } to referrer.[[LoadedModules]]. loaded_modules.append(ModuleWithSpecifier { .specifier = module_request.module_specifier.to_string(), .module = GC::Ref(*module) }); } } } // 2. If payload is a GraphLoadingState Record, then if (payload.has>()) { // a. Perform ContinueModuleLoading(payload, result) continue_module_loading(payload.get>(), result); } // 3. Else, else { // a. Perform ContinueDynamicImport(payload, result). continue_dynamic_import(payload.get>(), result); } // 4. Return unused. } // 16.2.1.10 GetModuleNamespace ( module ), https://tc39.es/ecma262/#sec-getmodulenamespace GC::Ref Module::get_module_namespace(VM& vm) { // 1. Assert: If module is a Cyclic Module Record, then module.[[Status]] is not NEW or UNLINKED. // FIXME: Spec bug: https://github.com/tc39/ecma262/issues/3114 // 2. Let namespace be module.[[Namespace]]. auto namespace_ = m_namespace; // 3. If namespace is EMPTY, then if (!namespace_) { // a. Let exportedNames be module.GetExportedNames(). auto exported_names = get_exported_names(vm); // b. Let unambiguousNames be a new empty List. Vector unambiguous_names; // c. For each element name of exportedNames, do for (auto& name : exported_names) { // i. Let resolution be module.ResolveExport(name). auto resolution = resolve_export(vm, name); // ii. If resolution is a ResolvedBinding Record, append name to unambiguousNames. if (resolution.is_valid()) unambiguous_names.append(name); } // d. Set namespace to ModuleNamespaceCreate(module, unambiguousNames). namespace_ = module_namespace_create(unambiguous_names); } // 4. Return namespace. return *namespace_; } Vector Module::get_exported_names(VM& vm) { HashTable export_star_set; return get_exported_names(vm, export_star_set); } // 10.4.6.12 ModuleNamespaceCreate ( module, exports ), https://tc39.es/ecma262/#sec-modulenamespacecreate GC::Ref Module::module_namespace_create(Vector unambiguous_names) { auto& realm = this->realm(); // 1. Assert: module.[[Namespace]] is empty. VERIFY(!m_namespace); // 2. Let internalSlotsList be the internal slots listed in Table 34. // 3. Let M be MakeBasicObject(internalSlotsList). // 4. Set M's essential internal methods to the definitions specified in 10.4.6. // 5. Set M.[[Module]] to module. // 6. Let sortedExports be a List whose elements are the elements of exports ordered as if an Array of the same values had been sorted using %Array.prototype.sort% using undefined as comparefn. // 7. Set M.[[Exports]] to sortedExports. // 8. Create own properties of M corresponding to the definitions in 28.3. auto module_namespace = realm.create(realm, this, move(unambiguous_names)); // 9. Set module.[[Namespace]] to M. m_namespace = module_namespace; // 10. Return M. return module_namespace; } }