2021-05-01 01:08:51 +04:30
/*
* Copyright ( c ) 2021 , Ali Mohammad Pur < mpfard @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# 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 {
2021-06-04 03:42:11 +04:30
Optional < FunctionAddress > Store : : allocate ( ModuleInstance & module , Module : : Function const & function )
2021-05-01 01:08:51 +04:30
{
FunctionAddress address { m_functions . size ( ) } ;
if ( function . type ( ) . value ( ) > module . types ( ) . size ( ) )
return { } ;
auto & type = module . types ( ) [ function . type ( ) . value ( ) ] ;
m_functions . empend ( WasmFunction { type , module , function } ) ;
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 ;
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 ( ) } ;
m_globals . append ( GlobalInstance { move ( value ) , type . is_mutable ( ) } ) ;
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 ] ;
}
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
Optional < InstantiationResult > instantiation_result ;
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < TypeSection > ( [ & ] ( TypeSection const & section ) {
2021-05-10 15:40:49 +04:30
main_module_instance . types ( ) = 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 ;
// FIXME: Check that imports/extern match
for ( auto & entry : externs ) {
if ( auto * ptr = entry . get_pointer < GlobalAddress > ( ) )
auxiliary_instance . globals ( ) . append ( * ptr ) ;
}
2023-09-24 21:20:45 +03:30
Vector < FunctionAddress > module_functions ;
module_functions . ensure_capacity ( module . functions ( ) . size ( ) ) ;
2023-07-08 13:50:40 +03:30
for ( auto & func : module . functions ( ) ) {
auto address = m_store . allocate ( main_module_instance , func ) ;
VERIFY ( address . has_value ( ) ) ;
auxiliary_instance . functions ( ) . append ( * address ) ;
2023-09-24 21:20:45 +03:30
module_functions . append ( * address ) ;
2023-07-08 13:50:40 +03:30
}
2023-05-28 12:13:43 +02:00
BytecodeInterpreter interpreter ( m_stack_info ) ;
2021-05-24 02:04:58 +04:30
2021-05-01 01:08:51 +04:30
module . for_each_section_of_type < GlobalSection > ( [ & ] ( auto & global_section ) {
for ( auto & entry : global_section . entries ( ) ) {
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 > { } ,
entry . expression ( ) ,
1 ,
} ) ;
2023-02-25 11:15:11 +03:30
auto result = config . execute ( interpreter ) . assert_wasm_result ( ) ;
2021-05-01 01:08:51 +04:30
if ( result . is_trap ( ) )
2023-12-16 17:49:34 +03:30
instantiation_result = InstantiationError { ByteString : : formatted ( " Global value construction trapped: {} " , result . trap ( ) . reason ) } ;
2021-05-01 01:08:51 +04:30
else
global_values . append ( result . values ( ) . first ( ) ) ;
}
} ) ;
2021-06-04 03:30:09 +04:30
if ( instantiation_result . has_value ( ) )
return instantiation_result . release_value ( ) ;
2023-09-24 21:20:45 +03:30
if ( auto result = allocate_all_initial_phase ( module , main_module_instance , externs , global_values , module_functions ) ; result . has_value ( ) )
2021-05-10 15:40:49 +04:30
return result . release_value ( ) ;
2021-05-01 01:08:51 +04:30
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < ElementSection > ( [ & ] ( ElementSection const & section ) {
2021-06-04 03:30:09 +04:30
for ( auto & segment : section . segments ( ) ) {
Vector < Reference > references ;
for ( auto & entry : segment . init ) {
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 {
main_module_instance ,
Vector < Value > { } ,
entry ,
entry . instructions ( ) . size ( ) ,
} ) ;
2023-02-25 11:15:11 +03:30
auto result = config . execute ( interpreter ) . assert_wasm_result ( ) ;
2021-06-04 03:30:09 +04:30
if ( result . is_trap ( ) ) {
2023-12-16 17:49:34 +03:30
instantiation_result = InstantiationError { ByteString : : formatted ( " Element construction trapped: {} " , result . trap ( ) . reason ) } ;
2021-06-04 03:30:09 +04:30
return IterationDecision : : Continue ;
}
for ( auto & value : result . values ( ) ) {
if ( ! value . type ( ) . is_reference ( ) ) {
instantiation_result = InstantiationError { " Evaluated element entry is not a reference " } ;
return IterationDecision : : Continue ;
}
auto reference = value . to < Reference > ( ) ;
if ( ! reference . has_value ( ) ) {
instantiation_result = InstantiationError { " Evaluated element entry does not contain a reference " } ;
return IterationDecision : : Continue ;
}
// FIXME: type-check the reference.
references . prepend ( reference . release_value ( ) ) ;
}
}
elements . append ( move ( references ) ) ;
}
return IterationDecision : : Continue ;
2021-05-01 01:08:51 +04:30
} ) ;
2021-06-04 03:30:09 +04:30
if ( instantiation_result . has_value ( ) )
return instantiation_result . release_value ( ) ;
if ( auto result = allocate_all_final_phase ( module , main_module_instance , elements ) ; result . has_value ( ) )
return result . release_value ( ) ;
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < ElementSection > ( [ & ] ( ElementSection const & section ) {
2021-06-04 03:30:09 +04:30
size_t index = 0 ;
for ( auto & segment : section . segments ( ) ) {
auto current_index = index ;
+ + index ;
auto active_ptr = segment . mode . get_pointer < ElementSection : : Active > ( ) ;
if ( ! active_ptr )
continue ;
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 {
main_module_instance ,
Vector < Value > { } ,
active_ptr - > expression ,
1 ,
} ) ;
2023-02-25 11:15:11 +03:30
auto result = config . execute ( interpreter ) . assert_wasm_result ( ) ;
2021-06-04 03:30:09 +04:30
if ( result . is_trap ( ) ) {
2023-12-16 17:49:34 +03:30
instantiation_result = InstantiationError { ByteString : : formatted ( " Element section initialisation trapped: {} " , result . trap ( ) . reason ) } ;
2021-06-04 03:30:09 +04:30
return IterationDecision : : Break ;
}
auto d = result . values ( ) . first ( ) . to < i32 > ( ) ;
if ( ! d . has_value ( ) ) {
instantiation_result = InstantiationError { " Element section initialisation returned invalid table initial offset " } ;
return IterationDecision : : Break ;
}
2024-05-31 17:14:49 -07:00
auto table_instance = m_store . get ( main_module_instance . tables ( ) [ active_ptr - > index . value ( ) ] ) ;
2021-06-04 03:30:09 +04:30
if ( current_index > = main_module_instance . elements ( ) . size ( ) ) {
instantiation_result = InstantiationError { " Invalid element referenced by active element segment " } ;
return IterationDecision : : Break ;
}
auto elem_instance = m_store . get ( main_module_instance . elements ( ) [ current_index ] ) ;
if ( ! table_instance | | ! elem_instance ) {
instantiation_result = InstantiationError { " Invalid element referenced by active element segment " } ;
return IterationDecision : : Break ;
}
auto total_required_size = elem_instance - > references ( ) . size ( ) + d . value ( ) ;
if ( table_instance - > type ( ) . limits ( ) . max ( ) . value_or ( total_required_size ) < total_required_size ) {
instantiation_result = InstantiationError { " Table limit overflow in active element segment " } ;
return IterationDecision : : Break ;
}
if ( table_instance - > elements ( ) . size ( ) < total_required_size )
table_instance - > elements ( ) . resize ( total_required_size ) ;
size_t i = 0 ;
for ( auto it = elem_instance - > references ( ) . begin ( ) ; it < elem_instance - > references ( ) . end ( ) ; + + i , + + it ) {
table_instance - > elements ( ) [ i + d . value ( ) ] = * it ;
}
}
return IterationDecision : : Continue ;
} ) ;
if ( instantiation_result . has_value ( ) )
return instantiation_result . release_value ( ) ;
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < DataSection > ( [ & ] ( DataSection const & data_section ) {
2021-05-01 01:08:51 +04:30
for ( auto & segment : data_section . data ( ) ) {
segment . value ( ) . visit (
2021-06-04 03:42:11 +04:30
[ & ] ( DataSection : : Data : : Active const & data ) {
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 {
main_module_instance ,
Vector < Value > { } ,
data . offset ,
1 ,
} ) ;
2023-02-25 11:15:11 +03:30
auto result = config . execute ( interpreter ) . assert_wasm_result ( ) ;
2021-06-04 03:30:09 +04:30
if ( result . is_trap ( ) ) {
2023-12-16 17:49:34 +03:30
instantiation_result = InstantiationError { ByteString : : formatted ( " Data section initialisation trapped: {} " , result . trap ( ) . reason ) } ;
2021-06-04 03:30:09 +04:30
return ;
}
2021-05-01 01:08:51 +04:30
size_t offset = 0 ;
result . values ( ) . first ( ) . value ( ) . visit (
2021-06-04 03:42:11 +04:30
[ & ] ( auto const & value ) { offset = value ; } ,
2023-06-12 13:04:22 +03:30
[ & ] ( u128 const & ) { instantiation_result = InstantiationError { " Data segment offset returned a vector type " sv } ; } ,
2021-12-04 17:56:58 +03:30
[ & ] ( Reference const & ) { instantiation_result = InstantiationError { " Data segment offset returned a reference " sv } ; } ) ;
2021-05-01 01:08:51 +04:30
if ( instantiation_result . has_value ( ) & & instantiation_result - > is_error ( ) )
return ;
2021-05-10 15:40:49 +04:30
if ( main_module_instance . memories ( ) . size ( ) < = data . index . value ( ) ) {
2021-07-06 14:03:38 +04:30
instantiation_result = InstantiationError {
2023-12-16 17:49:34 +03:30
ByteString : : formatted ( " Data segment referenced out-of-bounds memory ({}) of max {} entries " ,
2021-07-06 14:03:38 +04:30
data . index . value ( ) , main_module_instance . memories ( ) . size ( ) )
} ;
2021-05-01 01:08:51 +04:30
return ;
}
2021-12-04 17:56:58 +03:30
auto maybe_data_address = m_store . allocate_data ( data . init ) ;
if ( ! maybe_data_address . has_value ( ) ) {
instantiation_result = InstantiationError { " Failed to allocate a data instance for an active data segment " sv } ;
return ;
}
main_module_instance . datas ( ) . append ( * maybe_data_address ) ;
2021-07-12 00:09:42 +04:30
if ( data . init . is_empty ( ) )
return ;
2021-05-10 15:40:49 +04:30
auto address = main_module_instance . memories ( ) [ data . index . value ( ) ] ;
2021-05-01 01:08:51 +04:30
if ( auto instance = m_store . get ( address ) ) {
2021-07-06 14:03:38 +04:30
if ( auto max = instance - > type ( ) . limits ( ) . max ( ) ; max . has_value ( ) ) {
2022-10-24 03:19:20 +03:30
if ( * max * Constants : : page_size < data . init . size ( ) + offset ) {
2021-07-06 14:03:38 +04:30
instantiation_result = InstantiationError {
2023-12-16 17:49:34 +03:30
ByteString : : formatted ( " Data segment attempted to write to out-of-bounds memory ({}) of max {} bytes " ,
2021-07-06 14:03:38 +04:30
data . init . size ( ) + offset , instance - > type ( ) . limits ( ) . max ( ) . value ( ) )
} ;
return ;
}
2021-05-01 01:08:51 +04:30
}
2021-05-17 21:41:07 +04:30
if ( instance - > size ( ) < data . init . size ( ) + offset )
instance - > grow ( data . init . size ( ) + offset - instance - > size ( ) ) ;
2021-05-01 01:08:51 +04:30
instance - > data ( ) . overwrite ( offset , data . init . data ( ) , data . init . size ( ) ) ;
}
} ,
2021-12-04 17:56:58 +03:30
[ & ] ( DataSection : : Data : : Passive const & passive ) {
auto maybe_data_address = m_store . allocate_data ( passive . init ) ;
if ( ! maybe_data_address . has_value ( ) ) {
instantiation_result = InstantiationError { " Failed to allocate a data instance for a passive data segment " sv } ;
return ;
}
main_module_instance . datas ( ) . append ( * maybe_data_address ) ;
2021-05-01 01:08:51 +04:30
} ) ;
}
} ) ;
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < StartSection > ( [ & ] ( StartSection const & section ) {
2021-05-10 15:40:49 +04:30
auto & functions = main_module_instance . functions ( ) ;
2021-05-03 22:45:16 +04:30
auto index = section . function ( ) . index ( ) ;
if ( functions . size ( ) < = index . value ( ) ) {
2023-12-16 17:49:34 +03:30
instantiation_result = InstantiationError { ByteString : : formatted ( " Start section function referenced invalid index {} of max {} entries " , index . value ( ) , functions . size ( ) ) } ;
2021-05-03 22:45:16 +04:30
return ;
}
invoke ( functions [ index . value ( ) ] , { } ) ;
2021-05-01 01:08:51 +04:30
} ) ;
2021-05-11 04:44:59 +04:30
if ( instantiation_result . has_value ( ) )
return instantiation_result . release_value ( ) ;
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?
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < TableSection > ( [ & ] ( TableSection const & section ) {
2021-05-01 01:08:51 +04:30
for ( auto & table : section . tables ( ) ) {
auto table_address = m_store . allocate ( table . type ( ) ) ;
VERIFY ( table_address . has_value ( ) ) ;
2021-05-10 15:40:49 +04:30
module_instance . tables ( ) . append ( * table_address ) ;
2021-05-01 01:08:51 +04:30
}
} ) ;
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < MemorySection > ( [ & ] ( MemorySection const & section ) {
2021-05-01 01:08:51 +04:30
for ( auto & memory : section . memories ( ) ) {
auto memory_address = m_store . allocate ( memory . type ( ) ) ;
VERIFY ( memory_address . has_value ( ) ) ;
2021-05-10 15:40:49 +04:30
module_instance . memories ( ) . append ( * memory_address ) ;
2021-05-01 01:08:51 +04:30
}
} ) ;
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < GlobalSection > ( [ & ] ( GlobalSection const & section ) {
2021-05-01 01:08:51 +04:30
size_t index = 0 ;
for ( auto & entry : section . entries ( ) ) {
2021-06-04 03:30:09 +04:30
auto address = m_store . allocate ( entry . type ( ) , move ( global_values [ index ] ) ) ;
2021-05-01 01:08:51 +04:30
VERIFY ( address . has_value ( ) ) ;
2021-05-10 15:40:49 +04:30
module_instance . globals ( ) . append ( * address ) ;
2021-05-01 01:08:51 +04:30
index + + ;
}
} ) ;
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < ExportSection > ( [ & ] ( ExportSection const & section ) {
2021-05-01 01:08:51 +04:30
for ( auto & entry : section . entries ( ) ) {
2021-09-19 23:00:45 +02:00
Variant < FunctionAddress , TableAddress , MemoryAddress , GlobalAddress , Empty > address { } ;
2021-05-01 01:08:51 +04:30
entry . description ( ) . visit (
2021-06-04 03:42:11 +04:30
[ & ] ( FunctionIndex const & index ) {
2021-05-10 15:40:49 +04:30
if ( module_instance . functions ( ) . size ( ) > index . value ( ) )
address = FunctionAddress { module_instance . functions ( ) [ index . value ( ) ] } ;
2021-05-01 01:08:51 +04:30
else
2021-05-10 15:40:49 +04:30
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . functions ( ) . size ( ) ) ;
2021-05-01 01:08:51 +04:30
} ,
2021-06-04 03:42:11 +04:30
[ & ] ( TableIndex const & index ) {
2021-05-10 15:40:49 +04:30
if ( module_instance . tables ( ) . size ( ) > index . value ( ) )
address = TableAddress { module_instance . tables ( ) [ index . value ( ) ] } ;
2021-05-01 01:08:51 +04:30
else
2021-05-10 15:40:49 +04:30
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . tables ( ) . size ( ) ) ;
2021-05-01 01:08:51 +04:30
} ,
2021-06-04 03:42:11 +04:30
[ & ] ( MemoryIndex const & index ) {
2021-05-10 15:40:49 +04:30
if ( module_instance . memories ( ) . size ( ) > index . value ( ) )
address = MemoryAddress { module_instance . memories ( ) [ index . value ( ) ] } ;
2021-05-01 01:08:51 +04:30
else
2021-05-10 15:40:49 +04:30
dbgln ( " Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {}) " , entry . name ( ) , index . value ( ) , module_instance . memories ( ) . size ( ) ) ;
2021-05-01 01:08:51 +04:30
} ,
2021-06-04 03:42:11 +04:30
[ & ] ( GlobalIndex const & index ) {
2021-05-10 15:40:49 +04:30
if ( module_instance . globals ( ) . size ( ) > index . value ( ) )
address = GlobalAddress { module_instance . globals ( ) [ index . value ( ) ] } ;
2021-05-01 01:08:51 +04:30
else
2021-05-10 15:40:49 +04:30
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
} ) ;
if ( address . has < Empty > ( ) ) {
result = InstantiationError { " An export could not be resolved " } ;
continue ;
}
2021-05-10 15:40:49 +04:30
module_instance . exports ( ) . append ( ExportInstance {
2021-05-01 01:08:51 +04:30
entry . name ( ) ,
2021-06-26 21:22:49 +02:00
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
{
2021-06-04 03:42:11 +04:30
module . for_each_section_of_type < ElementSection > ( [ & ] ( ElementSection const & section ) {
2021-06-04 03:30:09 +04:30
size_t index = 0 ;
for ( auto & segment : section . segments ( ) ) {
auto address = m_store . allocate ( segment . type , move ( elements [ index ] ) ) ;
VERIFY ( address . has_value ( ) ) ;
module_instance . elements ( ) . append ( * address ) ;
index + + ;
}
} ) ;
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 ) ;
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 ;
// There better be at most one import section!
bool already_seen_an_import_section = false ;
2021-06-04 03:42:11 +04:30
m_module . for_each_section_of_type < ImportSection > ( [ & ] ( ImportSection const & section ) {
2021-05-10 17:26:17 +04:30
if ( already_seen_an_import_section ) {
if ( ! m_error . has_value ( ) )
m_error = LinkError { } ;
m_error - > other_errors . append ( LinkError : : InvalidImportedModule ) ;
return ;
}
already_seen_an_import_section = true ;
for ( auto & import_ : section . imports ( ) ) {
m_ordered_imports . append ( { import_ . module ( ) , import_ . name ( ) , import_ . description ( ) } ) ;
m_unresolved_imports . set ( m_ordered_imports . last ( ) ) ;
}
} ) ;
}
2021-05-01 01:08:51 +04:30
}