mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:12:44 +00:00 
			
		
		
		
	 ff6d7cf3e4
			
		
	
	
		ff6d7cf3e4
		
	
	
	
	
		
			
			This patch updates various parts of the script fetching implementation to match the current specification. Notably, the implementation of changes to the import assertions / attributes proposal are not part of this patch(series).
		
			
				
	
	
		
			173 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
 | |
|  * Copyright (c) 2022, David Tuin <davidot@serenityos.org>
 | |
|  * Copyright (c) 2023, networkException <networkexception@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include <LibJS/CyclicModule.h>
 | |
| #include <LibJS/Module.h>
 | |
| #include <LibJS/Runtime/ModuleNamespaceObject.h>
 | |
| #include <LibJS/Runtime/ModuleRequest.h>
 | |
| #include <LibJS/Runtime/Promise.h>
 | |
| #include <LibJS/Runtime/VM.h>
 | |
| 
 | |
| namespace JS {
 | |
| 
 | |
| Module::Module(Realm& realm, DeprecatedString 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.1 InnerModuleLinking ( module, stack, index ), https://tc39.es/ecma262/#sec-InnerModuleLinking
 | |
| ThrowCompletionOr<u32> Module::inner_module_linking(VM& vm, Vector<Module*>&, 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<u32> Module::inner_module_evaluation(VM& vm, Vector<Module*>&, u32 index)
 | |
| {
 | |
|     // 1. If module is not a Cyclic Module Record, then
 | |
|     // a. Let promise be ! module.Evaluate().
 | |
|     auto promise = TRY(evaluate(vm));
 | |
| 
 | |
|     // b. Assert: promise.[[PromiseState]] is not pending.
 | |
|     VERIFY(promise->state() != Promise::State::Pending);
 | |
| 
 | |
|     // c. If promise.[[PromiseState]] is rejected, then
 | |
|     if (promise->state() == Promise::State::Rejected) {
 | |
|         // i. Return ThrowCompletion(promise.[[PromiseResult]]).
 | |
|         return throw_completion(promise->result());
 | |
|     }
 | |
| 
 | |
|     // d. Return index.
 | |
|     return index;
 | |
| }
 | |
| 
 | |
| // 16.2.1.9 FinishLoadingImportedModule ( referrer, specifier, payload, result ), https://tc39.es/ecma262/#sec-FinishLoadingImportedModule
 | |
| // FIXME: We currently implement an outdated version of https://tc39.es/proposal-import-attributes, as such it is not possible to
 | |
| //        use the exact steps from https://tc39.es/proposal-import-attributes/#sec-HostLoadImportedModule here.
 | |
| // FIXME: Support Realm for referrer.
 | |
| void finish_loading_imported_module(Realm& realm, Variant<JS::NonnullGCPtr<JS::Script>, JS::NonnullGCPtr<JS::CyclicModule>> referrer, ModuleRequest const& module_request, GraphLoadingState& payload, ThrowCompletionOr<Module*> const& result)
 | |
| {
 | |
|     // 1. If result is a normal completion, then
 | |
|     if (!result.is_error()) {
 | |
|         auto loaded_modules = referrer.visit(
 | |
|             [](JS::NonnullGCPtr<JS::Script> script) -> Vector<ModuleWithSpecifier> { return script->loaded_modules(); },
 | |
|             [](JS::NonnullGCPtr<JS::CyclicModule> module) -> Vector<ModuleWithSpecifier> { return module->loaded_modules(); });
 | |
| 
 | |
|         bool found_record = false;
 | |
| 
 | |
|         // a.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 = const_cast<Module*>(result.value());
 | |
| 
 | |
|             // i. Append the Record { [[Specifier]]: specifier, [[Module]]: result.[[Value]] } to referrer.[[LoadedModules]].
 | |
|             loaded_modules.append(ModuleWithSpecifier {
 | |
|                 .specifier = module_request.module_specifier,
 | |
|                 .module = NonnullGCPtr<Module>(*module) });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // FIXME: 2. If payload is a GraphLoadingState Record, then
 | |
|     // a. Perform ContinueModuleLoading(payload, result)
 | |
|     continue_module_loading(realm, payload, result);
 | |
| 
 | |
|     // FIXME: Else,
 | |
|     // FIXME: a. Perform ContinueDynamicImport(payload, result).
 | |
| 
 | |
|     // 4. Return unused.
 | |
| }
 | |
| 
 | |
| // 16.2.1.10 GetModuleNamespace ( module ), https://tc39.es/ecma262/#sec-getmodulenamespace
 | |
| ThrowCompletionOr<Object*> Module::get_module_namespace(VM& vm)
 | |
| {
 | |
|     // 1. Assert: If module is a Cyclic Module Record, then module.[[Status]] is not unlinked.
 | |
|     // FIXME: How do we check this without breaking encapsulation?
 | |
| 
 | |
|     // 2. Let namespace be module.[[Namespace]].
 | |
|     auto* namespace_ = m_namespace.ptr();
 | |
| 
 | |
|     // 3. If namespace is empty, then
 | |
|     if (!namespace_) {
 | |
|         // a. Let exportedNames be ? module.GetExportedNames().
 | |
|         auto exported_names = TRY(get_exported_names(vm));
 | |
| 
 | |
|         // b. Let unambiguousNames be a new empty List.
 | |
|         Vector<DeprecatedFlyString> unambiguous_names;
 | |
| 
 | |
|         // c. For each element name of exportedNames, do
 | |
|         for (auto& name : exported_names) {
 | |
|             // i. Let resolution be ? module.ResolveExport(name).
 | |
|             auto resolution = TRY(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(vm, unambiguous_names);
 | |
|         VERIFY(m_namespace);
 | |
|         // Note: This set the local variable 'namespace' and not the member variable which is done by ModuleNamespaceCreate
 | |
|     }
 | |
| 
 | |
|     // 4. Return namespace.
 | |
|     return namespace_;
 | |
| }
 | |
| 
 | |
| // 10.4.6.12 ModuleNamespaceCreate ( module, exports ), https://tc39.es/ecma262/#sec-modulenamespacecreate
 | |
| Object* Module::module_namespace_create(VM& vm, Vector<DeprecatedFlyString> 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 = vm.heap().allocate<ModuleNamespaceObject>(realm, realm, this, move(unambiguous_names));
 | |
| 
 | |
|     // 9. Set module.[[Namespace]] to M.
 | |
|     m_namespace = make_handle(module_namespace);
 | |
| 
 | |
|     // 10. Return M.
 | |
|     return module_namespace;
 | |
| }
 | |
| 
 | |
| }
 |