2021-05-01 01:08:51 +04:30
/*
* Copyright ( c ) 2021 , Ali Mohammad Pur < mpfard @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-06-10 15:41:47 -07:00
# include <AK/Enumerate.h>
2021-05-01 01:08:51 +04:30
# include <LibWasm/AbstractMachine/AbstractMachine.h>
2021-06-04 21:54:20 +10:00
# include <LibWasm/AbstractMachine/BytecodeInterpreter.h>
2021-05-01 01:08:51 +04:30
# include <LibWasm/AbstractMachine/Configuration.h>
2021-06-04 21:54:20 +10:00
# include <LibWasm/AbstractMachine/Interpreter.h>
2021-11-01 01:36:35 +03:30
# include <LibWasm/AbstractMachine/Validator.h>
2021-05-01 01:08:51 +04:30
# include <LibWasm/Types.h>
namespace Wasm {
2024-08-22 01:13:37 +02:00
Optional < FunctionAddress > Store : : allocate ( ModuleInstance & instance , Module const & module , CodeSection : : Code const & code , TypeIndex type_index )
2021-05-01 01:08:51 +04:30
{
FunctionAddress address { m_functions . size ( ) } ;
2024-12-08 19:58:50 +04:00
if ( type_index . value ( ) > = instance . types ( ) . size ( ) )
2021-05-01 01:08:51 +04:30
return { } ;
2024-08-22 01:13:37 +02:00
auto & type = instance . types ( ) [ type_index . value ( ) ] ;
m_functions . empend ( WasmFunction { type , instance , module , code } ) ;
2021-05-01 01:08:51 +04:30
return address ;
}
2021-05-17 12:29:44 +04:30
Optional < FunctionAddress > Store : : allocate ( HostFunction & & function )
2021-05-01 01:08:51 +04:30
{
FunctionAddress address { m_functions . size ( ) } ;
2021-05-17 12:29:44 +04:30
m_functions . empend ( HostFunction { move ( function ) } ) ;
2021-05-01 01:08:51 +04:30
return address ;
}
2021-06-04 03:42:11 +04:30
Optional < TableAddress > Store : : allocate ( TableType const & type )
2021-05-01 01:08:51 +04:30
{
TableAddress address { m_tables . size ( ) } ;
2024-05-31 17:14:49 -07:00
Vector < Reference > elements ;
2024-08-17 15:40:21 -07: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-05-01 01:08:51 +04:30
elements . resize ( type . limits ( ) . min ( ) ) ;
m_tables . empend ( TableInstance { type , move ( elements ) } ) ;
return address ;
}
2021-06-04 03:42:11 +04:30
Optional < MemoryAddress > Store : : allocate ( MemoryType const & type )
2021-05-01 01:08:51 +04:30
{
MemoryAddress address { m_memories . size ( ) } ;
2022-02-15 03:05:49 +03:30
auto instance = MemoryInstance : : create ( type ) ;
if ( instance . is_error ( ) )
return { } ;
m_memories . append ( instance . release_value ( ) ) ;
2021-05-01 01:08:51 +04:30
return address ;
}
2021-06-04 03:42:11 +04:30
Optional < GlobalAddress > Store : : allocate ( GlobalType const & type , Value value )
2021-05-01 01:08:51 +04:30
{
GlobalAddress address { m_globals . size ( ) } ;
2024-08-04 08:06:50 -07:00
m_globals . append ( GlobalInstance { value , type . is_mutable ( ) , type . type ( ) } ) ;
2021-05-01 01:08:51 +04:30
return address ;
}
2021-12-04 17:56:58 +03:30
Optional < DataAddress > Store : : allocate_data ( Vector < u8 > initializer )
{
DataAddress address { m_datas . size ( ) } ;
m_datas . append ( DataInstance { move ( initializer ) } ) ;
return address ;
}
2021-06-04 03:42:11 +04:30
Optional < ElementAddress > Store : : allocate ( ValueType const & type , Vector < Reference > references )
2021-06-04 03:30:09 +04:30
{
ElementAddress address { m_elements . size ( ) } ;
m_elements . append ( ElementInstance { type , move ( references ) } ) ;
return address ;
}
2021-05-01 01:08:51 +04:30
FunctionInstance * Store : : get ( FunctionAddress address )
{
auto value = address . value ( ) ;
if ( m_functions . size ( ) < = value )
return nullptr ;
return & m_functions [ value ] ;
}
2024-08-22 01:13:37 +02: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 ( ) ;
}
2021-05-01 01:08:51 +04:30
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 ;
return & m_memories [ value ] ;
}
GlobalInstance * Store : : get ( GlobalAddress address )
{
auto value = address . value ( ) ;
if ( m_globals . size ( ) < = value )
return nullptr ;
return & m_globals [ value ] ;
}
2021-06-04 03:30:09 +04:30
ElementInstance * Store : : get ( ElementAddress address )
{
auto value = address . value ( ) ;
if ( m_elements . size ( ) < = value )
return nullptr ;
return & m_elements [ value ] ;
}
2021-12-04 17:56:58 +03:30
DataInstance * Store : : get ( DataAddress address )
{
auto value = address . value ( ) ;
if ( m_datas . size ( ) < = value )
return nullptr ;
return & m_datas [ value ] ;
}
2021-11-01 01:36:35 +03:30
ErrorOr < void , ValidationError > AbstractMachine : : validate ( Module & module )
{
if ( module . validation_status ( ) ! = Module : : ValidationStatus : : Unchecked ) {
if ( module . validation_status ( ) = = Module : : ValidationStatus : : Valid )
return { } ;
return ValidationError { module . validation_error ( ) } ;
}
auto result = Validator { } . validate ( module ) ;
if ( result . is_error ( ) ) {
module . set_validation_error ( result . error ( ) . error_string ) ;
return result . release_error ( ) ;
}
return { } ;
}
2021-06-04 03:42:11 +04:30
InstantiationResult AbstractMachine : : instantiate ( Module const & module , Vector < ExternValue > externs )
2021-05-01 01:08:51 +04:30
{
2021-11-01 01:36:35 +03:30
if ( auto result = validate ( const_cast < Module & > ( module ) ) ; result . is_error ( ) )
2023-12-16 17:49:34 +03:30
return InstantiationError { ByteString : : formatted ( " Validation failed: {} " , result . error ( ) ) } ;
2021-11-01 01:36:35 +03:30
2021-05-11 04:44:59 +04:30
auto main_module_instance_pointer = make < ModuleInstance > ( ) ;
auto & main_module_instance = * main_module_instance_pointer ;
2021-05-01 01:08:51 +04:30
2024-07-29 19:56:00 -07:00
main_module_instance . types ( ) = module . type_section ( ) . types ( ) ;
2021-05-01 01:08:51 +04:30
Vector < Value > global_values ;
2021-06-04 03:30:09 +04:30
Vector < Vector < Reference > > elements ;
2021-05-01 01:08:51 +04:30
ModuleInstance auxiliary_instance ;
2024-07-29 19:56:00 -07: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 17:47:21 +02:00
return { } ;
2024-07-29 19:56:00 -07: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 17:47:21 +02:00
return { } ;
2024-06-10 15:41:47 -07:00
2024-07-29 19:56:00 -07: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 { } ;
} ,
[ & ] ( 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 ( ) ; } ) ;
auto & type = module . type_section ( ) . types ( ) [ type_index . value ( ) ] ;
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-05-01 01:08:51 +04:30
for ( auto & entry : externs ) {
if ( auto * ptr = entry . get_pointer < GlobalAddress > ( ) )
auxiliary_instance . globals ( ) . append ( * ptr ) ;
2024-06-16 09:55:51 -07:00
else if ( auto * ptr = entry . get_pointer < FunctionAddress > ( ) )
auxiliary_instance . functions ( ) . append ( * ptr ) ;
2021-05-01 01:08:51 +04:30
}
2024-07-27 16:44:36 -07:00
Vector < FunctionAddress > module_functions ;
2024-07-29 19:56:00 -07: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-22 01:13:37 +02:00
auto address = m_store . allocate ( main_module_instance , module , code , type_index ) ;
2024-07-29 19:56:00 -07:00
VERIFY ( address . has_value ( ) ) ;
auxiliary_instance . functions ( ) . append ( * address ) ;
module_functions . append ( * address ) ;
+ + i ;
}
2023-07-08 13:50:40 +03:30
2023-05-28 12:13:43 +02:00
BytecodeInterpreter interpreter ( m_stack_info ) ;
2025-04-22 09:48:26 +02:00
auto handle = register_scoped ( interpreter ) ;
2021-05-24 02:04:58 +04:30
2024-07-29 19:56:00 -07:00
for ( auto & entry : module . global_section ( ) . entries ( ) ) {
Configuration config { m_store } ;
if ( m_should_limit_instruction_count )
config . enable_instruction_count_limit ( ) ;
config . set_frame ( Frame {
auxiliary_instance ,
Vector < Value > { } ,
entry . expression ( ) ,
1 ,
} ) ;
2025-04-22 09:48:26 +02:00
auto result = config . execute ( interpreter ) ;
2024-07-29 19:56:00 -07:00
if ( result . is_trap ( ) )
2025-04-22 09:48:26 +02:00
return InstantiationError { " Global instantiation trapped " , move ( result . trap ( ) ) } ;
2024-07-29 19:56:00 -07:00
global_values . append ( result . values ( ) . first ( ) ) ;
}
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-05-01 01:08:51 +04:30
Configuration config { m_store } ;
2021-07-15 00:00:45 +04:30
if ( m_should_limit_instruction_count )
config . enable_instruction_count_limit ( ) ;
2021-05-23 21:42:19 +04:30
config . set_frame ( Frame {
auxiliary_instance ,
Vector < Value > { } ,
2024-07-29 19:56:00 -07:00
entry ,
entry . instructions ( ) . size ( ) ,
2021-05-23 21:42:19 +04:30
} ) ;
2025-04-22 09:48:26 +02:00
auto result = config . execute ( interpreter ) ;
2021-05-01 01:08:51 +04:30
if ( result . is_trap ( ) )
2025-04-22 09:48:26 +02:00
return InstantiationError { " Element section initialisation trapped " , move ( result . trap ( ) ) } ;
2021-05-01 01:08:51 +04:30
2024-07-29 19:56:00 -07:00
for ( auto & value : result . values ( ) ) {
auto reference = value . to < Reference > ( ) ;
2024-08-04 08:06:50 -07:00
references . append ( reference ) ;
2024-07-29 19:56:00 -07:00
}
}
elements . append ( move ( references ) ) ;
}
2021-06-04 03:30:09 +04:30
2024-07-29 19:56:00 -07:00
if ( auto result = allocate_all_final_phase ( module , main_module_instance , elements ) ; result . has_value ( ) )
2021-05-10 15:40:49 +04:30
return result . release_value ( ) ;
2021-05-01 01:08:51 +04:30
2024-07-29 19:56:00 -07: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 ( ) ;
config . set_frame ( Frame {
auxiliary_instance ,
Vector < Value > { } ,
active_ptr - > expression ,
1 ,
} ) ;
2025-04-22 09:48:26 +02:00
auto result = config . execute ( interpreter ) ;
2024-07-29 19:56:00 -07:00
if ( result . is_trap ( ) )
2025-04-22 09:48:26 +02:00
return InstantiationError { " Element section initialisation trapped " , move ( result . trap ( ) ) } ;
2024-07-29 19:56:00 -07: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 " } ;
Checked < size_t > total_size = elem_instance - > references ( ) . size ( ) ;
2024-08-04 08:06:50 -07:00
total_size . saturating_add ( d ) ;
2024-07-29 19:56:00 -07:00
if ( total_size . value ( ) > table_instance - > elements ( ) . size ( ) )
return InstantiationError { " Table instantiation out of bounds " } ;
size_t i = 0 ;
for ( auto it = elem_instance - > references ( ) . begin ( ) ; it < elem_instance - > references ( ) . end ( ) ; + + i , + + it )
2024-08-04 08:06:50 -07:00
table_instance - > elements ( ) [ i + d ] = * it ;
2024-07-29 19:56:00 -07: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-04 03:30:09 +04:30
Configuration config { m_store } ;
2021-07-15 00:00:45 +04:30
if ( m_should_limit_instruction_count )
config . enable_instruction_count_limit ( ) ;
2021-06-04 03:30:09 +04:30
config . set_frame ( Frame {
2024-06-16 09:55:51 -07:00
auxiliary_instance ,
2021-06-04 03:30:09 +04:30
Vector < Value > { } ,
2024-07-29 19:56:00 -07:00
data . offset ,
1 ,
2021-06-04 03:30:09 +04:30
} ) ;
2025-04-22 09:48:26 +02:00
auto result = config . execute ( interpreter ) ;
2024-07-29 19:56:00 -07:00
if ( result . is_trap ( ) )
2025-04-22 09:48:26 +02:00
return InstantiationError { " Data section initialisation trapped " , move ( result . trap ( ) ) } ;
2024-08-04 08:06:50 -07:00
size_t offset = result . values ( ) . first ( ) . to < u64 > ( ) ;
2024-07-29 19:56:00 -07: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-04 03:30:09 +04:30
}
2024-07-29 19:56:00 -07: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-04 03:30:09 +04:30
}
2024-07-29 19:56:00 -07: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 12:56:37 -07:00
instance - > data ( ) . overwrite ( offset , data . init . data ( ) , data . init . size ( ) ) ;
2024-07-29 19:56:00 -07: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-05-01 01:08:51 +04:30
2024-07-29 19:56:00 -07:00
if ( module . start_section ( ) . function ( ) . has_value ( ) ) {
2021-05-10 15:40:49 +04:30
auto & functions = main_module_instance . functions ( ) ;
2024-07-29 19:56:00 -07:00
auto index = module . start_section ( ) . function ( ) - > index ( ) ;
2021-05-03 22:45:16 +04:30
if ( functions . size ( ) < = index . value ( ) ) {
2024-07-29 19:56:00 -07:00
return InstantiationError { ByteString : : formatted ( " Start section function referenced invalid index {} of max {} entries " , index . value ( ) , functions . size ( ) ) } ;
2021-05-03 22:45:16 +04:30
}
2024-06-16 07:11:49 -07:00
auto result = invoke ( functions [ index . value ( ) ] , { } ) ;
if ( result . is_trap ( ) )
2025-04-22 09:48:26 +02:00
return InstantiationError { " Start function trapped " , move ( result . trap ( ) ) } ;
2024-07-29 19:56:00 -07:00
}
2021-05-11 04:44:59 +04:30
return InstantiationResult { move ( main_module_instance_pointer ) } ;
2021-05-01 01:08:51 +04:30
}
2023-09-24 21:20:45 +03:30
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-05-01 01:08:51 +04:30
{
2021-05-10 15:40:49 +04:30
Optional < InstantiationError > result ;
2021-05-01 01:08:51 +04:30
for ( auto & entry : externs ) {
entry . visit (
2021-06-04 03:42:11 +04:30
[ & ] ( FunctionAddress const & address ) { module_instance . functions ( ) . append ( address ) ; } ,
[ & ] ( TableAddress const & address ) { module_instance . tables ( ) . append ( address ) ; } ,
[ & ] ( MemoryAddress const & address ) { module_instance . memories ( ) . append ( address ) ; } ,
[ & ] ( GlobalAddress const & address ) { module_instance . globals ( ) . append ( address ) ; } ) ;
2021-05-01 01:08:51 +04:30
}
2023-09-24 21:20:45 +03:30
module_instance . functions ( ) . extend ( own_functions ) ;
2021-05-01 01:08:51 +04:30
// FIXME: What if this fails?
2024-07-29 19:56:00 -07:00
for ( auto & table : module . table_section ( ) . tables ( ) ) {
auto table_address = m_store . allocate ( table . type ( ) ) ;
VERIFY ( table_address . has_value ( ) ) ;
module_instance . tables ( ) . append ( * table_address ) ;
}
2021-05-01 01:08:51 +04:30
2024-07-29 19:56:00 -07:00
for ( auto & memory : module . memory_section ( ) . memories ( ) ) {
auto memory_address = m_store . allocate ( memory . type ( ) ) ;
VERIFY ( memory_address . has_value ( ) ) ;
module_instance . memories ( ) . append ( * memory_address ) ;
}
2021-05-01 01:08:51 +04:30
2024-07-29 19:56:00 -07: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-05-01 01:08:51 +04:30
2024-07-29 19:56:00 -07:00
for ( auto & entry : module . export_section ( ) . entries ( ) ) {
Variant < FunctionAddress , TableAddress , MemoryAddress , GlobalAddress , Empty > address { } ;
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 ( ) ) ;
2021-05-01 01:08:51 +04:30
} ) ;
2024-07-29 19:56:00 -07:00
if ( address . has < Empty > ( ) ) {
result = InstantiationError { " An export could not be resolved " } ;
continue ;
2021-05-01 01:08:51 +04:30
}
2024-07-29 19:56:00 -07:00
module_instance . exports ( ) . append ( ExportInstance {
entry . name ( ) ,
move ( address ) . downcast < FunctionAddress , TableAddress , MemoryAddress , GlobalAddress > ( ) ,
} ) ;
}
2021-05-01 01:08:51 +04:30
2021-05-10 15:40:49 +04:30
return result ;
2021-05-01 01:08:51 +04:30
}
2021-06-04 03:42:11 +04:30
Optional < InstantiationError > AbstractMachine : : allocate_all_final_phase ( Module const & module , ModuleInstance & module_instance , Vector < Vector < Reference > > & elements )
2021-06-04 03:30:09 +04:30
{
2024-07-29 19:56:00 -07: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-04 03:30:09 +04:30
return { } ;
}
2021-05-01 01:08:51 +04:30
Result AbstractMachine : : invoke ( FunctionAddress address , Vector < Value > arguments )
2021-05-24 02:04:58 +04:30
{
2023-05-28 12:13:43 +02:00
BytecodeInterpreter interpreter ( m_stack_info ) ;
2025-04-22 09:48:26 +02:00
auto handle = register_scoped ( interpreter ) ;
2021-05-24 02:04:58 +04:30
return invoke ( interpreter , address , move ( arguments ) ) ;
}
Result AbstractMachine : : invoke ( Interpreter & interpreter , FunctionAddress address , Vector < Value > arguments )
2021-05-01 01:08:51 +04:30
{
2021-05-21 21:10:44 +04:30
Configuration configuration { m_store } ;
2021-07-15 00:00:45 +04:30
if ( m_should_limit_instruction_count )
configuration . enable_instruction_count_limit ( ) ;
2021-05-24 02:04:58 +04:30
return configuration . call ( interpreter , address , move ( arguments ) ) ;
2021-05-01 01:08:51 +04:30
}
2021-06-04 03:42:11 +04:30
void Linker : : link ( ModuleInstance const & instance )
2021-05-10 17:26:17 +04:30
{
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-04 03:42:11 +04:30
void Linker : : link ( HashMap < Linker : : Name , ExternValue > const & exports )
2021-05-10 17:26:17 +04:30
{
populate ( ) ;
if ( m_unresolved_imports . is_empty ( ) )
return ;
2021-06-09 20:31:07 +04:30
if ( exports . is_empty ( ) )
return ;
2021-05-10 17:26:17 +04:30
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 22:57:59 +01:00
AK : : ErrorOr < Vector < ExternValue > , LinkError > Linker : : finish ( )
2021-05-10 17:26:17 +04:30
{
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 19:56:00 -07: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 17:26:17 +04:30
}
2025-04-22 09:48:26 +02:00
void AbstractMachine : : visit_external_resources ( HostVisitOps const & host )
{
for ( auto interpreter_ptr : m_active_interpreters )
interpreter_ptr - > visit_external_resources ( host ) ;
}
2021-05-01 01:08:51 +04:30
}