2021-04-30 17:38:51 -03:00
/*
* Copyright ( c ) 2021 , Ali Mohammad Pur < mpfard @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-06-10 19:41:47 -03:00
# include <AK/Enumerate.h>
2026-06-04 05:40:32 -03:00
# include <AK/NeverDestroyed.h>
2026-03-21 10:42:32 -03:00
# include <AK/SaturatingMath.h>
2026-04-04 14:26:41 -03:00
# include <LibCore/System.h>
2026-06-04 09:17:57 -03:00
# include <LibSync/MutexProtected.h>
2021-04-30 17:38:51 -03:00
# include <LibWasm/AbstractMachine/AbstractMachine.h>
2021-06-04 08:54:20 -03:00
# include <LibWasm/AbstractMachine/BytecodeInterpreter.h>
2021-04-30 17:38:51 -03:00
# include <LibWasm/AbstractMachine/Configuration.h>
2021-06-04 08:54:20 -03:00
# include <LibWasm/AbstractMachine/Interpreter.h>
2021-10-31 19:06:35 -03:00
# include <LibWasm/AbstractMachine/Validator.h>
2021-04-30 17:38:51 -03:00
# include <LibWasm/Types.h>
namespace Wasm {
2026-06-04 05:40:32 -03:00
static auto & module_stats ( )
{
2026-06-04 09:17:57 -03:00
static NeverDestroyed < Sync : : MutexProtected < Vector < ModuleStats > > > stats ;
2026-06-04 05:40:32 -03:00
return * stats ;
}
2026-05-11 11:35:24 -03:00
void record_module_stats ( ModuleStats stats )
{
2026-06-04 09:17:57 -03:00
module_stats ( ) . with_locked ( [ & ] ( auto & v ) {
v . append ( move ( stats ) ) ;
} ) ;
2026-05-11 11:35:24 -03:00
}
void dump_module_stats ( )
{
2026-06-04 09:17:57 -03:00
module_stats ( ) . with_locked ( [ & ] ( auto & v ) {
if ( v . is_empty ( ) ) {
warnln ( " wasm-stats: no modules compiled yet " ) ;
return ;
}
warnln ( " wasm-stats: {} module(s) compiled " , v . size ( ) ) ;
2026-06-04 11:53:04 -03:00
warnln ( " wasm-stats: hash input KiB parse ms validate ms cl ms cl blob KiB funcs tu fns tu pts cache " ) ;
2026-06-04 09:17:57 -03:00
AK : : Duration total_parse ;
AK : : Duration total_validate ;
AK : : Duration total_cranelift ;
size_t total_input = 0 ;
size_t total_blob = 0 ;
size_t total_hits = 0 ;
2026-06-04 11:53:04 -03:00
size_t total_tier_up_functions = 0 ;
size_t total_tier_up_checkpoints = 0 ;
2026-06-04 09:17:57 -03:00
for ( auto const & s : v ) {
StringBuilder hash_prefix ;
for ( size_t i = 0 ; i < 4 ; + + i )
hash_prefix . appendff ( " {:02x} " , s . wasm_hash [ i ] ) ;
2026-06-04 11:53:04 -03:00
warnln ( " wasm-stats: {} {:>9} {:>8} {:>11} {:>5} {:>11} {:>5} {:>7} {:>7} {} " ,
2026-06-04 09:17:57 -03:00
hash_prefix . to_byte_string ( ) ,
s . input_size_bytes / 1024 ,
s . parse_time . to_milliseconds ( ) ,
s . validate_time . to_milliseconds ( ) ,
s . cranelift_time . to_milliseconds ( ) ,
s . cranelift_blob_size_bytes / 1024 ,
s . function_count ,
2026-06-04 11:53:04 -03:00
s . tier_up_function_count ,
s . tier_up_checkpoint_count ,
2026-06-04 09:17:57 -03:00
s . cache_hit ? " HIT " : " miss " ) ;
total_parse = total_parse + s . parse_time ;
total_validate = total_validate + s . validate_time ;
total_cranelift = total_cranelift + s . cranelift_time ;
total_input + = s . input_size_bytes ;
total_blob + = s . cranelift_blob_size_bytes ;
2026-06-04 11:53:04 -03:00
total_tier_up_functions + = s . tier_up_function_count ;
total_tier_up_checkpoints + = s . tier_up_checkpoint_count ;
2026-06-04 09:17:57 -03:00
if ( s . cache_hit )
+ + total_hits ;
}
2026-06-04 11:53:04 -03:00
warnln ( " wasm-stats: ---- {:>9} {:>8} {:>11} {:>5} {:>11} {:>5} {:>7} {:>7} hits={} " ,
2026-06-04 09:17:57 -03:00
total_input / 1024 ,
total_parse . to_milliseconds ( ) ,
total_validate . to_milliseconds ( ) ,
total_cranelift . to_milliseconds ( ) ,
total_blob / 1024 ,
2026-06-04 11:53:04 -03:00
" " sv ,
total_tier_up_functions ,
total_tier_up_checkpoints ,
2026-06-04 09:17:57 -03:00
total_hits ) ;
} ) ;
2026-05-11 11:35:24 -03:00
}
2026-04-04 14:26:41 -03:00
MemoryBuffer : : ~ MemoryBuffer ( )
{
clear ( ) ;
}
MemoryBuffer : : MemoryBuffer ( MemoryBuffer & & other )
: m_size ( exchange ( other . m_size , 0 ) )
, m_reserved_capacity ( exchange ( other . m_reserved_capacity , 0 ) )
, m_mapping_size ( exchange ( other . m_mapping_size , 0 ) )
, m_host_page_size ( exchange ( other . m_host_page_size , 0 ) )
, m_mapping_base ( exchange ( other . m_mapping_base , nullptr ) )
, m_data ( exchange ( other . m_data , nullptr ) )
, m_fallback ( move ( other . m_fallback ) )
{
}
MemoryBuffer & MemoryBuffer : : operator = ( MemoryBuffer & & other )
{
if ( this ! = & other ) {
clear ( ) ;
m_size = exchange ( other . m_size , 0 ) ;
m_reserved_capacity = exchange ( other . m_reserved_capacity , 0 ) ;
m_mapping_size = exchange ( other . m_mapping_size , 0 ) ;
m_host_page_size = exchange ( other . m_host_page_size , 0 ) ;
m_mapping_base = exchange ( other . m_mapping_base , nullptr ) ;
m_data = exchange ( other . m_data , nullptr ) ;
m_fallback = move ( other . m_fallback ) ;
}
return * this ;
}
void MemoryBuffer : : clear ( )
{
if ( m_mapping_base ) {
VERIFY ( m_reserved_capacity ) ;
VERIFY ( m_mapping_size ) ;
VERIFY ( m_host_page_size ) ;
auto reservation_size = m_mapping_size + 2 * m_host_page_size ;
[[maybe_unused]] auto result = Core : : System : : release_address_space ( m_mapping_base , reservation_size ) ;
VERIFY ( ! result . is_error ( ) ) ;
}
m_mapping_base = nullptr ;
m_data = nullptr ;
m_reserved_capacity = 0 ;
m_mapping_size = 0 ;
m_host_page_size = 0 ;
m_size = 0 ;
m_fallback . clear ( ) ;
}
void MemoryBuffer : : try_reserve_wasm32_address_space ( )
{
if ( m_mapping_base )
return ;
auto host_page_size = static_cast < size_t > ( PAGE_SIZE ) ;
auto reserved_capacity = static_cast < size_t > ( Constants : : page_size ) * 65536 ;
auto mapping_size = reserved_capacity * 2 ;
auto reservation_size = mapping_size + 2 * host_page_size ;
auto mapping_or_error = Core : : System : : reserve_address_space ( reservation_size ) ;
if ( mapping_or_error . is_error ( ) )
return ;
m_mapping_base = mapping_or_error . value ( ) ;
m_data = reinterpret_cast < u8 * > ( m_mapping_base ) + host_page_size ;
m_reserved_capacity = reserved_capacity ;
m_mapping_size = mapping_size ;
m_host_page_size = host_page_size ;
}
ErrorOr < void > MemoryBuffer : : try_resize ( size_t new_size )
{
if ( m_data ) {
VERIFY ( new_size > = m_size ) ;
VERIFY ( m_host_page_size ) ;
if ( new_size > m_reserved_capacity )
return Error : : from_errno ( ENOMEM ) ;
if ( new_size = = m_size )
return { } ;
auto * grow_base = m_data + m_size ;
auto grow_size = new_size - m_size ;
TRY ( Core : : System : : commit_memory ( grow_base , grow_size ) ) ;
m_size = new_size ;
return { } ;
}
TRY ( m_fallback . try_resize ( new_size ) ) ;
m_size = m_fallback . size ( ) ;
return { } ;
}
bool MemoryBuffer : : contains_virtual_address ( void const * address ) const
{
if ( ! m_mapping_base )
return false ;
auto fault_address = bit_cast < FlatPtr > ( address ) ;
auto base = bit_cast < FlatPtr > ( m_data ) ;
return fault_address > = base & & fault_address < base + m_mapping_size ;
}
ErrorOr < MemoryInstance > MemoryInstance : : create ( MemoryType const & type )
{
MemoryInstance instance { type } ;
if ( ! instance . grow ( type . limits ( ) . min ( ) * Constants : : page_size , GrowType : : No ) )
return Error : : from_string_literal ( " Failed to grow to requested size " ) ;
return { move ( instance ) } ;
}
MemoryInstance : : MemoryInstance ( MemoryType const & type )
: m_type ( type )
{
if ( type . limits ( ) . address_type ( ) = = AddressType : : I32 )
m_data . try_reserve_wasm32_address_space ( ) ;
}
bool MemoryInstance : : grow ( size_t size_to_grow , GrowType grow_type , InhibitGrowCallback inhibit_callback )
{
if ( size_to_grow = = 0 )
return true ;
u64 new_size = m_data . size ( ) + size_to_grow ;
if ( new_size > = Constants : : page_size * 65536 )
return false ;
if ( auto max = m_type . limits ( ) . max ( ) ; max . has_value ( ) ) {
if ( max . value ( ) * Constants : : page_size < new_size )
return false ;
}
auto previous_size = m_data . size ( ) ;
if ( m_data . try_resize ( new_size ) . is_error ( ) )
return false ;
if ( ! m_data . is_virtual ( ) )
m_data . span ( ) . slice ( previous_size , size_to_grow ) . fill ( 0 ) ;
if ( inhibit_callback = = InhibitGrowCallback : : No & & successful_grow_hook )
successful_grow_hook ( ) ;
if ( grow_type = = GrowType : : Yes )
m_type = MemoryType { Limits ( m_type . limits ( ) . address_type ( ) , m_type . limits ( ) . min ( ) + size_to_grow / Constants : : page_size , m_type . limits ( ) . max ( ) ) } ;
return true ;
}
2026-05-21 16:42:37 -03:00
Vector < CompiledFunctionEntry > const & ModuleInstance : : compiled_fn_table ( Store & store ) const
{
if ( m_compiled_fn_table_built )
return m_compiled_fn_table ;
auto count = m_functions . size ( ) ;
2026-06-04 11:53:04 -03:00
if ( count = = 0 ) {
m_compiled_fn_table_built = true ;
2026-05-21 16:42:37 -03:00
return m_compiled_fn_table ;
2026-06-04 11:53:04 -03:00
}
2026-05-21 16:42:37 -03:00
m_compiled_fn_table . resize_with_default_value_and_keep_capacity ( count , { } ) ;
auto * entries = m_compiled_fn_table . data ( ) ;
2026-06-04 11:53:04 -03:00
// Since we asynchronously compile the code to native, we'll need to rebuild this table incrementally until all functions have been compiled.
bool all_ready = true ;
2026-05-21 16:42:37 -03:00
for ( size_t i = 0 ; i < count ; i + + ) {
auto * instance = store . unsafe_get ( m_functions [ i ] ) ;
auto * wasm_fn = instance - > get_pointer < WasmFunction > ( ) ;
if ( ! wasm_fn )
continue ;
2026-06-04 11:53:04 -03:00
if ( auto src = wasm_fn - > module_ref ( ) ; src & & ! src - > has_attempted_cranelift_compilation ( ) )
all_ready = false ;
2026-05-21 16:42:37 -03:00
auto & ci = wasm_fn - > code ( ) . func ( ) . body ( ) . compiled_instructions ;
2026-06-04 11:53:04 -03:00
auto native = cranelift_entry_acquire ( ci ) ;
if ( native = = 0 )
2026-05-21 16:42:37 -03:00
continue ;
auto & entry = entries [ i ] ;
2026-06-04 11:53:04 -03:00
entry . handler_ptr = native ;
2026-05-21 16:42:37 -03:00
entry . dispatches_ptr = bit_cast < FlatPtr > ( ci . dispatches . data ( ) ) ;
entry . src_dst_ptr = bit_cast < FlatPtr > ( ci . src_dst_mappings . data ( ) ) ;
entry . first_insn = ci . dispatches [ 0 ] . instruction ;
entry . expression = & wasm_fn - > code ( ) . func ( ) . body ( ) ;
entry . module = & wasm_fn - > module ( ) ;
entry . total_local_count = static_cast < u32 > ( wasm_fn - > code ( ) . func ( ) . total_local_count ( ) ) ;
entry . arity = static_cast < u32 > ( wasm_fn - > type ( ) . results ( ) . size ( ) ) ;
entry . max_call_rec_size = static_cast < u32 > ( ci . max_call_rec_size ) ;
}
2026-06-04 11:53:04 -03:00
m_compiled_fn_table_built = all_ready ;
2026-05-21 16:42:37 -03:00
return m_compiled_fn_table ;
}
2024-08-21 20:13:37 -03:00
Optional < FunctionAddress > Store : : allocate ( ModuleInstance & instance , Module const & module , CodeSection : : Code const & code , TypeIndex type_index )
2021-04-30 17:38:51 -03:00
{
FunctionAddress address { m_functions . size ( ) } ;
2024-12-08 12:58:50 -03:00
if ( type_index . value ( ) > = instance . types ( ) . size ( ) )
2021-04-30 17:38:51 -03:00
return { } ;
2026-02-02 13:44:20 -03:00
auto & type = instance . types ( ) [ type_index . value ( ) ] . function ( ) ;
2024-08-21 20:13:37 -03:00
m_functions . empend ( WasmFunction { type , instance , module , code } ) ;
2021-04-30 17:38:51 -03:00
return address ;
}
2021-05-17 04:59:44 -03:00
Optional < FunctionAddress > Store : : allocate ( HostFunction & & function )
2021-04-30 17:38:51 -03:00
{
FunctionAddress address { m_functions . size ( ) } ;
2021-05-17 04:59:44 -03:00
m_functions . empend ( HostFunction { move ( function ) } ) ;
2021-04-30 17:38:51 -03:00
return address ;
}
2021-06-03 20:12:11 -03:00
Optional < TableAddress > Store : : allocate ( TableType const & type )
2021-04-30 17:38:51 -03:00
{
2025-11-07 21:10:27 -03:00
if ( type . limits ( ) . min ( ) > Constants : : max_allowed_table_size )
return { } ;
2021-04-30 17:38:51 -03:00
TableAddress address { m_tables . size ( ) } ;
2024-05-31 21:14:49 -03:00
Vector < Reference > elements ;
2024-08-17 19:40:21 -03:00
elements . ensure_capacity ( type . limits ( ) . min ( ) ) ;
for ( size_t i = 0 ; i < type . limits ( ) . min ( ) ; i + + )
elements . append ( Wasm : : Reference { Wasm : : Reference : : Null { type . element_type ( ) } } ) ;
2021-04-30 17:38:51 -03:00
elements . resize ( type . limits ( ) . min ( ) ) ;
m_tables . empend ( TableInstance { type , move ( elements ) } ) ;
return address ;
}
2021-06-03 20:12:11 -03:00
Optional < MemoryAddress > Store : : allocate ( MemoryType const & type )
2021-04-30 17:38:51 -03:00
{
MemoryAddress address { m_memories . size ( ) } ;
2022-02-14 20:35:49 -03:00
auto instance = MemoryInstance : : create ( type ) ;
if ( instance . is_error ( ) )
return { } ;
2026-04-04 14:26:41 -03:00
m_memories . append ( make < MemoryInstance > ( instance . release_value ( ) ) ) ;
2021-04-30 17:38:51 -03:00
return address ;
}
2021-06-03 20:12:11 -03:00
Optional < GlobalAddress > Store : : allocate ( GlobalType const & type , Value value )
2021-04-30 17:38:51 -03:00
{
GlobalAddress address { m_globals . size ( ) } ;
2024-08-04 12:06:50 -03:00
m_globals . append ( GlobalInstance { value , type . is_mutable ( ) , type . type ( ) } ) ;
2021-04-30 17:38:51 -03:00
return address ;
}
2021-12-04 11:26:58 -03:00
Optional < DataAddress > Store : : allocate_data ( Vector < u8 > initializer )
{
DataAddress address { m_datas . size ( ) } ;
m_datas . append ( DataInstance { move ( initializer ) } ) ;
return address ;
}
2021-06-03 20:12:11 -03:00
Optional < ElementAddress > Store : : allocate ( ValueType const & type , Vector < Reference > references )
2021-06-03 20:00:09 -03:00
{
ElementAddress address { m_elements . size ( ) } ;
m_elements . append ( ElementInstance { type , move ( references ) } ) ;
return address ;
}
2025-09-24 22:35:34 -03:00
Optional < TagAddress > Store : : allocate ( FunctionType const & type , TagType : : Flags flags )
{
TagAddress address { m_tags . size ( ) } ;
m_tags . append ( { type , flags } ) ;
return address ;
}
Optional < ExceptionAddress > Store : : allocate ( TagInstance const & tag_instance , Vector < Value > params )
{
ExceptionAddress address { m_exceptions . size ( ) } ;
m_exceptions . append ( ExceptionInstance { tag_instance , move ( params ) } ) ;
return address ;
}
2021-04-30 17:38:51 -03:00
FunctionInstance * Store : : get ( FunctionAddress address )
{
auto value = address . value ( ) ;
if ( m_functions . size ( ) < = value )
return nullptr ;
2026-04-13 20:36:28 -03:00
auto & instance = m_functions [ value ] ;
if ( auto const * wasm = instance . get_pointer < WasmFunction > ( ) ) {
if ( ! wasm - > try_module ( ) )
return nullptr ;
}
return & instance ;
2021-04-30 17:38:51 -03:00
}
2024-08-21 20:13:37 -03:00
Module const * Store : : get_module_for ( Wasm : : FunctionAddress address )
{
auto * function = get ( address ) ;
if ( ! function | | function - > has < HostFunction > ( ) )
return nullptr ;
return function - > get < WasmFunction > ( ) . module_ref ( ) . ptr ( ) ;
}
2026-04-13 20:36:28 -03:00
RefPtr < ModuleInstance const > Store : : get_module_instance_for ( FunctionAddress address )
{
auto * function = get ( address ) ;
if ( ! function | | function - > has < HostFunction > ( ) )
return nullptr ;
return function - > get < WasmFunction > ( ) . try_module ( ) ;
}
2021-04-30 17:38:51 -03:00
TableInstance * Store : : get ( TableAddress address )
{
auto value = address . value ( ) ;
if ( m_tables . size ( ) < = value )
return nullptr ;
return & m_tables [ value ] ;
}
MemoryInstance * Store : : get ( MemoryAddress address )
{
auto value = address . value ( ) ;
if ( m_memories . size ( ) < = value )
return nullptr ;
2026-04-04 14:26:41 -03:00
return m_memories [ value ] . ptr ( ) ;
2021-04-30 17:38:51 -03:00
}
GlobalInstance * Store : : get ( GlobalAddress address )
{
auto value = address . value ( ) ;
if ( m_globals . size ( ) < = value )
return nullptr ;
return & m_globals [ value ] ;
}
2021-06-03 20:00:09 -03:00
ElementInstance * Store : : get ( ElementAddress address )
{
auto value = address . value ( ) ;
if ( m_elements . size ( ) < = value )
return nullptr ;
return & m_elements [ value ] ;
}
2021-12-04 11:26:58 -03:00
DataInstance * Store : : get ( DataAddress address )
{
auto value = address . value ( ) ;
if ( m_datas . size ( ) < = value )
return nullptr ;
return & m_datas [ value ] ;
}
2025-09-24 22:35:34 -03:00
TagInstance * Store : : get ( TagAddress address )
{
auto value = address . value ( ) ;
if ( m_tags . size ( ) < = value )
return nullptr ;
return & m_tags [ value ] ;
}
ExceptionInstance * Store : : get ( ExceptionAddress address )
{
auto value = address . value ( ) ;
if ( m_exceptions . size ( ) < = value )
return nullptr ;
return & m_exceptions [ value ] ;
}
2026-06-02 11:59:39 -03:00
ErrorOr < void , ValidationError > AbstractMachine : : validate ( Module & module , Optional < CompileCacheConfig > cache_config , CompileToNative compile_to_native )
2021-10-31 19:06:35 -03:00
{
if ( module . validation_status ( ) ! = Module : : ValidationStatus : : Unchecked ) {
if ( module . validation_status ( ) = = Module : : ValidationStatus : : Valid )
return { } ;
return ValidationError { module . validation_error ( ) } ;
}
2026-05-14 10:32:18 -03:00
Validator validator ;
auto result = validator . validate ( module ) ;
2021-10-31 19:06:35 -03:00
if ( result . is_error ( ) ) {
module . set_validation_error ( result . error ( ) . error_string ) ;
return result . release_error ( ) ;
}
2026-06-04 09:17:57 -03:00
if ( compile_to_native = = CompileToNative : : Yes & & module . try_begin_cranelift_compilation ( ) ) {
if ( cache_config . has_value ( ) )
module . set_cranelift_cache_config ( cache_config . release_value ( ) ) ;
compile_module_to_native ( module ) ;
module . finish_cranelift_compilation ( ) ;
}
2021-10-31 19:06:35 -03:00
return { } ;
}
2021-06-03 20:12:11 -03:00
InstantiationResult AbstractMachine : : instantiate ( Module const & module , Vector < ExternValue > externs )
2021-04-30 17:38:51 -03:00
{
2021-10-31 19:06:35 -03:00
if ( auto result = validate ( const_cast < Module & > ( module ) ) ; result . is_error ( ) )
2023-12-16 11:19:34 -03:00
return InstantiationError { ByteString : : formatted ( " Validation failed: {} " , result . error ( ) ) } ;
2021-10-31 19:06:35 -03:00
2026-04-13 20:36:28 -03:00
auto main_module_instance_pointer = adopt_ref ( * new ModuleInstance ) ;
2026-01-23 08:30:50 -03:00
main_module_instance_pointer - > cached_minimum_call_record_allocation_size = module . minimum_call_record_allocation_size ( ) ;
2021-05-10 21:14:59 -03:00
auto & main_module_instance = * main_module_instance_pointer ;
2021-04-30 17:38:51 -03:00
2024-07-29 23:56:00 -03:00
main_module_instance . types ( ) = module . type_section ( ) . types ( ) ;
2021-04-30 17:38:51 -03:00
Vector < Value > global_values ;
2021-06-03 20:00:09 -03:00
Vector < Vector < Reference > > elements ;
2026-04-13 20:36:28 -03:00
auto auxiliary_instance_ptr = adopt_ref ( * new ModuleInstance ) ;
auto & auxiliary_instance = * auxiliary_instance_ptr ;
2021-04-30 17:38:51 -03:00
2026-01-23 08:30:50 -03:00
auxiliary_instance . cached_minimum_call_record_allocation_size = module . minimum_call_record_allocation_size ( ) ;
2024-07-29 23:56:00 -03:00
for ( auto [ i , import_ ] : enumerate ( module . import_section ( ) . imports ( ) ) ) {
auto extern_ = externs . at ( i ) ;
auto invalid = import_ . description ( ) . visit (
[ & ] ( MemoryType const & mem_type ) - > Optional < ByteString > {
if ( ! extern_ . has < MemoryAddress > ( ) )
return " Expected memory import " sv ;
auto other_mem_type = m_store . get ( extern_ . get < MemoryAddress > ( ) ) - > type ( ) ;
if ( other_mem_type . limits ( ) . is_subset_of ( mem_type . limits ( ) ) )
2024-07-16 12:47:21 -03:00
return { } ;
2024-07-29 23:56:00 -03:00
return ByteString : : formatted ( " Memory import and extern do not match: {}-{} vs {}-{} " , mem_type . limits ( ) . min ( ) , mem_type . limits ( ) . max ( ) , other_mem_type . limits ( ) . min ( ) , other_mem_type . limits ( ) . max ( ) ) ;
} ,
[ & ] ( TableType const & table_type ) - > Optional < ByteString > {
if ( ! extern_ . has < TableAddress > ( ) )
return " Expected table import " sv ;
auto other_table_type = m_store . get ( extern_ . get < TableAddress > ( ) ) - > type ( ) ;
if ( table_type . element_type ( ) = = other_table_type . element_type ( )
& & other_table_type . limits ( ) . is_subset_of ( table_type . limits ( ) ) )
2024-07-16 12:47:21 -03:00
return { } ;
2024-06-10 19:41:47 -03:00
2024-07-29 23:56:00 -03:00
return ByteString : : formatted ( " Table import and extern do not match: {}-{} vs {}-{} " , table_type . limits ( ) . min ( ) , table_type . limits ( ) . max ( ) , other_table_type . limits ( ) . min ( ) , other_table_type . limits ( ) . max ( ) ) ;
} ,
[ & ] ( GlobalType const & global_type ) - > Optional < ByteString > {
if ( ! extern_ . has < GlobalAddress > ( ) )
return " Expected global import " sv ;
auto other_global_type = m_store . get ( extern_ . get < GlobalAddress > ( ) ) - > type ( ) ;
if ( global_type . type ( ) = = other_global_type . type ( )
& & global_type . is_mutable ( ) = = other_global_type . is_mutable ( ) )
return { } ;
return " Global import and extern do not match " sv ;
} ,
[ & ] ( FunctionType const & type ) - > Optional < ByteString > {
if ( ! extern_ . has < FunctionAddress > ( ) )
return " Expected function import " sv ;
auto other_type = m_store . get ( extern_ . get < FunctionAddress > ( ) ) - > visit ( [ & ] ( WasmFunction const & wasm_func ) { return wasm_func . type ( ) ; } , [ & ] ( HostFunction const & host_func ) { return host_func . type ( ) ; } ) ;
if ( type . results ( ) ! = other_type . results ( ) )
return ByteString : : formatted ( " Function import and extern do not match, results: {} vs {} " , type . results ( ) , other_type . results ( ) ) ;
if ( type . parameters ( ) ! = other_type . parameters ( ) )
return ByteString : : formatted ( " Function import and extern do not match, parameters: {} vs {} " , type . parameters ( ) , other_type . parameters ( ) ) ;
return { } ;
} ,
2025-09-24 22:35:34 -03:00
[ & ] ( TagType const & type ) - > Optional < ByteString > {
if ( ! extern_ . has < TagAddress > ( ) )
return " Expected tag import " sv ;
auto other_tag_instance = m_store . get ( extern_ . get < TagAddress > ( ) ) ;
if ( other_tag_instance - > flags ( ) ! = type . flags ( ) )
return " Tag import and extern do not match " sv ;
auto & this_type = module . type_section ( ) . types ( ) [ type . type ( ) . value ( ) ] ;
2026-02-02 13:44:20 -03:00
if ( other_tag_instance - > type ( ) . parameters ( ) ! = this_type . function ( ) . parameters ( ) )
2025-09-24 22:35:34 -03:00
return " Tag import and extern do not match " sv ;
return { } ;
} ,
2024-07-29 23:56:00 -03:00
[ & ] ( TypeIndex type_index ) - > Optional < ByteString > {
if ( ! extern_ . has < FunctionAddress > ( ) )
return " Expected function import " sv ;
auto other_type = m_store . get ( extern_ . get < FunctionAddress > ( ) ) - > visit ( [ & ] ( WasmFunction const & wasm_func ) { return wasm_func . type ( ) ; } , [ & ] ( HostFunction const & host_func ) { return host_func . type ( ) ; } ) ;
2026-02-02 13:44:20 -03:00
auto & type = module . type_section ( ) . types ( ) [ type_index . value ( ) ] . function ( ) ;
2024-07-29 23:56:00 -03:00
if ( type . results ( ) ! = other_type . results ( ) )
return ByteString : : formatted ( " Function import and extern do not match, results: {} vs {} " , type . results ( ) , other_type . results ( ) ) ;
if ( type . parameters ( ) ! = other_type . parameters ( ) )
return ByteString : : formatted ( " Function import and extern do not match, parameters: {} vs {} " , type . parameters ( ) , other_type . parameters ( ) ) ;
return { } ;
} ) ;
if ( invalid . has_value ( ) )
return InstantiationError { ByteString : : formatted ( " {}::{}: {} " , import_ . module ( ) , import_ . name ( ) , invalid . release_value ( ) ) } ;
}
2021-04-30 17:38:51 -03:00
for ( auto & entry : externs ) {
if ( auto * ptr = entry . get_pointer < GlobalAddress > ( ) )
auxiliary_instance . globals ( ) . append ( * ptr ) ;
2024-06-16 13:55:51 -03:00
else if ( auto * ptr = entry . get_pointer < FunctionAddress > ( ) )
auxiliary_instance . functions ( ) . append ( * ptr ) ;
2021-04-30 17:38:51 -03:00
}
2024-07-27 20:44:36 -03:00
Vector < FunctionAddress > module_functions ;
2024-07-29 23:56:00 -03:00
module_functions . ensure_capacity ( module . function_section ( ) . types ( ) . size ( ) ) ;
size_t i = 0 ;
for ( auto & code : module . code_section ( ) . functions ( ) ) {
auto type_index = module . function_section ( ) . types ( ) [ i ] ;
2024-08-21 20:13:37 -03:00
auto address = m_store . allocate ( main_module_instance , module , code , type_index ) ;
2024-07-29 23:56:00 -03:00
VERIFY ( address . has_value ( ) ) ;
auxiliary_instance . functions ( ) . append ( * address ) ;
module_functions . append ( * address ) ;
+ + i ;
}
2023-07-08 07:20:40 -03:00
2023-05-28 07:13:43 -03:00
BytecodeInterpreter interpreter ( m_stack_info ) ;
2025-04-22 04:48:26 -03:00
auto handle = register_scoped ( interpreter ) ;
2021-05-23 18:34:58 -03:00
2024-07-29 23:56:00 -03:00
for ( auto & entry : module . global_section ( ) . entries ( ) ) {
Configuration config { m_store } ;
if ( m_should_limit_instruction_count )
config . enable_instruction_count_limit ( ) ;
2025-12-03 23:06:50 -03:00
config . set_frame ( IsTailcall : : No ,
2024-07-29 23:56:00 -03:00
auxiliary_instance ,
2025-12-03 23:06:50 -03:00
Vector < Value , ArgumentsStaticSize > { } ,
2024-07-29 23:56:00 -03:00
entry . expression ( ) ,
2026-04-04 14:26:41 -03:00
1u z ) ;
2025-04-22 04:48:26 -03:00
auto result = config . execute ( interpreter ) ;
2024-07-29 23:56:00 -03:00
if ( result . is_trap ( ) )
2025-04-22 04:48:26 -03:00
return InstantiationError { " Global instantiation trapped " , move ( result . trap ( ) ) } ;
2024-07-29 23:56:00 -03:00
global_values . append ( result . values ( ) . first ( ) ) ;
2026-04-13 20:36:28 -03:00
auto addr = m_store . allocate ( entry . type ( ) , result . values ( ) . first ( ) ) . release_value ( ) ;
auxiliary_instance . globals ( ) . append ( addr ) ;
2024-07-29 23:56:00 -03:00
}
if ( auto result = allocate_all_initial_phase ( module , main_module_instance , externs , global_values , module_functions ) ; result . has_value ( ) )
return result . release_value ( ) ;
for ( auto & segment : module . element_section ( ) . segments ( ) ) {
Vector < Reference > references ;
for ( auto & entry : segment . init ) {
2021-04-30 17:38:51 -03:00
Configuration config { m_store } ;
2021-07-14 16:30:45 -03:00
if ( m_should_limit_instruction_count )
config . enable_instruction_count_limit ( ) ;
2025-12-03 23:06:50 -03:00
config . set_frame ( IsTailcall : : No ,
2025-09-24 07:19:23 -03:00
main_module_instance ,
2025-12-03 23:06:50 -03:00
Vector < Value , ArgumentsStaticSize > { } ,
2024-07-29 23:56:00 -03:00
entry ,
2025-12-03 23:06:50 -03:00
entry . instructions ( ) . size ( ) - 1 ) ;
2025-04-22 04:48:26 -03:00
auto result = config . execute ( interpreter ) ;
2021-04-30 17:38:51 -03:00
if ( result . is_trap ( ) )
2025-04-22 04:48:26 -03:00
return InstantiationError { " Element section initialisation trapped " , move ( result . trap ( ) ) } ;
2021-04-30 17:38:51 -03:00
2024-07-29 23:56:00 -03:00
for ( auto & value : result . values ( ) ) {
auto reference = value . to < Reference > ( ) ;
2024-08-04 12:06:50 -03:00
references . append ( reference ) ;
2024-07-29 23:56:00 -03:00
}
}
elements . append ( move ( references ) ) ;
}
2021-06-03 20:00:09 -03:00
2024-07-29 23:56:00 -03:00
if ( auto result = allocate_all_final_phase ( module , main_module_instance , elements ) ; result . has_value ( ) )
2021-05-10 08:10:49 -03:00
return result . release_value ( ) ;
2021-04-30 17:38:51 -03:00
2024-07-29 23:56:00 -03:00
size_t index = 0 ;
for ( auto & segment : module . element_section ( ) . segments ( ) ) {
auto current_index = index ;
+ + index ;
auto active_ptr = segment . mode . get_pointer < ElementSection : : Active > ( ) ;
auto elem_instance = m_store . get ( main_module_instance . elements ( ) [ current_index ] ) ;
if ( ! active_ptr ) {
if ( segment . mode . has < ElementSection : : Declarative > ( ) )
* elem_instance = ElementInstance ( elem_instance - > type ( ) , { } ) ;
continue ;
}
Configuration config { m_store } ;
if ( m_should_limit_instruction_count )
config . enable_instruction_count_limit ( ) ;
2025-12-03 23:06:50 -03:00
config . set_frame ( IsTailcall : : No ,
2025-09-24 07:19:23 -03:00
main_module_instance ,
2025-12-03 23:06:50 -03:00
Vector < Value , ArgumentsStaticSize > { } ,
2024-07-29 23:56:00 -03:00
active_ptr - > expression ,
2026-04-04 14:26:41 -03:00
1u z ) ;
2025-04-22 04:48:26 -03:00
auto result = config . execute ( interpreter ) ;
2024-07-29 23:56:00 -03:00
if ( result . is_trap ( ) )
2025-04-22 04:48:26 -03:00
return InstantiationError { " Element section initialisation trapped " , move ( result . trap ( ) ) } ;
2024-07-29 23:56:00 -03:00
auto d = result . values ( ) . first ( ) . to < i32 > ( ) ;
auto table_instance = m_store . get ( main_module_instance . tables ( ) [ active_ptr - > index . value ( ) ] ) ;
if ( current_index > = main_module_instance . elements ( ) . size ( ) )
return InstantiationError { " Invalid element referenced by active element segment " } ;
if ( ! table_instance | | ! elem_instance )
return InstantiationError { " Invalid element referenced by active element segment " } ;
2026-03-21 10:42:32 -03:00
auto total_size = saturating_add ( elem_instance - > references ( ) . size ( ) , static_cast < size_t > ( d ) ) ;
2024-07-29 23:56:00 -03:00
2026-03-21 10:42:32 -03:00
if ( total_size > table_instance - > elements ( ) . size ( ) )
2024-07-29 23:56:00 -03:00
return InstantiationError { " Table instantiation out of bounds " } ;
size_t i = 0 ;
2026-04-13 20:36:28 -03:00
for ( auto it = elem_instance - > references ( ) . begin ( ) ; it < elem_instance - > references ( ) . end ( ) ; + + i , + + it ) {
RefPtr < ModuleInstance const > anchor ;
if ( auto const * func = it - > ref ( ) . template get_pointer < Reference : : Func > ( ) )
anchor = m_store . get_module_instance_for ( func - > address ) ;
table_instance - > set_element ( i + d , * it , move ( anchor ) ) ;
}
2024-07-29 23:56:00 -03:00
// Drop element
* m_store . get ( main_module_instance . elements ( ) [ current_index ] ) = ElementInstance ( elem_instance - > type ( ) , { } ) ;
}
for ( auto & segment : module . data_section ( ) . data ( ) ) {
Optional < InstantiationError > result = segment . value ( ) . visit (
[ & ] ( DataSection : : Data : : Active const & data ) - > Optional < InstantiationError > {
2021-06-03 20:00:09 -03:00
Configuration config { m_store } ;
2021-07-14 16:30:45 -03:00
if ( m_should_limit_instruction_count )
config . enable_instruction_count_limit ( ) ;
2025-12-03 23:06:50 -03:00
config . set_frame ( IsTailcall : : No ,
2025-09-24 07:19:23 -03:00
main_module_instance ,
2025-12-03 23:06:50 -03:00
Vector < Value , ArgumentsStaticSize > { } ,
2024-07-29 23:56:00 -03:00
data . offset ,
2026-04-04 14:26:41 -03:00
1u z ) ;
2025-04-22 04:48:26 -03:00
auto result = config . execute ( interpreter ) ;
2024-07-29 23:56:00 -03:00
if ( result . is_trap ( ) )
2025-04-22 04:48:26 -03:00
return InstantiationError { " Data section initialisation trapped " , move ( result . trap ( ) ) } ;
2024-08-04 12:06:50 -03:00
size_t offset = result . values ( ) . first ( ) . to < u64 > ( ) ;
2024-07-29 23:56:00 -03:00
if ( main_module_instance . memories ( ) . size ( ) < = data . index . value ( ) ) {
return InstantiationError {
ByteString : : formatted ( " Data segment referenced out-of-bounds memory ({}) of max {} entries " ,
data . index . value ( ) , main_module_instance . memories ( ) . size ( ) )
} ;
2021-06-03 20:00:09 -03:00
}
2024-07-29 23:56:00 -03:00
auto maybe_data_address = m_store . allocate_data ( data . init ) ;
if ( ! maybe_data_address . has_value ( ) ) {
return InstantiationError { " Failed to allocate a data instance for an active data segment " sv } ;
2021-06-03 20:00:09 -03:00
}
2024-07-29 23:56:00 -03:00
main_module_instance . datas ( ) . append ( * maybe_data_address ) ;
auto address = main_module_instance . memories ( ) [ data . index . value ( ) ] ;
auto instance = m_store . get ( address ) ;
Checked < size_t > checked_offset = data . init . size ( ) ;
checked_offset + = offset ;
if ( checked_offset . has_overflow ( ) | | checked_offset > instance - > size ( ) ) {
return InstantiationError {
ByteString : : formatted ( " Data segment attempted to write to out-of-bounds memory ({}) in memory of size {} " ,
offset , instance - > size ( ) )
} ;
}
if ( ! data . init . is_empty ( ) )
2024-06-01 16:56:37 -03:00
instance - > data ( ) . overwrite ( offset , data . init . data ( ) , data . init . size ( ) ) ;
2024-07-29 23:56:00 -03:00
return { } ;
} ,
[ & ] ( DataSection : : Data : : Passive const & passive ) - > Optional < InstantiationError > {
auto maybe_data_address = m_store . allocate_data ( passive . init ) ;
if ( ! maybe_data_address . has_value ( ) ) {
return InstantiationError { " Failed to allocate a data instance for a passive data segment " sv } ;
}
main_module_instance . datas ( ) . append ( * maybe_data_address ) ;
return { } ;
} ) ;
if ( result . has_value ( ) )
return result . release_value ( ) ;
}
2021-04-30 17:38:51 -03:00
2024-07-29 23:56:00 -03:00
if ( module . start_section ( ) . function ( ) . has_value ( ) ) {
2021-05-10 08:10:49 -03:00
auto & functions = main_module_instance . functions ( ) ;
2024-07-29 23:56:00 -03:00
auto index = module . start_section ( ) . function ( ) - > index ( ) ;
2025-07-25 09:28:29 -03:00
if ( functions . size ( ) < = index . value ( ) )
2024-07-29 23:56:00 -03:00
return InstantiationError { ByteString : : formatted ( " Start section function referenced invalid index {} of max {} entries " , index . value ( ) , functions . size ( ) ) } ;
2024-06-16 11:11:49 -03:00
auto result = invoke ( functions [ index . value ( ) ] , { } ) ;
if ( result . is_trap ( ) )
2025-07-25 09:28:29 -03:00
return InstantiationError { " Start function trapped " , move ( result . trap ( ) ) , InstantiationErrorSource : : StartFunction } ;
2024-07-29 23:56:00 -03:00
}
2021-05-10 21:14:59 -03:00
return InstantiationResult { move ( main_module_instance_pointer ) } ;
2021-04-30 17:38:51 -03:00
}
2023-09-24 14:50:45 -03:00
Optional < InstantiationError > AbstractMachine : : allocate_all_initial_phase ( Module const & module , ModuleInstance & module_instance , Vector < ExternValue > & externs , Vector < Value > & global_values , Vector < FunctionAddress > & own_functions )
2021-04-30 17:38:51 -03:00
{
2021-05-10 08:10:49 -03:00
Optional < InstantiationError > result ;
2021-04-30 17:38:51 -03:00
for ( auto & entry : externs ) {
entry . visit (
2021-06-03 20:12:11 -03:00
[ & ] ( FunctionAddress const & address ) { module_instance . functions ( ) . append ( address ) ; } ,
[ & ] ( TableAddress const & address ) { module_instance . tables ( ) . append ( address ) ; } ,
[ & ] ( MemoryAddress const & address ) { module_instance . memories ( ) . append ( address ) ; } ,
2025-09-24 22:35:34 -03:00
[ & ] ( GlobalAddress const & address ) { module_instance . globals ( ) . append ( address ) ; } ,
[ & ] ( TagAddress const & address ) { module_instance . tags ( ) . append ( address ) ; } ) ;
2021-04-30 17:38:51 -03:00
}
2023-09-24 14:50:45 -03:00
module_instance . functions ( ) . extend ( own_functions ) ;
2021-04-30 17:38:51 -03:00
// FIXME: What if this fails?
2024-07-29 23:56:00 -03:00
for ( auto & table : module . table_section ( ) . tables ( ) ) {
auto table_address = m_store . allocate ( table . type ( ) ) ;
2026-04-13 20:36:28 -03:00
if ( table_address . has_value ( ) ) {
2025-11-07 21:10:27 -03:00
module_instance . tables ( ) . append ( * table_address ) ;
2026-04-13 20:36:28 -03:00
}
2024-07-29 23:56:00 -03:00
}
2021-04-30 17:38:51 -03:00
2024-07-29 23:56:00 -03:00
for ( auto & memory : module . memory_section ( ) . memories ( ) ) {
auto memory_address = m_store . allocate ( memory . type ( ) ) ;
2026-04-13 20:36:28 -03:00
if ( memory_address . has_value ( ) ) {
2025-11-07 21:10:27 -03:00
module_instance . memories ( ) . append ( * memory_address ) ;
2026-04-13 20:36:28 -03:00
}
2024-07-29 23:56:00 -03:00
}
2021-04-30 17:38:51 -03:00
2024-07-29 23:56:00 -03:00
size_t index = 0 ;
for ( auto & entry : module . global_section ( ) . entries ( ) ) {
auto address = m_store . allocate ( entry . type ( ) , move ( global_values [ index ] ) ) ;
VERIFY ( address . has_value ( ) ) ;
module_instance . globals ( ) . append ( * address ) ;
index + + ;
}
2021-04-30 17:38:51 -03:00
2025-09-24 22:35:34 -03:00
for ( auto & entry : module . tag_section ( ) . tags ( ) ) {
auto & type = module . type_section ( ) . types ( ) [ entry . type ( ) . value ( ) ] ;
2026-02-02 13:44:20 -03:00
auto address = m_store . allocate ( type . function ( ) , entry . flags ( ) ) ;
2025-09-24 22:35:34 -03:00
VERIFY ( address . has_value ( ) ) ;
module_instance . tags ( ) . append ( * address ) ;
}
2024-07-29 23:56:00 -03:00
for ( auto & entry : module . export_section ( ) . entries ( ) ) {
2025-09-24 22:35:34 -03:00
Variant < FunctionAddress , TableAddress , MemoryAddress , GlobalAddress , TagAddress , Empty > address { } ;
2024-07-29 23:56:00 -03:00
entry . description ( ) . visit (
[ & ] ( FunctionIndex const & index ) {
if ( module_instance . functions ( ) . size ( ) > index . value ( ) )
address = FunctionAddress { module_instance . functions ( ) [ index . value ( ) ] } ;
else
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . functions ( ) . size ( ) ) ;
} ,
[ & ] ( TableIndex const & index ) {
if ( module_instance . tables ( ) . size ( ) > index . value ( ) )
address = TableAddress { module_instance . tables ( ) [ index . value ( ) ] } ;
else
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . tables ( ) . size ( ) ) ;
} ,
[ & ] ( MemoryIndex const & index ) {
if ( module_instance . memories ( ) . size ( ) > index . value ( ) )
address = MemoryAddress { module_instance . memories ( ) [ index . value ( ) ] } ;
else
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . memories ( ) . size ( ) ) ;
} ,
[ & ] ( GlobalIndex const & index ) {
if ( module_instance . globals ( ) . size ( ) > index . value ( ) )
address = GlobalAddress { module_instance . globals ( ) [ index . value ( ) ] } ;
else
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . globals ( ) . size ( ) ) ;
2025-09-24 22:35:34 -03:00
} ,
[ & ] ( TagIndex const & index ) {
if ( module_instance . tags ( ) . size ( ) > index . value ( ) )
address = TagAddress { module_instance . tags ( ) [ index . value ( ) ] } ;
else
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . tags ( ) . size ( ) ) ;
2021-04-30 17:38:51 -03:00
} ) ;
2024-07-29 23:56:00 -03:00
if ( address . has < Empty > ( ) ) {
result = InstantiationError { " An export could not be resolved " } ;
continue ;
2021-04-30 17:38:51 -03:00
}
2024-07-29 23:56:00 -03:00
module_instance . exports ( ) . append ( ExportInstance {
entry . name ( ) ,
2025-09-24 22:35:34 -03:00
move ( address ) . downcast < FunctionAddress , TableAddress , MemoryAddress , GlobalAddress , TagAddress > ( ) ,
2024-07-29 23:56:00 -03:00
} ) ;
}
2021-04-30 17:38:51 -03:00
2021-05-10 08:10:49 -03:00
return result ;
2021-04-30 17:38:51 -03:00
}
2021-06-03 20:12:11 -03:00
Optional < InstantiationError > AbstractMachine : : allocate_all_final_phase ( Module const & module , ModuleInstance & module_instance , Vector < Vector < Reference > > & elements )
2021-06-03 20:00:09 -03:00
{
2024-07-29 23:56:00 -03:00
size_t index = 0 ;
for ( auto & segment : module . element_section ( ) . segments ( ) ) {
auto address = m_store . allocate ( segment . type , move ( elements [ index ] ) ) ;
VERIFY ( address . has_value ( ) ) ;
module_instance . elements ( ) . append ( * address ) ;
index + + ;
}
2021-06-03 20:00:09 -03:00
return { } ;
}
2021-04-30 17:38:51 -03:00
Result AbstractMachine : : invoke ( FunctionAddress address , Vector < Value > arguments )
2021-05-23 18:34:58 -03:00
{
2023-05-28 07:13:43 -03:00
BytecodeInterpreter interpreter ( m_stack_info ) ;
2025-04-22 04:48:26 -03:00
auto handle = register_scoped ( interpreter ) ;
2021-05-23 18:34:58 -03:00
return invoke ( interpreter , address , move ( arguments ) ) ;
}
Result AbstractMachine : : invoke ( Interpreter & interpreter , FunctionAddress address , Vector < Value > arguments )
2021-04-30 17:38:51 -03:00
{
2021-05-21 13:40:44 -03:00
Configuration configuration { m_store } ;
2021-07-14 16:30:45 -03:00
if ( m_should_limit_instruction_count )
configuration . enable_instruction_count_limit ( ) ;
2025-12-03 23:06:50 -03:00
Vector < Value , ArgumentsStaticSize > args = move ( arguments ) ;
return configuration . call ( interpreter , address , args ) ;
2021-04-30 17:38:51 -03:00
}
2021-06-03 20:12:11 -03:00
void Linker : : link ( ModuleInstance const & instance )
2021-05-10 09:56:17 -03:00
{
populate ( ) ;
if ( m_unresolved_imports . is_empty ( ) )
return ;
HashTable < Name > resolved_imports ;
for ( auto & import_ : m_unresolved_imports ) {
auto it = instance . exports ( ) . find_if ( [ & ] ( auto & export_ ) { return export_ . name ( ) = = import_ . name ; } ) ;
if ( ! it . is_end ( ) ) {
resolved_imports . set ( import_ ) ;
m_resolved_imports . set ( import_ , it - > value ( ) ) ;
}
}
for ( auto & entry : resolved_imports )
m_unresolved_imports . remove ( entry ) ;
}
2021-06-03 20:12:11 -03:00
void Linker : : link ( HashMap < Linker : : Name , ExternValue > const & exports )
2021-05-10 09:56:17 -03:00
{
populate ( ) ;
if ( m_unresolved_imports . is_empty ( ) )
return ;
2021-06-09 13:01:07 -03:00
if ( exports . is_empty ( ) )
return ;
2021-05-10 09:56:17 -03:00
HashTable < Name > resolved_imports ;
for ( auto & import_ : m_unresolved_imports ) {
auto export_ = exports . get ( import_ ) ;
if ( export_ . has_value ( ) ) {
resolved_imports . set ( import_ ) ;
m_resolved_imports . set ( import_ , export_ . value ( ) ) ;
}
}
for ( auto & entry : resolved_imports )
m_unresolved_imports . remove ( entry ) ;
}
2024-03-11 18:57:59 -03:00
AK : : ErrorOr < Vector < ExternValue > , LinkError > Linker : : finish ( )
2021-05-10 09:56:17 -03:00
{
populate ( ) ;
if ( ! m_unresolved_imports . is_empty ( ) ) {
if ( ! m_error . has_value ( ) )
m_error = LinkError { } ;
for ( auto & entry : m_unresolved_imports )
m_error - > missing_imports . append ( entry . name ) ;
return * m_error ;
}
if ( m_error . has_value ( ) )
return * m_error ;
// Result must be in the same order as the module imports
Vector < ExternValue > exports ;
exports . ensure_capacity ( m_ordered_imports . size ( ) ) ;
for ( auto & import_ : m_ordered_imports )
exports . unchecked_append ( * m_resolved_imports . get ( import_ ) ) ;
return exports ;
}
void Linker : : populate ( )
{
if ( ! m_ordered_imports . is_empty ( ) )
return ;
2024-07-29 23:56:00 -03:00
for ( auto & import_ : m_module . import_section ( ) . imports ( ) ) {
m_ordered_imports . append ( { import_ . module ( ) , import_ . name ( ) , import_ . description ( ) } ) ;
m_unresolved_imports . set ( m_ordered_imports . last ( ) ) ;
}
2021-05-10 09:56:17 -03:00
}
2025-04-22 04:48:26 -03:00
void AbstractMachine : : visit_external_resources ( HostVisitOps const & host )
{
for ( auto interpreter_ptr : m_active_interpreters )
interpreter_ptr - > visit_external_resources ( host ) ;
}
2025-05-13 08:06:33 -03:00
2021-04-30 17:38:51 -03:00
}