2021-04-26 05:18:13 -03:00
/*
* Copyright ( c ) 2021 , Ali Mohammad Pur < mpfard @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# pragma once
2026-06-02 11:59:39 -03:00
# include <AK/AtomicRefCounted.h>
2021-10-31 19:06:35 -03:00
# include <AK/Badge.h>
2023-12-16 11:19:34 -03:00
# include <AK/ByteString.h>
2021-04-26 05:18:13 -03:00
# include <AK/DistinctNumeric.h>
2026-05-14 05:25:54 -03:00
# include <AK/FixedArray.h>
2026-05-14 10:32:18 -03:00
# include <AK/Function.h>
2023-01-20 10:07:24 -03:00
# include <AK/LEB128.h>
2026-05-14 05:22:37 -03:00
# include <AK/NumericLimits.h>
# include <AK/Optional.h>
2026-05-14 05:35:51 -03:00
# include <AK/OwnPtr.h>
2021-04-26 05:18:13 -03:00
# include <AK/Result.h>
2023-06-12 06:34:22 -03:00
# include <AK/String.h>
2026-05-11 11:35:24 -03:00
# include <AK/Time.h>
2023-06-12 06:34:22 -03:00
# include <AK/UFixedBigInt.h>
2021-04-26 05:18:13 -03:00
# include <AK/Variant.h>
2024-08-21 20:13:37 -03:00
# include <AK/WeakPtr.h>
2026-06-03 16:30:38 -03:00
# include <LibSync/ConditionVariable.h>
# include <LibSync/Mutex.h>
2021-04-26 05:18:13 -03:00
# include <LibWasm/Constants.h>
2025-08-07 17:47:21 -03:00
# include <LibWasm/Export.h>
2021-10-31 19:06:35 -03:00
# include <LibWasm/Forward.h>
2021-04-26 05:18:13 -03:00
# include <LibWasm/Opcode.h>
namespace Wasm {
2026-06-11 01:39:38 -03:00
class DefinedType ;
2025-11-07 07:29:20 -03:00
class Module ;
2023-06-12 07:08:22 -03:00
template < size_t M >
using NativeIntegralType = Conditional < M = = 8 , u8 , Conditional < M = = 16 , u16 , Conditional < M = = 32 , u32 , Conditional < M = = 64 , u64 , void > > > > ;
template < size_t M >
using NativeFloatingType = Conditional < M = = 32 , f32 , Conditional < M = = 64 , f64 , void > > ;
template < size_t M , size_t N , template < typename > typename SetSign , typename ElementType = SetSign < NativeIntegralType < M > > >
using NativeVectorType __attribute__ ( ( vector_size ( N * sizeof ( ElementType ) ) ) ) = ElementType ;
2024-02-07 11:01:38 -03:00
template < size_t M , size_t N , typename ElementType = NativeFloatingType < M > >
using NativeFloatingVectorType __attribute__ ( ( vector_size ( N * sizeof ( ElementType ) ) ) ) = ElementType ;
2023-06-12 07:08:22 -03:00
template < typename T , template < typename > typename SetSign >
using Native128ByteVectorOf = NativeVectorType < sizeof ( T ) * 8 , 16 / sizeof ( T ) , SetSign , T > ;
2021-04-26 05:18:13 -03:00
enum class ParseError {
2021-04-27 08:53:36 -03:00
UnexpectedEof ,
2021-04-27 10:29:21 -03:00
UnknownInstruction ,
ExpectedFloatingImmediate ,
2021-04-27 08:53:36 -03:00
ExpectedIndex ,
ExpectedKindTag ,
2021-04-27 10:29:21 -03:00
ExpectedSignedImmediate ,
2021-04-27 08:53:36 -03:00
ExpectedSize ,
ExpectedValueOrTerminator ,
2021-04-27 10:29:21 -03:00
InvalidImmediate ,
2021-04-27 08:53:36 -03:00
InvalidIndex ,
2021-04-26 05:18:13 -03:00
InvalidInput ,
2021-04-27 08:53:36 -03:00
InvalidModuleMagic ,
InvalidModuleVersion ,
InvalidSize ,
InvalidTag ,
InvalidType ,
HugeAllocationRequested ,
2021-09-05 19:59:52 -03:00
OutOfMemory ,
2024-06-01 16:53:19 -03:00
SectionSizeMismatch ,
2024-06-07 22:44:13 -03:00
InvalidUtf8 ,
2024-07-29 23:56:00 -03:00
DuplicateSection ,
2024-08-09 21:15:45 -03:00
SectionOutOfOrder ,
2021-04-26 05:18:13 -03:00
} ;
2025-08-07 17:47:21 -03:00
WASM_API ByteString parse_error_to_byte_string ( ParseError ) ;
2021-04-27 08:53:36 -03:00
2021-04-26 05:18:13 -03:00
template < typename T >
2024-03-11 18:57:59 -03:00
using ParseResult = ErrorOr < T , ParseError > ;
2021-04-26 05:18:13 -03:00
2025-12-21 14:01:38 -03:00
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , TypeIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , FunctionIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , TableIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , ElementIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , MemoryIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , TagIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , LocalIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , GlobalIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , LabelIndex ) ;
AK_TYPEDEF_DISTINCT_ORDERED_ID ( u32 , DataIndex ) ;
AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL ( u32 , InstructionPointer , Arithmetic , Comparison , Flags , Increment ) ;
2021-04-26 05:18:13 -03:00
2026-05-14 05:22:37 -03:00
}
namespace AK {
template < >
struct SentinelOptionalTraits < Wasm : : InstructionPointer > {
static constexpr Wasm : : InstructionPointer sentinel_value ( ) { return { NumericLimits < Wasm : : InstructionPointer : : Type > : : max ( ) } ; }
static constexpr bool is_sentinel ( Wasm : : InstructionPointer const & value ) { return value . value ( ) = = NumericLimits < Wasm : : InstructionPointer : : Type > : : max ( ) ; }
} ;
template < >
class Optional < Wasm : : InstructionPointer > : public SentinelOptional < Wasm : : InstructionPointer > {
public :
using SentinelOptional : : SentinelOptional ;
} ;
}
namespace Wasm {
2025-11-07 07:29:20 -03:00
constexpr static inline auto LocalArgumentMarker = static_cast < LocalIndex : : Type > ( 1 ) < < ( sizeof ( LocalIndex : : Type ) * 8 - 1 ) ;
2023-02-09 21:00:18 -03:00
ParseError with_eof_check ( Stream const & stream , ParseError error_if_not_eof ) ;
2021-04-27 08:53:36 -03:00
template < typename T >
struct GenericIndexParser {
2023-02-09 21:00:18 -03:00
static ParseResult < T > parse ( Stream & stream )
2021-04-27 08:53:36 -03:00
{
2024-06-16 11:38:06 -03:00
auto value_or_error = stream . read_value < LEB128 < u32 > > ( ) ;
2023-01-29 20:02:38 -03:00
if ( value_or_error . is_error ( ) )
2021-04-27 08:53:36 -03:00
return with_eof_check ( stream , ParseError : : ExpectedIndex ) ;
2025-12-21 14:01:38 -03:00
u32 value = value_or_error . release_value ( ) ;
2021-04-27 08:53:36 -03:00
return T { value } ;
}
} ;
2023-02-09 21:00:18 -03:00
class ReconsumableStream : public Stream {
2021-04-26 05:18:13 -03:00
public :
2023-02-09 21:00:18 -03:00
explicit ReconsumableStream ( Stream & stream )
2021-04-26 05:18:13 -03:00
: m_stream ( stream )
{
}
void unread ( ReadonlyBytes data ) { m_buffer . append ( data . data ( ) , data . size ( ) ) ; }
private :
2023-02-24 18:38:01 -03:00
virtual ErrorOr < Bytes > read_some ( Bytes bytes ) override
2021-04-26 05:18:13 -03:00
{
2023-01-21 07:44:19 -03:00
auto original_bytes = bytes ;
2021-04-26 05:18:13 -03:00
size_t bytes_read_from_buffer = 0 ;
if ( ! m_buffer . is_empty ( ) ) {
auto read_size = min ( bytes . size ( ) , m_buffer . size ( ) ) ;
m_buffer . span ( ) . slice ( 0 , read_size ) . copy_to ( bytes ) ;
bytes = bytes . slice ( read_size ) ;
for ( size_t i = 0 ; i < read_size ; + + i )
m_buffer . take_first ( ) ;
bytes_read_from_buffer = read_size ;
}
2023-02-24 18:38:01 -03:00
return original_bytes . trim ( TRY ( m_stream . read_some ( bytes ) ) . size ( ) + bytes_read_from_buffer ) ;
2021-04-26 05:18:13 -03:00
}
2023-01-21 07:44:19 -03:00
virtual bool is_eof ( ) const override
2021-04-26 05:18:13 -03:00
{
2023-01-21 07:44:19 -03:00
return m_buffer . is_empty ( ) & & m_stream . is_eof ( ) ;
2021-04-26 05:18:13 -03:00
}
2023-01-21 07:44:19 -03:00
virtual ErrorOr < void > discard ( size_t count ) override
2021-04-26 05:18:13 -03:00
{
size_t bytes_discarded_from_buffer = 0 ;
if ( ! m_buffer . is_empty ( ) ) {
auto read_size = min ( count , m_buffer . size ( ) ) ;
for ( size_t i = 0 ; i < read_size ; + + i )
m_buffer . take_first ( ) ;
bytes_discarded_from_buffer = read_size ;
}
2023-01-21 07:44:19 -03:00
return m_stream . discard ( count - bytes_discarded_from_buffer ) ;
}
2023-02-24 18:38:01 -03:00
virtual ErrorOr < size_t > write_some ( ReadonlyBytes ) override
2023-01-21 07:44:19 -03:00
{
return Error : : from_errno ( EBADF ) ;
}
virtual bool is_open ( ) const override
{
return m_stream . is_open ( ) ;
}
virtual void close ( ) override
{
m_stream . close ( ) ;
2021-04-26 05:18:13 -03:00
}
2023-02-09 21:00:18 -03:00
Stream & m_stream ;
2021-04-26 05:18:13 -03:00
Vector < u8 , 8 > m_buffer ;
} ;
2026-06-11 01:14:58 -03:00
// https://webassembly.github.io/spec/core/syntax/types.html#value-types
// valtype ::= numtype | vectype | reftype
// https://webassembly.github.io/spec/core/syntax/types.html#reference-types
// reftype ::= ref null? heaptype
// https://webassembly.github.io/spec/core/syntax/types.html#heap-types
// heaptype ::= absheaptype | typeidx
// absheaptype ::= func | nofunc | extern | noextern | any | eq | i31 | struct | array | none | exn | noexn
// https://webassembly.github.io/spec/core/syntax/types.html#composite-types
// packtype ::= i8 | i16
2021-04-26 05:18:13 -03:00
class ValueType {
public :
2026-03-06 08:12:51 -03:00
enum Kind : u8 {
2021-04-26 05:18:13 -03:00
I32 ,
I64 ,
F32 ,
F64 ,
2023-06-12 06:34:22 -03:00
V128 ,
2026-06-11 01:14:58 -03:00
I8 , // as packtype
I16 , // as packtype
2021-04-26 05:18:13 -03:00
FunctionReference ,
2026-06-11 01:14:58 -03:00
NoFunctionReference ,
2021-04-26 05:18:13 -03:00
ExternReference ,
2026-06-11 01:14:58 -03:00
NoExternReference ,
AnyReference ,
EqReference ,
I31Reference ,
StructReference ,
ArrayReference ,
NoneReference ,
2025-09-24 22:35:34 -03:00
ExceptionReference ,
2026-06-11 01:14:58 -03:00
NoExceptionReference ,
2026-02-08 13:51:47 -03:00
TypeUseReference ,
2021-04-26 05:18:13 -03:00
} ;
explicit ValueType ( Kind kind )
: m_kind ( kind )
{
}
2026-06-11 01:14:58 -03:00
explicit ValueType ( Kind kind , bool nullable )
2026-02-08 13:51:47 -03:00
: m_kind ( kind )
2026-06-11 01:14:58 -03:00
, m_nullable ( nullable )
{
}
explicit ValueType ( Kind kind , TypeIndex type_index , bool nullable = true )
: m_kind ( kind )
, m_nullable ( nullable )
2026-05-14 05:31:19 -03:00
, m_type_index ( type_index )
2026-02-08 13:51:47 -03:00
{
2026-05-14 05:31:19 -03:00
VERIFY ( kind = = TypeUseReference ) ;
2026-02-08 13:51:47 -03:00
}
2021-10-31 19:06:35 -03:00
bool operator = = ( ValueType const & ) const = default ;
2026-03-06 08:12:51 -03:00
bool is_nullable ( ) const { return m_nullable ; }
void set_nullable ( bool nullable ) { m_nullable = nullable ; }
2026-06-11 01:14:58 -03:00
auto is_reference ( ) const { return m_kind > = FunctionReference ; }
2023-06-12 06:34:22 -03:00
auto is_vector ( ) const { return m_kind = = V128 ; }
2026-06-11 01:14:58 -03:00
auto is_packed ( ) const { return m_kind = = I8 | | m_kind = = I16 ; }
auto is_numeric ( ) const { return ! is_reference ( ) & & ! is_vector ( ) & & ! is_packed ( ) ; }
2026-02-08 13:51:47 -03:00
auto is_typeuse ( ) const { return m_kind = = TypeUseReference ; }
2021-04-26 05:18:13 -03:00
auto kind ( ) const { return m_kind ; }
2026-06-11 01:14:58 -03:00
// https://webassembly.github.io/spec/core/syntax/types.html#aux-unpack
// unpack(valtype) = valtype
// unpack(packtype) = i32
ValueType unpacked ( ) const
{
if ( is_packed ( ) )
return ValueType ( I32 ) ;
return * this ;
}
// https://webassembly.github.io/spec/core/valid/types.html#defaultable-types
bool is_defaultable ( ) const
{
if ( is_reference ( ) )
return m_nullable ;
return true ;
}
2026-05-14 05:31:19 -03:00
auto unsafe_typeindex ( ) const
{
VERIFY ( m_kind = = TypeUseReference ) ;
return m_type_index ;
}
2026-02-08 13:51:47 -03:00
2023-02-09 21:00:18 -03:00
static ParseResult < ValueType > parse ( Stream & stream ) ;
2021-04-26 05:18:13 -03:00
2026-02-08 13:51:47 -03:00
ByteString kind_name ( ) const
2021-04-26 05:18:13 -03:00
{
2026-02-08 13:51:47 -03:00
switch ( m_kind ) {
2021-04-26 05:18:13 -03:00
case I32 :
return " i32 " ;
case I64 :
return " i64 " ;
case F32 :
return " f32 " ;
case F64 :
return " f64 " ;
2023-06-12 06:34:22 -03:00
case V128 :
return " v128 " ;
2026-06-11 01:14:58 -03:00
case I8 :
return " i8 " ;
case I16 :
return " i16 " ;
2021-04-26 05:18:13 -03:00
case FunctionReference :
2026-06-11 01:14:58 -03:00
return m_nullable ? " funcref " : " (ref func) " ;
case NoFunctionReference :
return m_nullable ? " nullfuncref " : " (ref nofunc) " ;
2021-04-26 05:18:13 -03:00
case ExternReference :
2026-06-11 01:14:58 -03:00
return m_nullable ? " externref " : " (ref extern) " ;
case NoExternReference :
return m_nullable ? " nullexternref " : " (ref noextern) " ;
case AnyReference :
return m_nullable ? " anyref " : " (ref any) " ;
case EqReference :
return m_nullable ? " eqref " : " (ref eq) " ;
case I31Reference :
return m_nullable ? " i31ref " : " (ref i31) " ;
case StructReference :
return m_nullable ? " structref " : " (ref struct) " ;
case ArrayReference :
return m_nullable ? " arrayref " : " (ref array) " ;
case NoneReference :
return m_nullable ? " nullref " : " (ref none) " ;
2025-09-24 22:35:34 -03:00
case ExceptionReference :
2026-06-11 01:14:58 -03:00
return m_nullable ? " exnref " : " (ref exn) " ;
case NoExceptionReference :
return m_nullable ? " nullexnref " : " (ref noexn) " ;
2026-02-08 13:51:47 -03:00
case TypeUseReference :
2026-06-11 01:14:58 -03:00
return ByteString : : formatted ( " (ref {}{}) " , m_nullable ? " null " : " " , unsafe_typeindex ( ) . value ( ) ) ;
2021-04-26 05:18:13 -03:00
}
VERIFY_NOT_REACHED ( ) ;
}
private :
Kind m_kind ;
2026-03-06 08:12:51 -03:00
bool m_nullable { true } ;
2026-05-14 05:31:19 -03:00
TypeIndex m_type_index ;
2021-04-26 05:18:13 -03:00
} ;
2026-05-14 05:31:19 -03:00
static_assert ( sizeof ( ValueType ) = = 8 ) ;
2021-04-26 05:18:13 -03:00
// https://webassembly.github.io/spec/core/bikeshed/#result-types%E2%91%A2
class ResultType {
public :
explicit ResultType ( Vector < ValueType > types )
: m_types ( move ( types ) )
{
}
2021-06-03 20:12:11 -03:00
auto const & types ( ) const { return m_types ; }
2021-04-26 05:18:13 -03:00
2025-06-06 09:11:24 -03:00
static ParseResult < ResultType > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < ValueType > m_types ;
} ;
// https://webassembly.github.io/spec/core/bikeshed/#function-types%E2%91%A4
class FunctionType {
public :
FunctionType ( Vector < ValueType > parameters , Vector < ValueType > results )
: m_parameters ( move ( parameters ) )
, m_results ( move ( results ) )
{
}
auto & parameters ( ) const { return m_parameters ; }
auto & results ( ) const { return m_results ; }
2025-06-06 09:11:24 -03:00
static ParseResult < FunctionType > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < ValueType > m_parameters ;
Vector < ValueType > m_results ;
} ;
2026-02-02 13:44:20 -03:00
// https://webassembly.github.io/spec/core/bikeshed/#composite-types%E2%91%A0
class FieldType {
public :
FieldType ( bool is_mutable , ValueType type_ )
: m_is_mutable ( is_mutable )
, m_type ( type_ )
{
}
auto & type ( ) const { return m_type ; }
auto is_mutable ( ) const { return m_is_mutable ; }
static ParseResult < FieldType > parse ( ConstrainedStream & stream ) ;
private :
bool m_is_mutable { false } ;
ValueType m_type ;
} ;
// https://webassembly.github.io/spec/core/bikeshed/#composite-types%E2%91%A0
class StructType {
public :
StructType ( Vector < FieldType > fields )
: m_fields ( move ( fields ) )
{
}
auto & fields ( ) const { return m_fields ; }
static ParseResult < StructType > parse ( ConstrainedStream & stream ) ;
private :
Vector < FieldType > m_fields ;
} ;
2026-02-08 15:09:18 -03:00
// https://webassembly.github.io/spec/core/bikeshed/#composite-types%E2%91%A0
class ArrayType {
public :
ArrayType ( FieldType type )
: m_type ( type )
{
}
auto & type ( ) const { return m_type ; }
static ParseResult < ArrayType > parse ( ConstrainedStream & stream ) ;
private :
FieldType m_type ;
} ;
2025-09-23 00:52:12 -03:00
// https://webassembly.github.io/memory64/core/bikeshed/#address-type%E2%91%A0
enum class AddressType : u8 {
I32 ,
I64 ,
} ;
2021-04-26 05:18:13 -03:00
// https://webassembly.github.io/spec/core/bikeshed/#limits%E2%91%A5
class Limits {
public :
2025-09-23 00:52:12 -03:00
explicit Limits ( AddressType address_type , u64 min , Optional < u64 > max = { } )
: m_address_type ( address_type )
, m_min ( min )
2021-04-26 05:18:13 -03:00
, m_max ( move ( max ) )
{
}
2025-09-23 00:52:12 -03:00
ValueType address_value_type ( ) const
{
return m_address_type = = AddressType : : I32 ? ValueType ( ValueType : : I32 ) : ValueType ( ValueType : : I64 ) ;
}
auto address_type ( ) const { return m_address_type ; }
2021-04-26 05:18:13 -03:00
auto min ( ) const { return m_min ; }
auto & max ( ) const { return m_max ; }
2024-06-10 19:41:47 -03:00
bool is_subset_of ( Limits other ) const
{
return m_min > = other . min ( )
2025-09-23 00:52:12 -03:00
& & ( ! other . max ( ) . has_value ( ) | | ( m_max . has_value ( ) & & * m_max < = * other . max ( ) ) )
& & m_address_type = = other . m_address_type ;
2024-06-10 19:41:47 -03:00
}
2021-04-26 05:18:13 -03:00
2025-06-06 09:11:24 -03:00
static ParseResult < Limits > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
2025-09-23 00:52:12 -03:00
AddressType m_address_type { AddressType : : I32 } ;
u64 m_min { 0 } ;
Optional < u64 > m_max ;
2021-04-26 05:18:13 -03:00
} ;
// https://webassembly.github.io/spec/core/bikeshed/#memory-types%E2%91%A4
class MemoryType {
public :
explicit MemoryType ( Limits limits )
: m_limits ( move ( limits ) )
{
}
auto & limits ( ) const { return m_limits ; }
2025-06-06 09:11:24 -03:00
static ParseResult < MemoryType > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Limits m_limits ;
} ;
// https://webassembly.github.io/spec/core/bikeshed/#table-types%E2%91%A4
class TableType {
public :
explicit TableType ( ValueType element_type , Limits limits )
: m_element_type ( element_type )
, m_limits ( move ( limits ) )
{
VERIFY ( m_element_type . is_reference ( ) ) ;
}
auto & limits ( ) const { return m_limits ; }
auto & element_type ( ) const { return m_element_type ; }
2025-06-06 09:11:24 -03:00
static ParseResult < TableType > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
ValueType m_element_type ;
Limits m_limits ;
} ;
// https://webassembly.github.io/spec/core/bikeshed/#global-types%E2%91%A4
class GlobalType {
public :
GlobalType ( ValueType type , bool is_mutable )
: m_type ( type )
, m_is_mutable ( is_mutable )
{
}
auto & type ( ) const { return m_type ; }
auto is_mutable ( ) const { return m_is_mutable ; }
2025-06-06 09:11:24 -03:00
static ParseResult < GlobalType > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
ValueType m_type ;
bool m_is_mutable { false } ;
} ;
2025-09-24 22:35:34 -03:00
// https://webassembly.github.io/exception-handling/core/binary/types.html#tag-types
class TagType {
public :
enum Flags : u8 {
None = 0
} ;
TagType ( TypeIndex type , Flags flags )
: m_flags ( flags )
, m_type ( type )
{
}
auto & type ( ) const { return m_type ; }
auto flags ( ) const { return m_flags ; }
static ParseResult < TagType > parse ( ConstrainedStream & stream ) ;
private :
Flags m_flags { None } ;
TypeIndex m_type ;
} ;
2021-04-26 05:18:13 -03:00
// https://webassembly.github.io/spec/core/bikeshed/#binary-blocktype
class BlockType {
public :
enum Kind {
Empty ,
Type ,
Index ,
} ;
BlockType ( )
: m_kind ( Empty )
, m_empty ( 0 )
{
}
explicit BlockType ( ValueType type )
: m_kind ( Type )
, m_value_type ( type )
{
}
explicit BlockType ( TypeIndex index )
: m_kind ( Index )
, m_type_index ( index )
{
}
auto kind ( ) const { return m_kind ; }
auto & value_type ( ) const
{
VERIFY ( kind ( ) = = Type ) ;
return m_value_type ;
}
auto & type_index ( ) const
{
VERIFY ( kind ( ) = = Index ) ;
return m_type_index ;
}
2025-06-06 09:11:24 -03:00
static ParseResult < BlockType > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Kind m_kind { Empty } ;
union {
ValueType m_value_type ;
TypeIndex m_type_index ;
u8 m_empty ;
} ;
} ;
2025-09-24 22:35:34 -03:00
// Proposal "exception-handling"
// https://webassembly.github.io/exception-handling/core/binary/instructions.html
class Catch {
public :
Catch ( bool ref , TagIndex index , LabelIndex label ) // catch[_ref] x l
: m_matching_tag_index ( index )
, m_target_label ( label )
, m_is_ref ( ref )
{
}
explicit Catch ( bool ref , LabelIndex label ) // catch_all[_ref] l
: m_target_label ( label )
, m_is_ref ( ref )
{
}
auto & matching_tag_index ( ) const { return m_matching_tag_index ; }
auto & target_label ( ) const { return m_target_label ; }
auto is_ref ( ) const { return m_is_ref ; }
static ParseResult < Catch > parse ( ConstrainedStream & stream ) ;
private :
Optional < TagIndex > m_matching_tag_index ; // None for catch_all
LabelIndex m_target_label ;
bool m_is_ref = false ; // true if catch*_ref
} ;
2021-04-26 05:18:13 -03:00
// https://webassembly.github.io/spec/core/bikeshed/#binary-instr
// https://webassembly.github.io/spec/core/bikeshed/#reference-instructions%E2%91%A6
// https://webassembly.github.io/spec/core/bikeshed/#parametric-instructions%E2%91%A6
// https://webassembly.github.io/spec/core/bikeshed/#variable-instructions%E2%91%A6
// https://webassembly.github.io/spec/core/bikeshed/#table-instructions%E2%91%A6
// https://webassembly.github.io/spec/core/bikeshed/#memory-instructions%E2%91%A6
// https://webassembly.github.io/spec/core/bikeshed/#numeric-instructions%E2%91%A6
class Instruction {
public :
explicit Instruction ( OpCode opcode )
: m_opcode ( opcode )
, m_arguments ( static_cast < u8 > ( 0 ) )
{
}
struct TableElementArgs {
2021-04-27 10:29:21 -03:00
ElementIndex element_index ;
TableIndex table_index ;
2021-04-26 05:18:13 -03:00
} ;
struct TableTableArgs {
TableIndex lhs ;
TableIndex rhs ;
} ;
2026-05-14 05:35:51 -03:00
template < typename ExtraData >
struct StructuredInstructionArgsBase {
using Extra = ExtraData ;
2021-04-26 05:18:13 -03:00
BlockType block_type ;
2025-12-03 23:37:37 -03:00
InstructionPointer end_ip ; // 'end' instruction IP if there is no 'else'; otherwise IP of instruction after 'end'.
2026-05-14 05:35:51 -03:00
ExtraData extra ;
2026-01-23 08:36:20 -03:00
struct Meta {
2026-01-15 11:33:18 -03:00
u32 arity ;
u32 parameter_count ;
2026-06-04 11:53:04 -03:00
bool tier_up_eligible ;
2026-01-23 08:36:20 -03:00
} ;
2026-05-14 05:24:24 -03:00
mutable Meta meta { } ;
2021-04-26 05:18:13 -03:00
} ;
2026-05-14 05:35:51 -03:00
struct StructuredInstructionArgs : StructuredInstructionArgsBase < Optional < InstructionPointer > > {
using Base = StructuredInstructionArgsBase < Optional < InstructionPointer > > ;
using Meta = typename Base : : Meta ;
StructuredInstructionArgs ( BlockType block_type , InstructionPointer end_ip , Optional < InstructionPointer > else_ip , Meta meta = { } )
: Base { block_type , end_ip , else_ip , meta }
{
}
auto & else_ip ( ) { return extra ; }
auto & else_ip ( ) const { return extra ; }
} ;
2021-04-26 05:18:13 -03:00
struct TableBranchArgs {
Vector < LabelIndex > labels ;
LabelIndex default_ ;
} ;
2026-01-23 08:36:20 -03:00
struct BranchArgs {
LabelIndex label ;
mutable bool has_stack_adjustment { false } ;
} ;
2021-04-26 05:18:13 -03:00
struct IndirectCallArgs {
TypeIndex type ;
TableIndex table ;
} ;
struct MemoryArgument {
u32 align ;
2025-09-23 00:52:12 -03:00
u64 offset ;
2023-10-22 17:49:28 -03:00
MemoryIndex memory_index { 0 } ;
2021-04-26 05:18:13 -03:00
} ;
2023-06-12 06:34:22 -03:00
struct MemoryAndLaneArgument {
MemoryArgument memory ;
u8 lane ;
} ;
struct LaneIndex {
u8 lane ;
} ;
2023-10-22 17:49:28 -03:00
// Proposal "multi-memory"
struct MemoryCopyArgs {
MemoryIndex src_index ;
MemoryIndex dst_index ;
} ;
struct MemoryInitArgs {
DataIndex data_index ;
MemoryIndex memory_index ;
} ;
struct MemoryIndexArgument {
MemoryIndex memory_index ;
} ;
2026-06-11 02:15:32 -03:00
// Proposal "gc"
struct StructFieldArgs {
TypeIndex type_index ;
u32 field_index ;
} ;
struct ArrayNewFixedArgs {
TypeIndex type_index ;
u32 count ;
} ;
struct ArrayDataArgs {
TypeIndex type_index ;
DataIndex data_index ;
} ;
struct ArrayElemArgs {
TypeIndex type_index ;
ElementIndex element_index ;
} ;
struct ArrayCopyArgs {
TypeIndex destination_type_index ;
TypeIndex source_type_index ;
} ;
struct BranchOnCastArgs {
BranchArgs branch ;
ValueType source_type ; // Nullability carries the castop null_1? flag.
ValueType target_type ; // Nullability carries the castop null_2? flag.
} ;
2025-09-24 22:35:34 -03:00
// Proposal "exception-handling"
2026-05-14 05:35:51 -03:00
struct TryTableArgs : StructuredInstructionArgsBase < OwnPtr < FixedArray < Catch > > > {
using Base = StructuredInstructionArgsBase < OwnPtr < FixedArray < Catch > > > ;
using Meta = typename Base : : Meta ;
TryTableArgs ( BlockType block_type , InstructionPointer end_ip , ReadonlySpan < Catch > catches , Meta meta = { } )
: Base { block_type , end_ip , create_catches ( catches ) , meta }
{
}
TryTableArgs ( TryTableArgs const & other )
: Base { other . block_type , other . end_ip , clone_catches ( other . extra ) , other . meta }
{
}
TryTableArgs & operator = ( TryTableArgs const & other )
{
if ( this = = & other )
return * this ;
block_type = other . block_type ;
end_ip = other . end_ip ;
extra = clone_catches ( other . extra ) ;
meta = other . meta ;
return * this ;
}
TryTableArgs ( TryTableArgs & & ) = default ;
TryTableArgs & operator = ( TryTableArgs & & ) = default ;
ReadonlySpan < Catch > catches ( ) const
{
if ( ! extra )
return { } ;
return extra - > span ( ) ;
}
private :
static OwnPtr < FixedArray < Catch > > create_catches ( ReadonlySpan < Catch > catches )
{
if ( catches . is_empty ( ) )
return nullptr ;
return make < FixedArray < Catch > > ( MUST ( FixedArray < Catch > : : create ( catches ) ) ) ;
}
static OwnPtr < FixedArray < Catch > > clone_catches ( OwnPtr < FixedArray < Catch > > const & catches )
{
if ( ! catches )
return nullptr ;
return make < FixedArray < Catch > > ( MUST ( catches - > clone ( ) ) ) ;
}
2025-09-24 22:35:34 -03:00
} ;
2023-06-12 06:34:22 -03:00
struct ShuffleArgument {
explicit ShuffleArgument ( u8 ( & lanes ) [ 16 ] )
: lanes {
lanes [ 0 ] , lanes [ 1 ] , lanes [ 2 ] , lanes [ 3 ] , lanes [ 4 ] , lanes [ 5 ] , lanes [ 6 ] , lanes [ 7 ] ,
lanes [ 8 ] , lanes [ 9 ] , lanes [ 10 ] , lanes [ 11 ] , lanes [ 12 ] , lanes [ 13 ] , lanes [ 14 ] , lanes [ 15 ]
}
{
}
u8 lanes [ 16 ] ;
} ;
2021-04-26 05:18:13 -03:00
template < typename T >
explicit Instruction ( OpCode opcode , T argument )
: m_opcode ( opcode )
, m_arguments ( move ( argument ) )
{
}
2025-08-02 15:30:44 -03:00
explicit Instruction ( OpCode opcode , LocalIndex argument )
: m_opcode ( opcode )
, m_local_index ( argument )
, m_arguments ( static_cast < u8 > ( 0 ) )
{
}
template < typename Arg1 >
explicit Instruction ( OpCode opcode , LocalIndex argument0 , Arg1 & & argument1 )
: m_opcode ( opcode )
, m_local_index ( argument0 )
, m_arguments ( forward < Arg1 > ( argument1 ) )
{
}
2025-06-06 09:11:24 -03:00
static ParseResult < Instruction > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
2021-04-27 14:43:01 -03:00
auto & opcode ( ) const { return m_opcode ; }
auto & arguments ( ) const { return m_arguments ; }
2024-07-24 14:48:31 -03:00
auto & arguments ( ) { return m_arguments ; }
2021-04-27 14:43:01 -03:00
2025-08-02 15:30:44 -03:00
LocalIndex local_index ( ) const { return m_local_index ; }
2025-11-07 07:29:20 -03:00
void set_local_index ( Badge < Module > , LocalIndex index ) { m_local_index = index ; }
2021-04-26 05:18:13 -03:00
private :
OpCode m_opcode { 0 } ;
2025-08-02 15:30:44 -03:00
LocalIndex m_local_index ;
2021-04-26 05:18:13 -03:00
Variant <
2026-06-11 02:15:32 -03:00
ArrayCopyArgs ,
ArrayDataArgs ,
ArrayElemArgs ,
ArrayNewFixedArgs ,
2021-05-01 12:26:45 -03:00
BlockType ,
2026-01-23 08:36:20 -03:00
BranchArgs ,
2026-06-11 02:15:32 -03:00
BranchOnCastArgs ,
2021-04-26 05:18:13 -03:00
DataIndex ,
2021-04-27 10:29:21 -03:00
ElementIndex ,
2021-04-26 05:18:13 -03:00
FunctionIndex ,
2021-04-27 10:29:21 -03:00
GlobalIndex ,
2025-09-24 22:35:34 -03:00
TagIndex ,
2021-04-26 05:18:13 -03:00
IndirectCallArgs ,
LabelIndex ,
2023-06-12 06:34:22 -03:00
LaneIndex ,
2025-08-02 15:30:44 -03:00
LocalIndex , // Only used by instructions that take more than one local index (currently only fused ops).
2021-04-26 05:18:13 -03:00
MemoryArgument ,
2023-06-12 06:34:22 -03:00
MemoryAndLaneArgument ,
2023-10-22 17:49:28 -03:00
MemoryCopyArgs ,
MemoryIndexArgument ,
MemoryInitArgs ,
2026-06-11 02:15:32 -03:00
StructFieldArgs ,
2021-05-01 12:26:45 -03:00
StructuredInstructionArgs ,
2023-06-12 06:34:22 -03:00
ShuffleArgument ,
2021-04-26 05:18:13 -03:00
TableBranchArgs ,
TableElementArgs ,
TableIndex ,
TableTableArgs ,
2025-09-24 22:35:34 -03:00
TryTableArgs ,
2026-03-06 08:13:38 -03:00
TypeIndex ,
2021-04-26 05:18:13 -03:00
ValueType ,
Vector < ValueType > ,
double ,
float ,
i32 ,
i64 ,
2023-06-12 06:34:22 -03:00
u128 ,
2024-04-24 08:32:02 -03:00
u8 > // Empty state
m_arguments ;
2021-04-26 05:18:13 -03:00
} ;
2026-05-14 05:22:37 -03:00
}
namespace AK {
template < >
struct SentinelOptionalTraits < Wasm : : Instruction > {
static Wasm : : Instruction sentinel_value ( ) { return Wasm : : Instruction { Wasm : : OpCode { NumericLimits < Wasm : : OpCode : : Type > : : max ( ) } } ; }
static bool is_sentinel ( Wasm : : Instruction const & value ) { return value . opcode ( ) . value ( ) = = NumericLimits < Wasm : : OpCode : : Type > : : max ( ) ; }
} ;
template < >
class Optional < Wasm : : Instruction > : public SentinelOptional < Wasm : : Instruction > {
public :
using SentinelOptional : : SentinelOptional ;
} ;
}
namespace Wasm {
static_assert ( sizeof ( Optional < Instruction > ) = = sizeof ( Instruction ) ) ;
static_assert ( sizeof ( Optional < InstructionPointer > ) = = sizeof ( InstructionPointer ) ) ;
2025-08-02 15:30:44 -03:00
struct Dispatch {
enum RegisterOrStack : u8 {
R0 ,
R1 ,
R2 ,
R3 ,
R4 ,
R5 ,
R6 ,
R7 ,
CountRegisters ,
Stack = CountRegisters ,
2026-01-23 08:30:50 -03:00
CallRecord ,
LastCallRecord = NumericLimits < u8 > : : max ( ) ,
2025-08-02 15:30:44 -03:00
} ;
2025-12-03 23:37:37 -03:00
static_assert ( is_power_of_two ( to_underlying ( Stack ) ) , " Stack marker must be a single bit " ) ;
2025-09-19 18:06:08 -03:00
union {
OpCode instruction_opcode ;
FlatPtr handler_ptr ;
} ;
2025-08-02 15:30:44 -03:00
Instruction const * instruction { nullptr } ;
2025-12-03 23:25:19 -03:00
} ;
union SourcesAndDestination {
struct {
Dispatch : : RegisterOrStack sources [ 3 ] ;
Dispatch : : RegisterOrStack destination ;
2025-08-02 15:30:44 -03:00
} ;
2025-12-03 23:25:19 -03:00
u32 sources_and_destination ;
2025-08-02 15:30:44 -03:00
} ;
2025-12-03 23:25:19 -03:00
2026-05-14 05:25:54 -03:00
class InstructionStorage {
using Chunk = FixedArray < Optional < Instruction > > ;
public :
InstructionStorage ( ) = default ;
InstructionStorage ( InstructionStorage const & ) = delete ;
InstructionStorage & operator = ( InstructionStorage const & ) = delete ;
InstructionStorage ( InstructionStorage & & ) = default ;
InstructionStorage & operator = ( InstructionStorage & & ) = default ;
Instruction & append ( Instruction ) ;
size_t size ( ) const { return m_size ; }
size_t capacity ( ) const { return m_capacity ; }
bool is_empty ( ) const { return m_size = = 0 ; }
private :
void add_chunk ( ) ;
Vector < Chunk , 0 , FastLastAccess : : Yes > m_chunks ;
size_t m_size { 0 } ;
size_t m_capacity { 0 } ;
size_t m_next_index_in_last_chunk { 0 } ;
} ;
2026-04-22 06:48:56 -03:00
void free_cranelift_code ( void * handle ) ;
2026-06-01 13:02:57 -03:00
struct CraneliftTrap {
u32 offset { 0 } ;
u8 code { 0 } ;
u8 _padding [ 3 ] { 0 , 0 , 0 } ;
} ;
static_assert ( sizeof ( CraneliftTrap ) = = 8 ) ;
2025-08-02 15:30:44 -03:00
struct CompiledInstructions {
Vector < Dispatch > dispatches ;
2025-12-03 23:25:19 -03:00
Vector < SourcesAndDestination > src_dst_mappings ;
2026-05-14 05:25:54 -03:00
InstructionStorage extra_instruction_storage ;
2026-06-04 11:53:04 -03:00
// Pointer/size_t-sized members first, then the u32, then the bools, so the trailing scalars pack
// into one word instead of scattering padding between them.
// Native entry point for this function (conforms to the interpreter handler ABI). Zero until
// the background/AOT compile has fully installed the code. Published with an atomic store-release
// as the LAST step of install_compiled_function() and read with an atomic load-acquire at every
// execution-decision site, so a function can tier up to JIT concurrently with execution without
// a reader ever observing a half-installed function. dispatches[0].handler_ptr always stays the
// C++ interpreter handler, so the interpreter path is valid regardless of compilation state.
FlatPtr cranelift_entry = 0 ;
2026-04-22 06:48:56 -03:00
void * cranelift_code_handle = nullptr ; // Owned; freed when the owning Module is destroyed.
size_t cranelift_code_size = 0 ;
2026-06-01 13:02:57 -03:00
CraneliftTrap const * cranelift_traps = nullptr ; // Owned by cranelift_code_handle.
size_t cranelift_trap_count = 0 ;
2025-12-03 23:06:50 -03:00
size_t max_call_arg_count = 0 ;
2026-01-23 08:30:50 -03:00
size_t max_call_rec_size = 0 ;
2026-06-04 11:53:04 -03:00
u32 cranelift_result_arity = 0 ; // result count to hand to try_cranelift_compile(); only meaningful when cranelift_eligible.
bool direct = false ; // true if all dispatches contain handler_ptr, otherwise false and all contain instruction_opcode.
bool cranelift_eligible = false ; // true if this expression cleared the Cranelift type/shape checks during validation.
bool has_tier_up_checkpoints = false ; // true if try_compile_instructions inserted synthetic_tier_up ops (Tier-Up sites).
bool cranelift_compiled = false ;
2025-08-02 15:30:44 -03:00
} ;
2026-06-04 11:53:04 -03:00
// Read the native entry with acquire ordering: a non-zero result means the function is fully
// installed and every cranelift_* field written before publication is visible to this thread.
inline FlatPtr cranelift_entry_acquire ( CompiledInstructions const & ci )
{
return AK : : atomic_load ( const_cast < FlatPtr volatile * > ( & ci . cranelift_entry ) , AK : : MemoryOrder : : memory_order_acquire ) ;
}
// Publish the native entry with release ordering. Must be the LAST write of install.
inline void publish_cranelift_entry ( CompiledInstructions & ci , FlatPtr entry )
{
AK : : atomic_store ( & ci . cranelift_entry , entry , AK : : MemoryOrder : : memory_order_release ) ;
}
2025-09-24 22:35:34 -03:00
template < Enum auto . . . Vs >
consteval auto as_ordered ( )
{
using Type = CommonType < decltype ( to_underlying ( Vs ) ) . . . > ;
Array < Type , sizeof . . . ( Vs ) > result ;
[ & ] < Type . . . Is > ( IntegerSequence < Type , Is . . . > ) {
( void ) ( ( result [ to_underlying ( Vs ) ] = Is ) , . . . ) ;
} ( MakeIntegerSequence < Type , static_cast < Type > ( sizeof . . . ( Vs ) ) > ( ) ) ;
return result ;
}
2024-08-09 21:15:45 -03:00
struct SectionId {
2021-04-26 05:18:13 -03:00
public :
2024-08-09 21:15:45 -03:00
enum class SectionIdKind : u8 {
Custom ,
Type ,
Import ,
Function ,
Table ,
Memory ,
Global ,
Export ,
Start ,
Element ,
DataCount ,
Code ,
Data ,
2025-09-24 22:35:34 -03:00
Tag ,
2024-08-09 21:15:45 -03:00
} ;
2025-09-24 22:35:34 -03:00
constexpr inline static auto section_order = as_ordered <
SectionIdKind : : Type ,
SectionIdKind : : Import ,
SectionIdKind : : Function ,
SectionIdKind : : Table ,
SectionIdKind : : Memory ,
SectionIdKind : : Tag ,
SectionIdKind : : Global ,
SectionIdKind : : Export ,
SectionIdKind : : Start ,
SectionIdKind : : Element ,
SectionIdKind : : DataCount ,
SectionIdKind : : Code ,
SectionIdKind : : Data ,
SectionIdKind : : Custom > ( ) ;
2024-08-09 21:15:45 -03:00
explicit SectionId ( SectionIdKind kind )
: m_kind ( kind )
{
}
2021-04-26 05:18:13 -03:00
2025-09-24 22:35:34 -03:00
bool can_appear_after ( SectionIdKind other ) const
{
if ( kind ( ) = = SectionIdKind : : Custom | | other = = SectionIdKind : : Custom )
return true ;
auto index = section_order [ to_underlying ( kind ( ) ) ] ;
auto other_index = section_order [ to_underlying ( other ) ] ;
return index > = other_index ;
}
SectionIdKind kind ( ) const
{
return m_kind ;
}
2024-08-09 21:15:45 -03:00
static ParseResult < SectionId > parse ( Stream & stream ) ;
private :
SectionIdKind m_kind ;
} ;
class CustomSection {
public :
2023-12-16 11:19:34 -03:00
CustomSection ( ByteString name , ByteBuffer contents )
2021-04-26 05:18:13 -03:00
: m_name ( move ( name ) )
, m_contents ( move ( contents ) )
{
}
auto & name ( ) const { return m_name ; }
auto & contents ( ) const { return m_contents ; }
2025-06-06 09:11:24 -03:00
static ParseResult < CustomSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
2023-12-16 11:19:34 -03:00
ByteString m_name ;
2021-04-26 05:18:13 -03:00
ByteBuffer m_contents ;
} ;
class TypeSection {
public :
2026-06-11 01:14:58 -03:00
// https://webassembly.github.io/spec/core/syntax/types.html#recursive-types
// https://webassembly.github.io/spec/core/syntax/types.html#composite-types
2026-02-02 13:44:20 -03:00
class Type {
2026-06-11 01:39:38 -03:00
public :
2026-06-11 01:14:58 -03:00
using CompositeType = Variant < FunctionType , StructType , ArrayType > ;
2026-02-02 13:44:20 -03:00
2026-06-11 01:14:58 -03:00
struct RecGroupSpan {
u32 first_type_index { 0 } ;
u32 size { 1 } ;
} ;
Type ( CompositeType type , Vector < TypeIndex > supertypes = { } , bool is_final = true )
: m_description ( move ( type ) )
, m_supertypes ( move ( supertypes ) )
, m_is_final ( is_final )
2026-02-02 13:44:20 -03:00
{
}
auto & description ( ) const { return m_description ; }
auto & function ( ) const { return m_description . get < FunctionType > ( ) ; }
auto & unsafe_function ( ) const { return m_description . unsafe_get < FunctionType > ( ) ; }
bool is_function ( ) const { return m_description . has < FunctionType > ( ) ; }
auto & struct_ ( ) const { return m_description . get < StructType > ( ) ; }
bool is_struct ( ) const { return m_description . has < StructType > ( ) ; }
2026-06-11 01:14:58 -03:00
auto & array ( ) const { return m_description . get < ArrayType > ( ) ; }
bool is_array ( ) const { return m_description . has < ArrayType > ( ) ; }
// sub final? x* ct
auto & supertypes ( ) const { return m_supertypes ; }
bool is_final ( ) const { return m_is_final ; }
auto & rec_group ( ) const { return m_rec_group ; }
void set_rec_group ( RecGroupSpan span ) { m_rec_group = span ; }
2026-02-02 13:44:20 -03:00
ByteString name ( ) const
{
return m_description . visit (
[ ] ( FunctionType const & ) - > ByteString { return " function type " ; } ,
2026-02-08 15:09:18 -03:00
[ ] ( StructType const & ) - > ByteString { return " struct type " ; } ,
[ ] ( ArrayType const & ) - > ByteString { return " array type " ; } ) ;
2026-02-02 13:44:20 -03:00
}
2026-06-11 01:14:58 -03:00
static ParseResult < Type > parse ( ConstrainedStream & stream , Optional < u8 > leading_tag = { } ) ;
2026-02-02 13:44:20 -03:00
private :
2026-06-11 01:14:58 -03:00
CompositeType m_description ;
Vector < TypeIndex > m_supertypes ;
bool m_is_final { true } ;
RecGroupSpan m_rec_group ;
2026-02-02 13:44:20 -03:00
} ;
2024-07-29 23:56:00 -03:00
TypeSection ( ) = default ;
2026-02-02 13:44:20 -03:00
explicit TypeSection ( Vector < Type > types )
2021-04-26 05:18:13 -03:00
: m_types ( move ( types ) )
{
}
auto & types ( ) const { return m_types ; }
2025-06-06 09:11:24 -03:00
static ParseResult < TypeSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
2026-02-02 13:44:20 -03:00
Vector < Type > m_types ;
2021-04-26 05:18:13 -03:00
} ;
class ImportSection {
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
class Import {
public :
2025-09-24 22:35:34 -03:00
using ImportDesc = Variant < TypeIndex , TableType , MemoryType , GlobalType , FunctionType , TagType > ;
2023-12-16 11:19:34 -03:00
Import ( ByteString module , ByteString name , ImportDesc description )
2021-04-26 05:18:13 -03:00
: m_module ( move ( module ) )
, m_name ( move ( name ) )
, m_description ( move ( description ) )
{
}
auto & module ( ) const { return m_module ; }
auto & name ( ) const { return m_name ; }
auto & description ( ) const { return m_description ; }
2025-06-06 09:11:24 -03:00
static ParseResult < Import > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
template < typename T >
static ParseResult < Import > parse_with_type ( auto & & stream , auto & & module , auto & & name )
{
2024-05-26 22:06:26 -03:00
auto result = TRY ( T : : parse ( stream ) ) ;
return Import { module , name , result } ;
2023-07-07 23:48:11 -03:00
}
2021-04-26 05:18:13 -03:00
2023-12-16 11:19:34 -03:00
ByteString m_module ;
ByteString m_name ;
2021-04-26 05:18:13 -03:00
ImportDesc m_description ;
} ;
public :
2024-07-29 23:56:00 -03:00
ImportSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit ImportSection ( Vector < Import > imports )
: m_imports ( move ( imports ) )
{
}
auto & imports ( ) const { return m_imports ; }
2025-06-06 09:11:24 -03:00
static ParseResult < ImportSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < Import > m_imports ;
} ;
class FunctionSection {
public :
2024-07-29 23:56:00 -03:00
FunctionSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit FunctionSection ( Vector < TypeIndex > types )
: m_types ( move ( types ) )
{
}
auto & types ( ) const { return m_types ; }
2025-06-06 09:11:24 -03:00
static ParseResult < FunctionSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < TypeIndex > m_types ;
} ;
2026-06-11 02:15:32 -03:00
class Expression {
public :
explicit Expression ( Vector < Instruction > instructions )
: m_instructions ( move ( instructions ) )
{
}
auto & instructions ( ) const { return m_instructions ; }
static ParseResult < Expression > parse ( ConstrainedStream & stream , Optional < size_t > size_hint = { } ) ;
void set_stack_usage_hint ( size_t value ) const { m_stack_usage_hint = value ; }
auto stack_usage_hint ( ) const { return m_stack_usage_hint ; }
void set_frame_usage_hint ( size_t value ) const { m_frame_usage_hint = value ; }
auto frame_usage_hint ( ) const { return m_frame_usage_hint ; }
mutable CompiledInstructions compiled_instructions ;
private :
Vector < Instruction > m_instructions ;
mutable Optional < size_t > m_stack_usage_hint ;
mutable Optional < size_t > m_frame_usage_hint ;
} ;
2021-04-26 05:18:13 -03:00
class TableSection {
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
class Table {
public :
2026-06-11 02:15:32 -03:00
explicit Table ( TableType type , Expression initializer )
2021-04-26 05:18:13 -03:00
: m_type ( move ( type ) )
2026-06-11 02:15:32 -03:00
, m_initializer ( move ( initializer ) )
2021-04-26 05:18:13 -03:00
{
}
auto & type ( ) const { return m_type ; }
2026-06-11 02:15:32 -03:00
auto & initializer ( ) const { return m_initializer ; }
2021-04-26 05:18:13 -03:00
2025-06-06 09:11:24 -03:00
static ParseResult < Table > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
TableType m_type ;
2026-06-11 02:15:32 -03:00
Expression m_initializer ;
2021-04-26 05:18:13 -03:00
} ;
public :
2024-07-29 23:56:00 -03:00
TableSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit TableSection ( Vector < Table > tables )
: m_tables ( move ( tables ) )
{
}
2023-07-07 23:48:11 -03:00
auto & tables ( ) const { return m_tables ; }
2021-04-26 05:18:13 -03:00
2025-06-06 09:11:24 -03:00
static ParseResult < TableSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < Table > m_tables ;
} ;
class MemorySection {
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
class Memory {
public :
explicit Memory ( MemoryType type )
: m_type ( move ( type ) )
{
}
auto & type ( ) const { return m_type ; }
2025-06-06 09:11:24 -03:00
static ParseResult < Memory > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
MemoryType m_type ;
} ;
public :
2024-07-29 23:56:00 -03:00
MemorySection ( ) = default ;
2022-01-06 11:07:15 -03:00
explicit MemorySection ( Vector < Memory > memories )
: m_memories ( move ( memories ) )
2021-04-26 05:18:13 -03:00
{
}
auto & memories ( ) const { return m_memories ; }
2025-06-06 09:11:24 -03:00
static ParseResult < MemorySection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < Memory > m_memories ;
} ;
class GlobalSection {
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
class Global {
public :
explicit Global ( GlobalType type , Expression expression )
: m_type ( move ( type ) )
, m_expression ( move ( expression ) )
{
}
auto & type ( ) const { return m_type ; }
auto & expression ( ) const { return m_expression ; }
2025-06-06 09:11:24 -03:00
static ParseResult < Global > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
GlobalType m_type ;
Expression m_expression ;
} ;
public :
2024-07-29 23:56:00 -03:00
GlobalSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit GlobalSection ( Vector < Global > entries )
: m_entries ( move ( entries ) )
{
}
auto & entries ( ) const { return m_entries ; }
2025-06-06 09:11:24 -03:00
static ParseResult < GlobalSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < Global > m_entries ;
} ;
class ExportSection {
private :
2025-09-24 22:35:34 -03:00
using ExportDesc = Variant < FunctionIndex , TableIndex , MemoryIndex , GlobalIndex , TagIndex > ;
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
class Export {
public :
2023-12-16 11:19:34 -03:00
explicit Export ( ByteString name , ExportDesc description )
2021-04-26 05:18:13 -03:00
: m_name ( move ( name ) )
, m_description ( move ( description ) )
{
}
auto & name ( ) const { return m_name ; }
auto & description ( ) const { return m_description ; }
2025-06-06 09:11:24 -03:00
static ParseResult < Export > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
2023-12-16 11:19:34 -03:00
ByteString m_name ;
2021-04-26 05:18:13 -03:00
ExportDesc m_description ;
} ;
2024-07-29 23:56:00 -03:00
ExportSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit ExportSection ( Vector < Export > entries )
: m_entries ( move ( entries ) )
{
}
auto & entries ( ) const { return m_entries ; }
2025-06-06 09:11:24 -03:00
static ParseResult < ExportSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < Export > m_entries ;
} ;
class StartSection {
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
class StartFunction {
public :
explicit StartFunction ( FunctionIndex index )
: m_index ( index )
{
}
auto & index ( ) const { return m_index ; }
2025-06-06 09:11:24 -03:00
static ParseResult < StartFunction > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
FunctionIndex m_index ;
} ;
2024-07-29 23:56:00 -03:00
StartSection ( ) = default ;
explicit StartSection ( Optional < StartFunction > func )
2021-04-26 05:18:13 -03:00
: m_function ( move ( func ) )
{
}
auto & function ( ) const { return m_function ; }
2025-06-06 09:11:24 -03:00
static ParseResult < StartSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
2024-07-29 23:56:00 -03:00
Optional < StartFunction > m_function ;
2021-04-26 05:18:13 -03:00
} ;
class ElementSection {
2021-04-27 14:43:01 -03:00
public :
2021-05-01 15:19:17 -03:00
struct Active {
TableIndex index ;
Expression expression ;
} ;
struct Declarative {
} ;
struct Passive {
} ;
2021-04-26 05:18:13 -03:00
2021-05-01 15:19:17 -03:00
struct Element {
2025-06-06 09:11:24 -03:00
static ParseResult < Element > parse ( ConstrainedStream & ) ;
2021-06-03 20:00:09 -03:00
ValueType type ;
Vector < Expression > init ;
Variant < Active , Passive , Declarative > mode ;
2021-04-26 05:18:13 -03:00
} ;
2024-07-29 23:56:00 -03:00
ElementSection ( ) = default ;
2021-06-03 20:00:09 -03:00
explicit ElementSection ( Vector < Element > segs )
2021-05-01 15:19:17 -03:00
: m_segments ( move ( segs ) )
2021-04-26 05:18:13 -03:00
{
}
2021-05-01 15:19:17 -03:00
auto & segments ( ) const { return m_segments ; }
2021-04-26 05:18:13 -03:00
2025-06-06 09:11:24 -03:00
static ParseResult < ElementSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
2021-06-03 20:00:09 -03:00
Vector < Element > m_segments ;
2021-04-26 05:18:13 -03:00
} ;
class Locals {
public :
explicit Locals ( u32 n , ValueType type )
: m_n ( n )
, m_type ( type )
{
}
// Yikes...
auto n ( ) const { return m_n ; }
auto & type ( ) const { return m_type ; }
2025-06-06 09:11:24 -03:00
static ParseResult < Locals > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
u32 m_n { 0 } ;
ValueType m_type ;
} ;
2021-04-30 17:37:08 -03:00
class CodeSection {
2021-04-26 05:18:13 -03:00
public :
2021-04-30 17:37:08 -03:00
// https://webassembly.github.io/spec/core/bikeshed/#binary-func
class Func {
public :
explicit Func ( Vector < Locals > locals , Expression body )
: m_locals ( move ( locals ) )
, m_body ( move ( body ) )
{
2025-11-07 07:29:20 -03:00
for ( auto const & local : m_locals )
m_total_local_count + = local . n ( ) ;
2021-04-30 17:37:08 -03:00
}
2021-04-26 05:18:13 -03:00
2021-04-30 17:37:08 -03:00
auto & locals ( ) const { return m_locals ; }
auto & body ( ) const { return m_body ; }
2021-04-26 05:18:13 -03:00
2025-06-06 09:11:24 -03:00
static ParseResult < Func > parse ( ConstrainedStream & stream , size_t size_hint ) ;
2021-04-26 05:18:13 -03:00
2025-11-07 07:29:20 -03:00
auto total_local_count ( ) const { return m_total_local_count ; }
2021-04-30 17:37:08 -03:00
private :
Vector < Locals > m_locals ;
Expression m_body ;
2025-11-07 07:29:20 -03:00
size_t m_total_local_count { 0 } ;
2021-04-30 17:37:08 -03:00
} ;
2021-04-26 05:18:13 -03:00
class Code {
public :
explicit Code ( u32 size , Func func )
: m_size ( size )
, m_func ( move ( func ) )
{
}
auto size ( ) const { return m_size ; }
auto & func ( ) const { return m_func ; }
2025-06-06 09:11:24 -03:00
static ParseResult < Code > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
u32 m_size { 0 } ;
Func m_func ;
} ;
2024-07-29 23:56:00 -03:00
CodeSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit CodeSection ( Vector < Code > funcs )
: m_functions ( move ( funcs ) )
{
}
auto & functions ( ) const { return m_functions ; }
2025-06-06 09:11:24 -03:00
static ParseResult < CodeSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < Code > m_functions ;
} ;
class DataSection {
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
class Data {
2021-04-27 14:43:01 -03:00
public :
2021-04-26 05:18:13 -03:00
struct Passive {
Vector < u8 > init ;
} ;
struct Active {
Vector < u8 > init ;
MemoryIndex index ;
Expression offset ;
} ;
using Value = Variant < Passive , Active > ;
explicit Data ( Value value )
: m_value ( move ( value ) )
{
}
auto & value ( ) const { return m_value ; }
2025-06-06 09:11:24 -03:00
static ParseResult < Data > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Value m_value ;
} ;
2024-07-29 23:56:00 -03:00
DataSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit DataSection ( Vector < Data > data )
: m_data ( move ( data ) )
{
}
auto & data ( ) const { return m_data ; }
2025-06-06 09:11:24 -03:00
static ParseResult < DataSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Vector < Data > m_data ;
} ;
class DataCountSection {
public :
2024-07-29 23:56:00 -03:00
DataCountSection ( ) = default ;
2021-04-26 05:18:13 -03:00
explicit DataCountSection ( Optional < u32 > count )
: m_count ( move ( count ) )
{
}
auto & count ( ) const { return m_count ; }
2025-06-06 09:11:24 -03:00
static ParseResult < DataCountSection > parse ( ConstrainedStream & stream ) ;
2021-04-26 05:18:13 -03:00
private :
Optional < u32 > m_count ;
} ;
2025-09-24 22:35:34 -03:00
class TagSection {
public :
TagSection ( ) = default ;
2026-01-08 11:07:45 -03:00
explicit TagSection ( Vector < TagType > tags )
2025-09-24 22:35:34 -03:00
: m_tags ( move ( tags ) )
{
}
auto & tags ( ) const { return m_tags ; }
static ParseResult < TagSection > parse ( ConstrainedStream & stream ) ;
private :
2026-01-08 11:07:45 -03:00
Vector < TagType > m_tags ;
2025-09-24 22:35:34 -03:00
} ;
2026-06-02 11:59:39 -03:00
enum class CompileToNative : u8 {
No ,
Yes ,
} ;
2026-06-04 09:17:57 -03:00
// Lightweight per-module compile stats accumulator. Exposed to embedders via record_module_stats() below.
// The cranelift_* and cache_hit fields are filled in by compile_module_to_native() once native compilation actually runs (possibly on another thread).
struct ModuleStats {
Array < u8 , 32 > wasm_hash { } ;
size_t input_size_bytes { 0 } ;
AK : : Duration parse_time ;
AK : : Duration validate_time ;
AK : : Duration cranelift_time ;
size_t cranelift_blob_size_bytes { 0 } ;
size_t function_count { 0 } ;
2026-06-04 11:53:04 -03:00
size_t tier_up_function_count { 0 } ; // functions instrumented with tier-up checkpoints
size_t tier_up_checkpoint_count { 0 } ; // total tier-up checkpoints inserted across the module
2026-06-04 09:17:57 -03:00
bool cache_hit { false } ;
} ;
// Caller-supplied hooks for the Cranelift on-disk cache.
// - `wasm_hash` is a 32-byte digest of the wasm bytes; embedded in produced blobs and verified against `existing_blob` before any install.
// - `existing_blob` is the prior cache hit (or empty for a miss); the native-compile pass tries to install it before falling through to cranelift.
// Owned, since the compile may run asynchronously long after the config was assembled.
// - `on_compiled` is invoked exactly once if a fresh blob was produced; never invoked on a cache hit nor when no cranelift output was captured.
struct CompileCacheConfig {
Array < u8 , 32 > wasm_hash { } ;
ByteBuffer existing_blob ;
AK : : Function < void ( ByteBuffer ) > on_compiled ;
} ;
2026-06-02 11:59:39 -03:00
class WASM_API Module : public AtomicRefCounted < Module >
2024-08-21 20:13:37 -03:00
, public Weakable < Module > {
2021-04-27 14:43:01 -03:00
public :
2021-10-31 19:06:35 -03:00
enum class ValidationStatus {
Unchecked ,
Invalid ,
Valid ,
} ;
2021-04-26 05:18:13 -03:00
static constexpr Array < u8 , 4 > wasm_magic { 0 , ' a ' , ' s ' , ' m ' } ;
static constexpr Array < u8 , 4 > wasm_version { 1 , 0 , 0 , 0 } ;
2024-07-29 23:56:00 -03:00
Module ( ) = default ;
auto & custom_sections ( ) { return m_custom_sections ; }
auto & custom_sections ( ) const { return m_custom_sections ; }
auto & type_section ( ) const { return m_type_section ; }
auto & type_section ( ) { return m_type_section ; }
auto & import_section ( ) const { return m_import_section ; }
auto & import_section ( ) { return m_import_section ; }
auto & function_section ( ) { return m_function_section ; }
auto & function_section ( ) const { return m_function_section ; }
auto & table_section ( ) { return m_table_section ; }
auto & table_section ( ) const { return m_table_section ; }
auto & memory_section ( ) { return m_memory_section ; }
auto & memory_section ( ) const { return m_memory_section ; }
auto & global_section ( ) { return m_global_section ; }
auto & global_section ( ) const { return m_global_section ; }
auto & export_section ( ) { return m_export_section ; }
auto & export_section ( ) const { return m_export_section ; }
auto & start_section ( ) { return m_start_section ; }
auto & start_section ( ) const { return m_start_section ; }
auto & element_section ( ) { return m_element_section ; }
auto & element_section ( ) const { return m_element_section ; }
auto & code_section ( ) { return m_code_section ; }
auto & code_section ( ) const { return m_code_section ; }
auto & data_section ( ) { return m_data_section ; }
auto & data_section ( ) const { return m_data_section ; }
auto & data_count_section ( ) { return m_data_count_section ; }
auto & data_count_section ( ) const { return m_data_count_section ; }
2025-09-24 22:35:34 -03:00
auto & tag_section ( ) { return m_tag_section ; }
auto & tag_section ( ) const { return m_tag_section ; }
2021-04-27 14:43:01 -03:00
2021-10-31 19:06:35 -03:00
void set_validation_status ( ValidationStatus status , Badge < Validator > ) { set_validation_status ( status ) ; }
ValidationStatus validation_status ( ) const { return m_validation_status ; }
2025-08-30 03:18:47 -03:00
StringView validation_error ( ) const LIFETIME_BOUND { return * m_validation_error ; }
2023-12-16 11:19:34 -03:00
void set_validation_error ( ByteString error ) { m_validation_error = move ( error ) ; }
2026-06-02 11:59:39 -03:00
bool has_attempted_cranelift_compilation ( ) const { return m_cranelift_compilation_state . load ( AK : : MemoryOrder : : memory_order_acquire ) = = 2 ; }
bool try_begin_cranelift_compilation ( ) const
{
u8 not_started = 0 ;
return m_cranelift_compilation_state . compare_exchange_strong ( not_started , 1 , AK : : MemoryOrder : : memory_order_acq_rel ) ;
}
void finish_cranelift_compilation ( ) const
{
2026-06-03 16:30:38 -03:00
Sync : : MutexLocker locker ( m_cranelift_compilation_mutex ) ;
2026-06-02 11:59:39 -03:00
m_cranelift_compilation_state . store ( 2 , AK : : MemoryOrder : : memory_order_release ) ;
2026-06-03 16:30:38 -03:00
m_cranelift_compilation_state_changed . broadcast ( ) ;
2026-06-02 11:59:39 -03:00
}
void wait_for_cranelift_compilation ( ) const
{
2026-06-03 16:30:38 -03:00
if ( m_cranelift_compilation_state . load ( AK : : MemoryOrder : : memory_order_acquire ) ! = 1 )
return ;
Sync : : MutexLocker locker ( m_cranelift_compilation_mutex ) ;
m_cranelift_compilation_state_changed . wait_while ( [ this ] {
return m_cranelift_compilation_state . load ( AK : : MemoryOrder : : memory_order_acquire ) = = 1 ;
} ) ;
2026-06-02 11:59:39 -03:00
}
2021-10-31 19:06:35 -03:00
2026-06-04 09:17:57 -03:00
// Disk-cache config for native compilation. Parked here by the embedder before compilation is kicked off, and consumed by whichever path ends up driving compile_module_to_native() first.
void set_cranelift_cache_config ( CompileCacheConfig config ) { m_cranelift_cache_config = move ( config ) ; }
Optional < CompileCacheConfig > take_cranelift_cache_config ( ) { return move ( m_cranelift_cache_config ) ; }
// Compile stats parked here by the embedder; compile_module_to_native() fills in the cranelift_* / cache_hit fields once native compilation runs, then records them.
void set_compile_stats ( ModuleStats stats ) { m_compile_stats = move ( stats ) ; }
Optional < ModuleStats > take_compile_stats ( ) { return move ( m_compile_stats ) ; }
2024-08-21 20:13:37 -03:00
static ParseResult < NonnullRefPtr < Module > > parse ( Stream & stream ) ;
2021-04-26 05:18:13 -03:00
2026-01-23 08:30:50 -03:00
size_t minimum_call_record_allocation_size ( ) const { return m_minimum_call_record_allocation_size ; }
void set_minimum_call_record_allocation_size ( size_t size ) { m_minimum_call_record_allocation_size = size ; }
2026-06-11 01:39:38 -03:00
// The defined type of each (flattened) type-section entry; filled in during validation.
// https://webassembly.github.io/spec/core/valid/conventions.html#defined-types
auto & canonical_types ( ) const { return m_canonical_types ; }
void set_canonical_types ( Vector < DefinedType const * > types ) { m_canonical_types = move ( types ) ; }
2021-04-26 05:18:13 -03:00
private :
2021-10-31 19:06:35 -03:00
void set_validation_status ( ValidationStatus status ) { m_validation_status = status ; }
2025-11-07 07:29:20 -03:00
void preprocess ( ) ;
2021-04-30 17:37:08 -03:00
2024-07-29 23:56:00 -03:00
Vector < CustomSection > m_custom_sections ;
TypeSection m_type_section ;
ImportSection m_import_section ;
FunctionSection m_function_section ;
TableSection m_table_section ;
MemorySection m_memory_section ;
GlobalSection m_global_section ;
ExportSection m_export_section ;
StartSection m_start_section ;
ElementSection m_element_section ;
CodeSection m_code_section ;
DataSection m_data_section ;
DataCountSection m_data_count_section ;
2025-09-24 22:35:34 -03:00
TagSection m_tag_section ;
2024-07-29 23:56:00 -03:00
2021-10-31 19:06:35 -03:00
ValidationStatus m_validation_status { ValidationStatus : : Unchecked } ;
2023-12-16 11:19:34 -03:00
Optional < ByteString > m_validation_error ;
2026-06-02 11:59:39 -03:00
mutable Atomic < u8 > m_cranelift_compilation_state { 0 } ;
2026-06-03 16:30:38 -03:00
mutable Sync : : Mutex m_cranelift_compilation_mutex ;
mutable Sync : : ConditionVariable m_cranelift_compilation_state_changed { m_cranelift_compilation_mutex } ;
2026-06-04 09:17:57 -03:00
Optional < CompileCacheConfig > m_cranelift_cache_config ;
Optional < ModuleStats > m_compile_stats ;
2026-01-23 08:30:50 -03:00
2026-06-11 01:39:38 -03:00
Vector < DefinedType const * > m_canonical_types ;
2026-01-23 08:30:50 -03:00
size_t m_minimum_call_record_allocation_size { 0 } ;
2021-04-26 05:18:13 -03:00
} ;
2025-05-13 08:06:33 -03:00
2025-08-02 15:30:44 -03:00
CompiledInstructions try_compile_instructions ( Expression const & , Span < FunctionType const > functions ) ;
2026-06-02 11:59:39 -03:00
ErrorOr < void , ValidationError > ensure_cranelift_compiled ( Module & ) ;
WASM_API void start_cranelift_compilation ( Module & ) ;
2026-04-22 06:48:56 -03:00
bool try_cranelift_compile ( CompiledInstructions & compiled , u32 result_arity = 0 ) ;
void flush_cranelift_batch ( ) ;
2026-06-01 11:41:36 -03:00
void discard_cranelift_batch ( ) ;
2025-08-02 15:30:44 -03:00
2026-06-04 09:17:57 -03:00
void compile_module_to_native ( Module & ) ;
2026-05-11 11:35:24 -03:00
WASM_API void record_module_stats ( ModuleStats ) ;
WASM_API void dump_module_stats ( ) ;
2026-05-14 10:32:18 -03:00
// Cranelift disk-cache plumbing. Validator drives these around CodeSection validation:
// 1. set_cranelift_active_function_index() before each function so cache-hit installs
// and post-compile capture know which function they're talking about.
// 2. begin_cranelift_cache_capture() to start collecting compiled bytes + relocs.
// 3. try_install_cranelift_cache_blob() with the wasm-bytes hash + stored blob; if
// it returns true, individual try_cranelift_compile calls will short-circuit by
// installing from the stashed records instead of queueing fresh compiles.
// 4. After flush, serialize_cranelift_cache_blob() returns a blob to hand to the
// cache store (or {} if nothing was captured); abort_cranelift_cache_capture()
// throws the capture away.
void set_cranelift_active_function_index ( u32 function_index ) ;
void begin_cranelift_cache_capture ( ) ;
void abort_cranelift_cache_capture ( ) ;
void abort_cranelift_cache_install ( ) ;
Optional < ByteBuffer > serialize_cranelift_cache_blob ( ReadonlyBytes wasm_hash ) ;
bool try_install_cranelift_cache_blob ( ReadonlyBytes expected_wasm_hash , ReadonlyBytes blob ) ;
2021-04-26 05:18:13 -03:00
}