2023-04-04 21:44:43 +00:00
/*
* Copyright ( c ) 2023 , Ali Mohammad Pur < mpfard @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# pragma once
# include <AK/DistinctNumeric.h>
# include <AK/Endian.h>
# include <AK/Function.h>
# include <AK/LexicalPath.h>
# include <AK/RedBlackTree.h>
# include <AK/String.h>
# include <AK/Vector.h>
# include <LibWasm/AbstractMachine/AbstractMachine.h>
# include <LibWasm/Forward.h>
namespace Wasm : : Wasi : : ABI {
// NOTE: The "real" ABI used in the wild is described by [api.h from libc-bottom-half](https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h)
// This is *not* the same ABI as the one described in the WASI spec, nor is it the same ABI as api.h on wasi-libc/master.
// The highlights of the ABI are:
// - (most) structs are passed as pointers to heap.
// - arrays are fat pointers splat across two arguments
// - return object locations are also passed as arguments, the number of arguments depends on the return type itself:
// - ArgsSizes / EnvironSizes / the return type of sock_recv use two arguments
// - everything else is passed like a normal struct
template < auto impl >
struct InvocationOf {
HostFunction operator ( ) ( Implementation & , StringView name ) ;
} ;
template < typename T , size_t N >
void serialize ( T const & , Array < Bytes , N > ) ;
template < typename T , size_t N >
T deserialize ( Array < ReadonlyBytes , N > const & ) ;
template < typename T >
struct ToCompatibleValue {
using Type = void ;
} ;
template < typename T >
struct CompatibleValue {
typename ToCompatibleValue < T > : : Type value ;
Wasm : : Value to_wasm_value ( ) const ;
} ;
template < typename T >
CompatibleValue < T > to_compatible_value ( Wasm : : Value const & ) ;
template < typename T >
T deserialize ( CompatibleValue < T > const & ) ;
}
namespace Wasm : : Wasi {
// NOTE: This is a copy of LittleEndian from Endian.h,
// we can't use those because they have a packed attribute, and depend on it;
// but we want proper alignment on these types.
template < typename T >
class alignas ( T ) LittleEndian {
public :
constexpr LittleEndian ( ) = default ;
constexpr LittleEndian ( T value )
: m_value ( AK : : convert_between_host_and_little_endian ( value ) )
{
}
constexpr operator T ( ) const { return AK : : convert_between_host_and_little_endian ( m_value ) ; }
constexpr T value ( ) const { return AK : : convert_between_host_and_little_endian ( m_value ) ; }
LittleEndian & operator + = ( T other )
{
m_value = AK : : convert_between_host_and_little_endian ( AK : : convert_between_host_and_little_endian ( m_value ) + other ) ;
return * this ;
}
// This returns the internal representation. In this case, that is the value stored in little endian format.
constexpr Bytes bytes ( ) { return Bytes { & m_value , sizeof ( m_value ) } ; }
constexpr ReadonlyBytes bytes ( ) const { return ReadonlyBytes { & m_value , sizeof ( m_value ) } ; }
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static LittleEndian read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
private :
T m_value { 0 } ;
} ;
using Size = LittleEndian < u32 > ;
using FileSize = LittleEndian < u64 > ;
using Timestamp = LittleEndian < u64 > ;
namespace Detail {
template < typename >
struct __Pointer_tag ;
template < typename >
struct __ConstPointer_tag ;
}
// NOTE: Might need to be updated if WASI ever supports memory64.
using UnderlyingPointerType = u32 ;
template < typename T >
using Pointer = DistinctNumeric < LittleEndian < UnderlyingPointerType > , Detail : : __Pointer_tag < T > , AK : : DistinctNumericFeature : : Comparison > ;
template < typename T >
using ConstPointer = DistinctNumeric < LittleEndian < UnderlyingPointerType > , Detail : : __ConstPointer_tag < T > , AK : : DistinctNumericFeature : : Comparison > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L70
enum class ClockID : u32 {
Realtime ,
Monotonic ,
ProcessCPUTimeID ,
ThreadCPUTimeID ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L105
enum class Errno : u16 {
Success ,
TooBig ,
Access ,
AddressInUse ,
AddressNotAvailable ,
AFNotSupported ,
Again ,
Already ,
BadF ,
BadMessage ,
Busy ,
Canceled ,
Child ,
ConnectionAborted ,
ConnectionRefused ,
ConnectionReset ,
Deadlock ,
DestinationAddressRequired ,
Domain ,
DQuot , // Reserved, Unused.
Exist ,
Fault ,
FBig ,
HostUnreachable ,
IdentifierRemoved ,
IllegalSequence ,
InProgress ,
Interrupted ,
Invalid ,
IO ,
IsConnected ,
IsDirectory ,
Loop ,
MFile ,
MLink ,
MessageSize ,
MultiHop , // Reserved, Unused.
NameTooLong ,
NetworkDown ,
NetworkReset ,
NetworkUnreachable ,
NFile ,
NoBufferSpace ,
NoDevice ,
NoEntry ,
NoExec ,
NoLock ,
NoLink ,
NoMemory ,
NoMessage ,
NoProtocolOption ,
NoSpace ,
NoSys ,
NotConnected ,
NotDirectory ,
NotEmpty ,
NotRecoverable ,
NotSocket ,
NotSupported ,
NoTTY ,
NXIO ,
Overflow ,
OwnerDead ,
Permission ,
Pipe ,
Protocol ,
ProtocolNotSupported ,
ProtocolType ,
Range ,
ReadOnlyFS ,
SPipe ,
SRCH ,
Stale ,
TimedOut ,
TextBusy ,
XDev ,
NotCapable ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L498
struct Rights {
using CompatibleType = u64 ;
struct Bits {
bool fd_datasync : 1 ;
bool fd_read : 1 ;
bool fd_seek : 1 ;
bool fd_fdstat_set_flags : 1 ;
bool fd_sync : 1 ;
bool fd_tell : 1 ;
bool fd_write : 1 ;
bool fd_advise : 1 ;
bool fd_allocate : 1 ;
bool path_create_directory : 1 ;
bool path_create_file : 1 ;
bool path_link_source : 1 ;
bool path_link_target : 1 ;
bool path_open : 1 ;
bool fd_readdir : 1 ;
bool path_readlink : 1 ;
bool path_rename_source : 1 ;
bool path_rename_target : 1 ;
bool path_filestat_get : 1 ;
bool path_filestat_set_size : 1 ;
bool path_filestat_set_times : 1 ;
bool fd_filestat_get : 1 ;
bool fd_filestat_set_size : 1 ;
bool fd_filestat_set_times : 1 ;
bool path_symlink : 1 ;
bool path_remove_directory : 1 ;
bool path_unlink_file : 1 ;
bool poll_fd_readwrite : 1 ;
bool sock_shutdown : 1 ;
bool sock_accept : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 2 ;
u32 _unused2 : 32 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static Rights read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L663
using FD = DistinctNumeric < LittleEndian < u32 > , struct __FD_tag , AK : : DistinctNumericFeature : : Comparison > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L671
struct IOVec {
Pointer < u8 > buf ;
Size buf_len ;
static IOVec read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L692
struct CIOVec {
ConstPointer < u8 > buf ;
Size buf_len ;
static CIOVec read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L713
using FileDelta = LittleEndian < i64 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L721
enum class Whence : u8 {
Set ,
Cur ,
End ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L746
using DirCookie = LittleEndian < u64 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L754
using DirNameLen = LittleEndian < u32 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L762
using INode = LittleEndian < u64 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L770
enum class FileType : u8 {
Unknown ,
BlockDevice ,
CharacterDevice ,
Directory ,
RegularFile ,
SocketDGram ,
SocketStream ,
SymbolicLink ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L818
struct DirEnt {
DirCookie d_next ;
INode d_ino ;
DirNameLen d_namlen ;
FileType d_type ;
u8 _padding [ 3 ] { 0 } ; // Not part of the API, but the struct is required to be 24 bytes - even though it has no explicit padding.
} ;
static_assert ( sizeof ( DirEnt ) = = 24 ) ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L851
enum class Advice : u8 {
Normal ,
Sequential ,
Random ,
WillNeed ,
DontNeed ,
NoReuse ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L889
struct FDFlags {
using CompatibleType = u16 ;
struct Bits {
bool append : 1 ;
bool dsync : 1 ;
bool nonblock : 1 ;
bool rsync : 1 ;
bool sync : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 3 ;
u8 _unused2 : 8 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static FDFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L924
struct FDStat {
FileType fs_filetype ;
2023-09-03 16:15:40 +00:00
u8 _padding1 { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
FDFlags fs_flags ;
2023-09-03 16:15:40 +00:00
u8 _padding2 [ 4 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
Rights fs_rights_base ;
Rights fs_rights_inheriting ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
} ;
static_assert ( sizeof ( FDStat ) = = 24 ) ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L959
using Device = LittleEndian < u64 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L967
struct FSTFlags {
using CompatibleType = u16 ;
struct Bits {
bool atim : 1 ;
bool atim_now : 1 ;
bool mtim : 1 ;
bool mtim_now : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 4 ;
u8 _unused2 : 8 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static FSTFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
static_assert ( sizeof ( FSTFlags ) = = 2 ) ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L995
struct LookupFlags {
using CompatibleType = u32 ;
struct Bits {
bool symlink_follow : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 7 ;
u8 _unused2 : 8 ;
u16 _unused3 : 16 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static LookupFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
static_assert ( sizeof ( LookupFlags ) = = 4 ) ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1008
struct OFlags {
using CompatibleType = u16 ;
struct Bits {
bool creat : 1 ;
bool directory : 1 ;
bool excl : 1 ;
bool trunc : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 4 ;
u8 _unused2 : 8 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
static OFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
static_assert ( sizeof ( OFlags ) = = 2 ) ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1036
using LinkCount = LittleEndian < u64 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1044
struct FileStat {
Device dev ;
INode ino ;
FileType filetype ;
2023-09-03 16:15:40 +00:00
u8 _padding1 [ 7 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
LinkCount nlink ;
FileSize size ;
Timestamp atim ;
Timestamp mtim ;
Timestamp ctim ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
} ;
static_assert ( sizeof ( FileStat ) = = 64 ) ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1102
using UserData = LittleEndian < u64 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1110
enum class EventType : u8 {
Clock ,
FDRead ,
FDWrite ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1137
struct EventRWFlags {
using CompatibleType = u16 ;
struct Bits {
bool fd_readwrite_hangup : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 7 ;
u8 _unused2 : 8 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static EventRWFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1151
struct EventFDReadWrite {
FileSize nbytes ;
2023-09-03 16:15:40 +00:00
u8 _padding [ 4 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
EventRWFlags flags ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static EventFDReadWrite read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
2023-09-03 16:15:40 +00:00
static_assert ( sizeof ( EventFDReadWrite ) = = 16 ) ;
2023-04-04 21:44:43 +00:00
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1186
struct Event {
UserData userdata ;
Errno errno_ ;
EventType type ;
2023-09-03 16:15:40 +00:00
u8 _padding [ 5 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
EventFDReadWrite fd_readwrite ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static Event read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
2023-09-03 16:15:40 +00:00
static_assert ( sizeof ( Event ) = = 32 ) ;
2023-04-04 21:44:43 +00:00
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1220
struct SubClockFlags {
using CompatibleType = u16 ;
struct Bits {
bool subscription_clock_abstime : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 7 ;
u8 _unused2 : 8 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static SubClockFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1237
struct SubscriptionClock {
ClockID id ;
2023-09-03 16:15:40 +00:00
u8 _padding1 [ 4 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
Timestamp timeout ;
Timestamp precision ;
SubClockFlags flags ;
2023-09-03 16:15:40 +00:00
u8 _padding2 [ 4 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static SubscriptionClock read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
2023-09-03 16:15:40 +00:00
static_assert ( sizeof ( SubscriptionClock ) = = 32 ) ;
2023-04-04 21:44:43 +00:00
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1272
struct SubscriptionFDReadWrite {
FD file_descriptor ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static SubscriptionFDReadWrite read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1287
2023-09-03 16:15:40 +00:00
union SubscriptionU {
SubscriptionClock clock ;
SubscriptionFDReadWrite fd_read ;
SubscriptionFDReadWrite fd_write ;
2023-04-04 21:44:43 +00:00
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1306
struct Subscription {
UserData userdata ;
2023-09-03 16:15:40 +00:00
EventType type ;
u8 _padding [ 7 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
SubscriptionU u ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static Subscription read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
static_assert ( sizeof ( Subscription ) = = 48 ) ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1334
using ExitCode = LittleEndian < u32 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1342
enum class Signal : u8 {
None ,
HUP ,
INT ,
QUIT ,
ILL ,
TRAP ,
ABRT ,
BUS ,
FPE ,
KILL ,
USR1 ,
SEGV ,
USR2 ,
PIPE ,
ALRM ,
TERM ,
CHLD ,
CONT ,
STOP ,
TSTP ,
TTIN ,
TTOU ,
URG ,
XCPU ,
XFSZ ,
VTALRM ,
PROF ,
WINCH ,
POLL ,
PWR ,
SYS ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1536
struct RIFlags {
using CompatibleType = u16 ;
struct Bits {
bool recv_peek : 1 ;
bool recv_waitall : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 6 ;
u8 _unused2 : 8 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
static RIFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1554
struct ROFlags {
using CompatibleType = u16 ;
struct Bits {
bool recv_data_truncated : 1 ;
2023-11-04 03:59:15 +00:00
u8 _unused1 : 7 ;
u8 _unused2 : 8 ;
2023-04-04 21:44:43 +00:00
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1568
using SIFlags = LittleEndian < u16 > ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1576
struct SDFlags {
using CompatibleType = u8 ;
struct Bits {
bool rd : 1 ;
bool wr : 1 ;
u8 _unused : 6 ;
} ;
static_assert ( sizeof ( Bits ) = = sizeof ( CompatibleType ) ) ;
union {
Bits bits ;
LittleEndian < CompatibleType > data ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static SDFlags read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1594
enum class PreOpenType : u8 {
Dir ,
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1607
struct PreStatDir {
Size pr_name_len ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
static PreStatDir read_from ( Array < ReadonlyBytes , 1 > const & bytes ) ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1636
struct PreStat {
2023-09-03 16:15:40 +00:00
PreOpenType type ;
u8 _padding [ 3 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
union {
PreStatDir dir ;
} ;
void serialize_into ( Array < Bytes , 1 > bytes ) const ;
} ;
2023-09-03 16:15:40 +00:00
static_assert ( sizeof ( PreStat ) = = 8 ) ;
2023-04-04 21:44:43 +00:00
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1676
struct ArgsSizes {
Size count ;
Size size ;
using SerializationComponents = TypeList < Size , Size > ;
void serialize_into ( Array < Bytes , 2 > bytes ) const ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1708
struct EnvironSizes {
Size count ;
Size size ;
using SerializationComponents = TypeList < Size , Size > ;
void serialize_into ( Array < Bytes , 2 > bytes ) const ;
} ;
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L2664
struct SockRecvResult {
Size size ;
ROFlags roflags ;
2023-09-03 16:15:40 +00:00
u8 _padding [ 2 ] { 0 } ; // Not part of the API.
2023-04-04 21:44:43 +00:00
using SerializationComponents = TypeList < Size , ROFlags > ;
void serialize_into ( Array < Bytes , 2 > bytes ) const ;
} ;
2023-09-03 16:15:40 +00:00
static_assert ( sizeof ( SockRecvResult ) = = 8 ) ;
2023-04-04 21:44:43 +00:00
template < typename TResult , typename Tag = u32 >
struct Result {
Result ( TResult & & result )
: bits { }
, tag ( 0 )
{
new ( & bits ) TResult ( move ( result ) ) ;
}
Result ( Errno & & error )
: bits { }
, tag ( 1 )
{
new ( & bits ) Errno ( error ) ;
}
Optional < TResult & > result ( ) const
{
if ( tag = = 0 )
return * bit_cast < TResult * > ( & bits [ 0 ] ) ;
return { } ;
}
Optional < Errno & > error ( ) const
{
if ( tag = = 1 )
return * bit_cast < Errno * > ( & bits [ 0 ] ) ;
return { } ;
}
bool is_error ( ) const { return tag = = 1 ; }
template < size_t N >
Errno serialize_into ( Array < Bytes , N > & & spans ) const
{
if ( tag = = 1 )
return error ( ) . value ( ) ;
ABI : : serialize ( * result ( ) , move ( spans ) ) ;
return Errno : : Success ;
}
private :
alignas ( max ( alignof ( TResult ) , alignof ( Errno ) ) ) u8 bits [ max ( sizeof ( TResult ) , sizeof ( Errno ) ) ] ;
LittleEndian < Tag > tag ;
} ;
template < typename Tag >
struct Result < void , Tag > {
Result ( )
: error_bits { }
, tag ( 0 )
{
}
Result ( Errno & & error )
: error_bits { }
, tag ( 1 )
{
new ( & error_bits ) Errno ( error ) ;
}
Optional < Empty > result ( ) const
{
if ( tag = = 0 )
return { Empty { } } ;
return { } ;
}
Optional < Errno & > error ( ) const
{
if ( tag = = 1 )
return * bit_cast < Errno * > ( & error_bits [ 0 ] ) ;
return { } ;
}
bool is_error ( ) const { return tag = = 1 ; }
private :
alignas ( Errno ) u8 error_bits [ sizeof ( Errno ) ] ;
LittleEndian < Tag > tag ;
} ;
struct Implementation {
struct MappedPath {
LexicalPath host_path ;
LexicalPath mapped_path ;
mutable Optional < int > opened_fd { } ;
} ;
struct Details {
Function < Vector < AK : : String > ( ) > provide_arguments ;
Function < Vector < AK : : String > ( ) > provide_environment ;
Function < Vector < MappedPath > ( ) > provide_preopened_directories ;
2024-07-16 15:51:32 +00:00
int stdin_fd { 0 } ;
int stdout_fd { 1 } ;
int stderr_fd { 2 } ;
2023-04-04 21:44:43 +00:00
} ;
explicit Implementation ( Details & & details )
: provide_arguments ( move ( details . provide_arguments ) )
, provide_environment ( move ( details . provide_environment ) )
, provide_preopened_directories ( move ( details . provide_preopened_directories ) )
{
// Map all of std{in,out,err} by default.
2024-07-16 15:51:32 +00:00
m_fd_map . insert ( 0 , details . stdin_fd ) ;
m_fd_map . insert ( 1 , details . stdout_fd ) ;
m_fd_map . insert ( 2 , details . stderr_fd ) ;
2023-04-04 21:44:43 +00:00
}
ErrorOr < HostFunction > function_by_name ( StringView ) ;
private :
template < auto impl >
HostFunction invocation_of ( StringView name ) { return ABI : : InvocationOf < impl > { } ( * this , name ) ; }
ErrorOr < Result < void > > impl $ args_get ( Configuration & , Pointer < Pointer < u8 > > argv , Pointer < u8 > argv_buf ) ;
ErrorOr < Result < ArgsSizes > > impl $ args_sizes_get ( Configuration & ) ;
ErrorOr < Result < void > > impl $ environ_get ( Configuration & , Pointer < Pointer < u8 > > environ , Pointer < u8 > environ_buf ) ;
ErrorOr < Result < EnvironSizes > > impl $ environ_sizes_get ( Configuration & ) ;
ErrorOr < Result < Timestamp > > impl $ clock_res_get ( Configuration & , ClockID id ) ;
ErrorOr < Result < Timestamp > > impl $ clock_time_get ( Configuration & , ClockID id , Timestamp precision ) ;
ErrorOr < Result < void > > impl $ fd_advise ( Configuration & , FD , FileSize offset , FileSize len , Advice ) ;
ErrorOr < Result < void > > impl $ fd_allocate ( Configuration & , FD , FileSize offset , FileSize len ) ;
ErrorOr < Result < void > > impl $ fd_close ( Configuration & , FD ) ;
ErrorOr < Result < void > > impl $ fd_datasync ( Configuration & , FD ) ;
ErrorOr < Result < FDStat > > impl $ fd_fdstat_get ( Configuration & , FD ) ;
ErrorOr < Result < void > > impl $ fd_fdstat_set_flags ( Configuration & , FD , FDFlags ) ;
ErrorOr < Result < void > > impl $ fd_fdstat_set_rights ( Configuration & , FD , Rights fs_rights_base , Rights fs_rights_inheriting ) ;
ErrorOr < Result < FileStat > > impl $ fd_filestat_get ( Configuration & , FD ) ;
ErrorOr < Result < void > > impl $ fd_filestat_set_size ( Configuration & , FD , FileSize ) ;
ErrorOr < Result < void > > impl $ fd_filestat_set_times ( Configuration & , FD , Timestamp atim , Timestamp mtim , FSTFlags ) ;
ErrorOr < Result < Size > > impl $ fd_pread ( Configuration & , FD , Pointer < IOVec > iovs , Size iovs_len , FileSize offset ) ;
ErrorOr < Result < PreStat > > impl $ fd_prestat_get ( Configuration & , FD ) ;
ErrorOr < Result < void > > impl $ fd_prestat_dir_name ( Configuration & , FD , Pointer < u8 > path , Size path_len ) ;
ErrorOr < Result < Size > > impl $ fd_pwrite ( Configuration & , FD , Pointer < CIOVec > iovs , Size iovs_len , FileSize offset ) ;
ErrorOr < Result < Size > > impl $ fd_read ( Configuration & , FD , Pointer < IOVec > iovs , Size iovs_len ) ;
ErrorOr < Result < Size > > impl $ fd_readdir ( Configuration & , FD , Pointer < u8 > buf , Size buf_len , DirCookie cookie ) ;
ErrorOr < Result < void > > impl $ fd_renumber ( Configuration & , FD from , FD to ) ;
ErrorOr < Result < FileSize > > impl $ fd_seek ( Configuration & , FD , FileDelta offset , Whence whence ) ;
ErrorOr < Result < void > > impl $ fd_sync ( Configuration & , FD ) ;
ErrorOr < Result < FileSize > > impl $ fd_tell ( Configuration & , FD ) ;
ErrorOr < Result < Size > > impl $ fd_write ( Configuration & , FD , Pointer < CIOVec > iovs , Size iovs_len ) ;
ErrorOr < Result < void > > impl $ path_create_directory ( Configuration & , FD , Pointer < u8 > path , Size path_len ) ;
ErrorOr < Result < FileStat > > impl $ path_filestat_get ( Configuration & , FD , LookupFlags , ConstPointer < u8 > path , Size path_len ) ;
ErrorOr < Result < void > > impl $ path_filestat_set_times ( Configuration & , FD , LookupFlags , Pointer < u8 > path , Size path_len , Timestamp atim , Timestamp mtim , FSTFlags ) ;
ErrorOr < Result < void > > impl $ path_link ( Configuration & , FD , LookupFlags , Pointer < u8 > old_path , Size old_path_len , FD , Pointer < u8 > new_path , Size new_path_len ) ;
ErrorOr < Result < FD > > impl $ path_open ( Configuration & , FD , LookupFlags , Pointer < u8 > path , Size path_len , OFlags , Rights fs_rights_base , Rights fs_rights_inheriting , FDFlags fd_flags ) ;
ErrorOr < Result < Size > > impl $ path_readlink ( Configuration & , FD , LookupFlags , Pointer < u8 > path , Size path_len , Pointer < u8 > buf , Size buf_len ) ;
ErrorOr < Result < void > > impl $ path_remove_directory ( Configuration & , FD , Pointer < u8 > path , Size path_len ) ;
ErrorOr < Result < void > > impl $ path_rename ( Configuration & , FD , Pointer < u8 > old_path , Size old_path_len , FD , Pointer < u8 > new_path , Size new_path_len ) ;
ErrorOr < Result < void > > impl $ path_symlink ( Configuration & , Pointer < u8 > old_path , Size old_path_len , FD , Pointer < u8 > new_path , Size new_path_len ) ;
ErrorOr < Result < void > > impl $ path_unlink_file ( Configuration & , FD , Pointer < u8 > path , Size path_len ) ;
ErrorOr < Result < Size > > impl $ poll_oneoff ( Configuration & , ConstPointer < Subscription > in , Pointer < Event > out , Size nsubscriptions ) ;
2024-07-16 15:49:48 +00:00
ErrorOr < void > impl $ proc_exit ( Configuration & , ExitCode ) ;
2023-04-04 21:44:43 +00:00
ErrorOr < Result < void > > impl $ proc_raise ( Configuration & , Signal ) ;
ErrorOr < Result < void > > impl $ sched_yield ( Configuration & ) ;
ErrorOr < Result < void > > impl $ random_get ( Configuration & , Pointer < u8 > buf , Size buf_len ) ;
ErrorOr < Result < FD > > impl $ sock_accept ( Configuration & , FD fd , FDFlags fd_flags ) ;
ErrorOr < Result < SockRecvResult > > impl $ sock_recv ( Configuration & , FD fd , Pointer < IOVec > ri_data , Size ri_data_len , RIFlags ri_flags ) ;
ErrorOr < Result < Size > > impl $ sock_send ( Configuration & , FD fd , Pointer < CIOVec > si_data , Size ri_data_len , SIFlags si_flags ) ;
ErrorOr < Result < void > > impl $ sock_shutdown ( Configuration & , FD fd , SDFlags how ) ;
Vector < AK : : String > const & arguments ( ) const ;
Vector < AK : : String > const & environment ( ) const ;
Vector < MappedPath > const & preopened_directories ( ) const ;
using PreopenedDirectoryDescriptor = DistinctNumeric < LittleEndian < size_t > , struct PreopenedDirectoryDescriptor_tag , AK : : DistinctNumericFeature : : Comparison , AK : : DistinctNumericFeature : : CastToUnderlying , AK : : DistinctNumericFeature : : Increment > ;
using UnmappedDescriptor = DistinctNumeric < LittleEndian < size_t > , struct UnmappedDescriptor_tag , AK : : DistinctNumericFeature : : Comparison , AK : : DistinctNumericFeature : : CastToUnderlying > ;
using MappedDescriptor = Variant < u32 , PreopenedDirectoryDescriptor > ;
using Descriptor = Variant < u32 , PreopenedDirectoryDescriptor , UnmappedDescriptor > ;
Descriptor map_fd ( FD ) ;
public :
Function < Vector < AK : : String > ( ) > provide_arguments ;
Function < Vector < AK : : String > ( ) > provide_environment ;
Function < Vector < MappedPath > ( ) > provide_preopened_directories ;
private :
struct Cache {
Optional < Vector < AK : : String > > cached_arguments ;
Optional < Vector < AK : : String > > cached_environment ;
Optional < Vector < MappedPath > > cached_preopened_directories ;
} ;
mutable Cache cache { } ;
RedBlackTree < u32 , MappedDescriptor > m_fd_map ;
size_t m_first_unmapped_preopened_directory_index { 0 } ;
} ;
# undef IMPL
}
namespace Wasm : : Wasi : : ABI {
template < typename T , typename . . . Args >
struct ToCompatibleValue < DistinctNumeric < T , Args . . . > > {
using Type = typename ToCompatibleValue < T > : : Type ;
} ;
template < typename T >
struct ToCompatibleValue < LittleEndian < T > > {
using Type = MakeSigned < T > ;
} ;
template < typename T >
requires ( requires { declval < typename T : : CompatibleType > ( ) ; } )
struct ToCompatibleValue < T > {
using Type = MakeSigned < typename T : : CompatibleType > ;
} ;
template < Integral T >
struct ToCompatibleValue < T > {
using Type = MakeSigned < T > ;
} ;
template < Enum T >
struct ToCompatibleValue < T > {
using Type = MakeSigned < UnderlyingType < T > > ;
} ;
}
template < typename T >
struct AK : : Formatter < Wasm : : Wasi : : LittleEndian < T > > : AK : : Formatter < T > {
ErrorOr < void > format ( FormatBuilder & builder , Wasm : : Wasi : : LittleEndian < T > value )
{
return Formatter < T > : : format ( builder , value . operator T ( ) ) ;
}
} ;