2021-09-14 17:35:23 +00:00
/*
2024-10-04 11:19:50 +00:00
* Copyright ( c ) 2021 , Andreas Kling < andreas @ ladybird . org >
2022-01-18 18:29:17 +00:00
* Copyright ( c ) 2022 , David Tuin < davidot @ serenityos . org >
2023-10-29 01:53:53 +00:00
* Copyright ( c ) 2023 , networkException < networkexception @ serenityos . org >
2021-09-14 17:35:23 +00:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-01-18 18:29:17 +00:00
# include <LibJS/CyclicModule.h>
2021-09-14 17:35:23 +00:00
# include <LibJS/Module.h>
2022-01-18 18:29:17 +00:00
# include <LibJS/Runtime/ModuleNamespaceObject.h>
2023-10-29 01:53:53 +00:00
# include <LibJS/Runtime/ModuleRequest.h>
2022-11-23 10:41:19 +00:00
# include <LibJS/Runtime/Promise.h>
# include <LibJS/Runtime/VM.h>
2021-09-14 17:35:23 +00:00
namespace JS {
2023-11-19 08:45:05 +00:00
JS_DEFINE_ALLOCATOR ( Module ) ;
2024-04-06 17:15:41 +00:00
JS_DEFINE_ALLOCATOR ( GraphLoadingState ) ;
2023-11-19 08:45:05 +00:00
2023-12-16 14:19:34 +00:00
Module : : Module ( Realm & realm , ByteString filename , Script : : HostDefined * host_defined )
2022-09-05 12:31:25 +00:00
: m_realm ( realm )
2022-10-02 19:18:33 +00:00
, m_host_defined ( host_defined )
2022-01-18 18:29:17 +00:00
, m_filename ( move ( filename ) )
2021-09-14 17:35:23 +00:00
{
}
2022-09-05 12:31:25 +00:00
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 ) ;
2022-10-02 19:18:33 +00:00
if ( m_host_defined )
m_host_defined - > visit_host_defined_self ( visitor ) ;
2022-09-05 12:31:25 +00:00
}
2022-01-18 18:29:17 +00:00
// 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().
2022-12-13 20:49:50 +00:00
auto promise = TRY ( evaluate ( vm ) ) ;
2022-01-18 18:29:17 +00:00
// 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 ;
}
2023-10-29 01:53:53 +00:00
// 16.2.1.9 FinishLoadingImportedModule ( referrer, specifier, payload, result ), https://tc39.es/ecma262/#sec-FinishLoadingImportedModule
2023-12-02 21:56:47 +00:00
void finish_loading_imported_module ( ImportedModuleReferrer referrer , ModuleRequest const & module_request , ImportedModulePayload payload , ThrowCompletionOr < NonnullGCPtr < Module > > const & result )
2023-10-29 01:53:53 +00:00
{
// 1. If result is a normal completion, then
if ( ! result . is_error ( ) ) {
2023-12-02 21:56:47 +00:00
// NOTE: Only Script and CyclicModule referrers have the [[LoadedModules]] internal slot.
if ( referrer . has < NonnullGCPtr < Script > > ( ) | | referrer . has < NonnullGCPtr < CyclicModule > > ( ) ) {
2023-12-03 13:21:21 +00:00
auto & loaded_modules = referrer . visit (
[ ] ( JS : : NonnullGCPtr < JS : : Realm > & ) - > Vector < ModuleWithSpecifier > & {
2023-12-02 21:56:47 +00:00
VERIFY_NOT_REACHED ( ) ;
2023-12-03 13:21:21 +00:00
__builtin_unreachable ( ) ;
} ,
[ ] ( auto & script_or_module ) - > Vector < ModuleWithSpecifier > & {
return script_or_module - > loaded_modules ( ) ;
2023-12-02 21:56:47 +00:00
} ) ;
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 ;
}
2023-10-29 01:53:53 +00:00
}
2023-12-02 21:56:47 +00:00
// b. Else,
if ( ! found_record ) {
auto module = result . value ( ) ;
2023-10-29 01:53:53 +00:00
2023-12-02 21:56:47 +00:00
// 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 ) } ) ;
}
2023-10-29 01:53:53 +00:00
}
}
2023-12-02 21:56:47 +00:00
if ( payload . has < NonnullGCPtr < GraphLoadingState > > ( ) ) {
// a. Perform ContinueModuleLoading(payload, result)
continue_module_loading ( payload . get < NonnullGCPtr < GraphLoadingState > > ( ) , result ) ;
}
// Else,
else {
// a. Perform ContinueDynamicImport(payload, result).
continue_dynamic_import ( payload . get < NonnullGCPtr < PromiseCapability > > ( ) , result ) ;
}
2023-10-29 01:53:53 +00:00
// 4. Return unused.
}
2022-01-18 18:29:17 +00:00
// 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]].
2022-09-05 12:31:25 +00:00
auto * namespace_ = m_namespace . ptr ( ) ;
2022-01-18 18:29:17 +00:00
// 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.
2023-01-09 00:23:00 +00:00
Vector < DeprecatedFlyString > unambiguous_names ;
2022-01-18 18:29:17 +00:00
// 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 ) ;
2022-09-05 12:31:25 +00:00
VERIFY ( m_namespace ) ;
2022-01-18 18:29:17 +00:00
// 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
2023-01-09 00:23:00 +00:00
Object * Module : : module_namespace_create ( VM & vm , Vector < DeprecatedFlyString > unambiguous_names )
2022-01-18 18:29:17 +00:00
{
2022-08-15 23:20:50 +00:00
auto & realm = this - > realm ( ) ;
2022-01-18 18:29:17 +00:00
// 1. Assert: module.[[Namespace]] is empty.
2022-09-05 12:31:25 +00:00
VERIFY ( ! m_namespace ) ;
2022-01-18 18:29:17 +00:00
// 2. Let internalSlotsList be the internal slots listed in Table 34.
2022-05-02 18:54:39 +00:00
// 3. Let M be MakeBasicObject(internalSlotsList).
2022-01-18 18:29:17 +00:00
// 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.
2023-08-13 11:05:26 +00:00
auto module_namespace = vm . heap ( ) . allocate < ModuleNamespaceObject > ( realm , realm , this , move ( unambiguous_names ) ) ;
2022-01-18 18:29:17 +00:00
// 9. Set module.[[Namespace]] to M.
m_namespace = make_handle ( module_namespace ) ;
// 10. Return M.
return module_namespace ;
}
2021-09-14 17:35:23 +00:00
}