/* * Copyright (c) 2023, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include 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 struct InvocationOf { HostFunction operator()(Implementation&, StringView name); }; template void serialize(T const&, Array); template T deserialize(Array const&); template struct ToCompatibleValue { using Type = void; }; template struct CompatibleValue { typename ToCompatibleValue::Type value; Wasm::Value to_wasm_value() const; }; template CompatibleValue to_compatible_value(Wasm::Value const&); template T deserialize(CompatibleValue 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 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) const; static LittleEndian read_from(Array const& bytes); private: T m_value { 0 }; }; using Size = LittleEndian; using FileSize = LittleEndian; using Timestamp = LittleEndian; namespace Detail { template struct __Pointer_tag; template struct __ConstPointer_tag; } // NOTE: Might need to be updated if WASI ever supports memory64. using UnderlyingPointerType = u32; template using Pointer = DistinctNumeric, Detail::__Pointer_tag, AK::DistinctNumericFeature::Comparison>; template using ConstPointer = DistinctNumeric, Detail::__ConstPointer_tag, 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; u8 _unused1 : 2; u32 _unused2 : 32; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; void serialize_into(Array bytes) const; static Rights read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L663 using FD = DistinctNumeric, 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 buf; Size buf_len; static IOVec read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L692 struct CIOVec { ConstPointer buf; Size buf_len; static CIOVec read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L713 using FileDelta = LittleEndian; // 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; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L754 using DirNameLen = LittleEndian; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L762 using INode = LittleEndian; // 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; u8 _unused1 : 3; u8 _unused2 : 8; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; void serialize_into(Array bytes) const; static FDFlags read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L924 struct FDStat { FileType fs_filetype; u8 _padding1 { 0 }; // Not part of the API. FDFlags fs_flags; u8 _padding2[4] { 0 }; // Not part of the API. Rights fs_rights_base; Rights fs_rights_inheriting; void serialize_into(Array 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; // 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; u8 _unused1 : 4; u8 _unused2 : 8; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; void serialize_into(Array bytes) const; static FSTFlags read_from(Array 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; u8 _unused1 : 7; u8 _unused2 : 8; u16 _unused3 : 16; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; void serialize_into(Array bytes) const; static LookupFlags read_from(Array 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; u8 _unused1 : 4; u8 _unused2 : 8; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; static OFlags read_from(Array 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; // 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; u8 _padding1[7] { 0 }; // Not part of the API. LinkCount nlink; FileSize size; Timestamp atim; Timestamp mtim; Timestamp ctim; void serialize_into(Array 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; // 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; u8 _unused1 : 7; u8 _unused2 : 8; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; void serialize_into(Array bytes) const; static EventRWFlags read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1151 struct EventFDReadWrite { FileSize nbytes; u8 _padding[4] { 0 }; // Not part of the API. EventRWFlags flags; void serialize_into(Array bytes) const; static EventFDReadWrite read_from(Array const& bytes); }; static_assert(sizeof(EventFDReadWrite) == 16); // 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; u8 _padding[5] { 0 }; // Not part of the API. EventFDReadWrite fd_readwrite; void serialize_into(Array bytes) const; static Event read_from(Array const& bytes); }; static_assert(sizeof(Event) == 32); // 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; u8 _unused1 : 7; u8 _unused2 : 8; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; void serialize_into(Array bytes) const; static SubClockFlags read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1237 struct SubscriptionClock { ClockID id; u8 _padding1[4] { 0 }; // Not part of the API. Timestamp timeout; Timestamp precision; SubClockFlags flags; u8 _padding2[4] { 0 }; // Not part of the API. void serialize_into(Array bytes) const; static SubscriptionClock read_from(Array const& bytes); }; static_assert(sizeof(SubscriptionClock) == 32); // 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) const; static SubscriptionFDReadWrite read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1287 union SubscriptionU { SubscriptionClock clock; SubscriptionFDReadWrite fd_read; SubscriptionFDReadWrite fd_write; }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1306 struct Subscription { UserData userdata; EventType type; u8 _padding[7] { 0 }; // Not part of the API. SubscriptionU u; void serialize_into(Array bytes) const; static Subscription read_from(Array 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; // 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; u8 _unused1 : 6; u8 _unused2 : 8; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; static RIFlags read_from(Array 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; u8 _unused1 : 7; u8 _unused2 : 8; }; static_assert(sizeof(Bits) == sizeof(CompatibleType)); union { Bits bits; LittleEndian data; }; void serialize_into(Array bytes) const; }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1568 using SIFlags = LittleEndian; // 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 data; }; void serialize_into(Array bytes) const; static SDFlags read_from(Array 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) const; static PreStatDir read_from(Array const& bytes); }; // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1636 struct PreStat { PreOpenType type; u8 _padding[3] { 0 }; // Not part of the API. union { PreStatDir dir; }; void serialize_into(Array bytes) const; }; static_assert(sizeof(PreStat) == 8); // 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; void serialize_into(Array 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; void serialize_into(Array 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; u8 _padding[2] { 0 }; // Not part of the API. using SerializationComponents = TypeList; void serialize_into(Array bytes) const; }; static_assert(sizeof(SockRecvResult) == 8); template struct Result { Result(TResult&& result) : bits {} , tag(0) { new (&bits) TResult(move(result)); } Result(Errno&& error) : bits {} , tag(1) { new (&bits) Errno(error); } Optional result() const { if (tag == 0) return *bit_cast(&bits[0]); return {}; } Optional error() const { if (tag == 1) return *bit_cast(&bits[0]); return {}; } bool is_error() const { return tag == 1; } template Errno serialize_into(Array&& 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; }; template struct Result { Result() : error_bits {} , tag(0) { } Result(Errno&& error) : error_bits {} , tag(1) { new (&error_bits) Errno(error); } Optional result() const { if (tag == 0) return { Empty {} }; return {}; } Optional error() const { if (tag == 1) return *bit_cast(&error_bits[0]); return {}; } bool is_error() const { return tag == 1; } private: alignas(Errno) u8 error_bits[sizeof(Errno)]; LittleEndian tag; }; struct Implementation { struct MappedPath { LexicalPath host_path; LexicalPath mapped_path; mutable Optional opened_fd {}; }; struct Details { Function()> provide_arguments; Function()> provide_environment; Function()> provide_preopened_directories; int stdin_fd { 0 }; int stdout_fd { 1 }; int stderr_fd { 2 }; }; 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. m_fd_map.insert(0, details.stdin_fd); m_fd_map.insert(1, details.stdout_fd); m_fd_map.insert(2, details.stderr_fd); } ErrorOr function_by_name(StringView); private: template HostFunction invocation_of(StringView name) { return ABI::InvocationOf {}(*this, name); } ErrorOr> impl$args_get(Configuration&, Pointer> argv, Pointer argv_buf); ErrorOr> impl$args_sizes_get(Configuration&); ErrorOr> impl$environ_get(Configuration&, Pointer> environ, Pointer environ_buf); ErrorOr> impl$environ_sizes_get(Configuration&); ErrorOr> impl$clock_res_get(Configuration&, ClockID id); ErrorOr> impl$clock_time_get(Configuration&, ClockID id, Timestamp precision); ErrorOr> impl$fd_advise(Configuration&, FD, FileSize offset, FileSize len, Advice); ErrorOr> impl$fd_allocate(Configuration&, FD, FileSize offset, FileSize len); ErrorOr> impl$fd_close(Configuration&, FD); ErrorOr> impl$fd_datasync(Configuration&, FD); ErrorOr> impl$fd_fdstat_get(Configuration&, FD); ErrorOr> impl$fd_fdstat_set_flags(Configuration&, FD, FDFlags); ErrorOr> impl$fd_fdstat_set_rights(Configuration&, FD, Rights fs_rights_base, Rights fs_rights_inheriting); ErrorOr> impl$fd_filestat_get(Configuration&, FD); ErrorOr> impl$fd_filestat_set_size(Configuration&, FD, FileSize); ErrorOr> impl$fd_filestat_set_times(Configuration&, FD, Timestamp atim, Timestamp mtim, FSTFlags); ErrorOr> impl$fd_pread(Configuration&, FD, Pointer iovs, Size iovs_len, FileSize offset); ErrorOr> impl$fd_prestat_get(Configuration&, FD); ErrorOr> impl$fd_prestat_dir_name(Configuration&, FD, Pointer path, Size path_len); ErrorOr> impl$fd_pwrite(Configuration&, FD, Pointer iovs, Size iovs_len, FileSize offset); ErrorOr> impl$fd_read(Configuration&, FD, Pointer iovs, Size iovs_len); ErrorOr> impl$fd_readdir(Configuration&, FD, Pointer buf, Size buf_len, DirCookie cookie); ErrorOr> impl$fd_renumber(Configuration&, FD from, FD to); ErrorOr> impl$fd_seek(Configuration&, FD, FileDelta offset, Whence whence); ErrorOr> impl$fd_sync(Configuration&, FD); ErrorOr> impl$fd_tell(Configuration&, FD); ErrorOr> impl$fd_write(Configuration&, FD, Pointer iovs, Size iovs_len); ErrorOr> impl$path_create_directory(Configuration&, FD, Pointer path, Size path_len); ErrorOr> impl$path_filestat_get(Configuration&, FD, LookupFlags, ConstPointer path, Size path_len); ErrorOr> impl$path_filestat_set_times(Configuration&, FD, LookupFlags, Pointer path, Size path_len, Timestamp atim, Timestamp mtim, FSTFlags); ErrorOr> impl$path_link(Configuration&, FD, LookupFlags, Pointer old_path, Size old_path_len, FD, Pointer new_path, Size new_path_len); ErrorOr> impl$path_open(Configuration&, FD, LookupFlags, Pointer path, Size path_len, OFlags, Rights fs_rights_base, Rights fs_rights_inheriting, FDFlags fd_flags); ErrorOr> impl$path_readlink(Configuration&, FD, LookupFlags, Pointer path, Size path_len, Pointer buf, Size buf_len); ErrorOr> impl$path_remove_directory(Configuration&, FD, Pointer path, Size path_len); ErrorOr> impl$path_rename(Configuration&, FD, Pointer old_path, Size old_path_len, FD, Pointer new_path, Size new_path_len); ErrorOr> impl$path_symlink(Configuration&, Pointer old_path, Size old_path_len, FD, Pointer new_path, Size new_path_len); ErrorOr> impl$path_unlink_file(Configuration&, FD, Pointer path, Size path_len); ErrorOr> impl$poll_oneoff(Configuration&, ConstPointer in, Pointer out, Size nsubscriptions); ErrorOr impl$proc_exit(Configuration&, ExitCode); ErrorOr> impl$proc_raise(Configuration&, Signal); ErrorOr> impl$sched_yield(Configuration&); ErrorOr> impl$random_get(Configuration&, Pointer buf, Size buf_len); ErrorOr> impl$sock_accept(Configuration&, FD fd, FDFlags fd_flags); ErrorOr> impl$sock_recv(Configuration&, FD fd, Pointer ri_data, Size ri_data_len, RIFlags ri_flags); ErrorOr> impl$sock_send(Configuration&, FD fd, Pointer si_data, Size ri_data_len, SIFlags si_flags); ErrorOr> impl$sock_shutdown(Configuration&, FD fd, SDFlags how); Vector const& arguments() const; Vector const& environment() const; Vector const& preopened_directories() const; using PreopenedDirectoryDescriptor = DistinctNumeric, struct PreopenedDirectoryDescriptor_tag, AK::DistinctNumericFeature::Comparison, AK::DistinctNumericFeature::CastToUnderlying, AK::DistinctNumericFeature::Increment>; using UnmappedDescriptor = DistinctNumeric, struct UnmappedDescriptor_tag, AK::DistinctNumericFeature::Comparison, AK::DistinctNumericFeature::CastToUnderlying>; using MappedDescriptor = Variant; using Descriptor = Variant; Descriptor map_fd(FD); public: Function()> provide_arguments; Function()> provide_environment; Function()> provide_preopened_directories; private: struct Cache { Optional> cached_arguments; Optional> cached_environment; Optional> cached_preopened_directories; }; mutable Cache cache {}; RedBlackTree m_fd_map; size_t m_first_unmapped_preopened_directory_index { 0 }; }; #undef IMPL } namespace Wasm::Wasi::ABI { template struct ToCompatibleValue> { using Type = typename ToCompatibleValue::Type; }; template struct ToCompatibleValue> { using Type = MakeSigned; }; template requires(requires { declval(); }) struct ToCompatibleValue { using Type = MakeSigned; }; template struct ToCompatibleValue { using Type = MakeSigned; }; template struct ToCompatibleValue { using Type = MakeSigned>; }; } template struct AK::Formatter> : AK::Formatter { ErrorOr format(FormatBuilder& builder, Wasm::Wasi::LittleEndian value) { return Formatter::format(builder, value.operator T()); } };