mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 06:04:57 +00:00
LibWasm: Start implementing WASI
This commit starts adding support for WASI, along with the framework to implement all the functions (though only a couple are currently implemented).
This commit is contained in:
parent
eceb244bef
commit
7e4e9fdb8f
7 changed files with 1972 additions and 1 deletions
|
@ -498,6 +498,10 @@
|
|||
# cmakedefine01 UTF8_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef WASI_DEBUG
|
||||
# cmakedefine01 WASI_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef WASM_BINPARSER_DEBUG
|
||||
# cmakedefine01 WASM_BINPARSER_DEBUG
|
||||
#endif
|
||||
|
|
|
@ -212,6 +212,7 @@ set(VOLATILE_PAGE_RANGES_DEBUG ON)
|
|||
set(VRA_DEBUG ON)
|
||||
set(WAITBLOCK_DEBUG ON)
|
||||
set(WAITQUEUE_DEBUG ON)
|
||||
set(WASI_DEBUG ON)
|
||||
set(WASM_BINPARSER_DEBUG ON)
|
||||
set(WASM_TRACE_DEBUG ON)
|
||||
set(WASM_VALIDATOR_DEBUG ON)
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
ALWAYS_INLINE Value& operator=(Value const& value) = default;
|
||||
|
||||
template<typename T>
|
||||
ALWAYS_INLINE Optional<T> to()
|
||||
ALWAYS_INLINE Optional<T> to() const
|
||||
{
|
||||
Optional<T> result;
|
||||
m_value.visit(
|
||||
|
|
|
@ -5,6 +5,7 @@ set(SOURCES
|
|||
AbstractMachine/Validator.cpp
|
||||
Parser/Parser.cpp
|
||||
Printer/Printer.cpp
|
||||
WASI/Wasi.cpp
|
||||
)
|
||||
|
||||
serenity_lib(LibWasm wasm)
|
||||
|
|
|
@ -11,5 +11,10 @@ namespace Wasm {
|
|||
class AbstractMachine;
|
||||
class Validator;
|
||||
struct ValidationError;
|
||||
struct Interpreter;
|
||||
|
||||
namespace Wasi {
|
||||
struct Implementation;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
1017
Userland/Libraries/LibWasm/WASI/Wasi.cpp
Normal file
1017
Userland/Libraries/LibWasm/WASI/Wasi.cpp
Normal file
File diff suppressed because it is too large
Load diff
943
Userland/Libraries/LibWasm/Wasi.h
Normal file
943
Userland/Libraries/LibWasm/Wasi.h
Normal file
|
@ -0,0 +1,943 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
u64 _unused : 34;
|
||||
};
|
||||
|
||||
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;
|
||||
u16 _unused : 11;
|
||||
};
|
||||
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;
|
||||
FDFlags fs_flags;
|
||||
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;
|
||||
u16 _unused : 12;
|
||||
};
|
||||
|
||||
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;
|
||||
u32 _unused : 31;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
u16 _unused : 12;
|
||||
};
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
u16 _unused : 15;
|
||||
};
|
||||
|
||||
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;
|
||||
EventRWFlags flags;
|
||||
|
||||
void serialize_into(Array<Bytes, 1> bytes) const;
|
||||
static EventFDReadWrite read_from(Array<ReadonlyBytes, 1> const& bytes);
|
||||
};
|
||||
|
||||
// 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;
|
||||
EventFDReadWrite fd_readwrite;
|
||||
|
||||
void serialize_into(Array<Bytes, 1> bytes) const;
|
||||
static Event read_from(Array<ReadonlyBytes, 1> const& bytes);
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
u16 _unused : 15;
|
||||
};
|
||||
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;
|
||||
Timestamp timeout;
|
||||
Timestamp precision;
|
||||
SubClockFlags flags;
|
||||
|
||||
void serialize_into(Array<Bytes, 1> bytes) const;
|
||||
static SubscriptionClock read_from(Array<ReadonlyBytes, 1> const& bytes);
|
||||
};
|
||||
|
||||
// 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
|
||||
struct SubscriptionU {
|
||||
u8 tag;
|
||||
union {
|
||||
SubscriptionClock clock;
|
||||
SubscriptionFDReadWrite fd_read;
|
||||
SubscriptionFDReadWrite fd_write;
|
||||
};
|
||||
|
||||
void serialize_into(Array<Bytes, 1> bytes) const;
|
||||
static SubscriptionU read_from(Array<ReadonlyBytes, 1> const& bytes);
|
||||
};
|
||||
|
||||
// https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1306
|
||||
struct Subscription {
|
||||
UserData userdata;
|
||||
SubscriptionU u;
|
||||
|
||||
void serialize_into(Array<Bytes, 1> bytes) const;
|
||||
static Subscription read_from(Array<ReadonlyBytes, 1> const& bytes);
|
||||
};
|
||||
static_assert(sizeof(Subscription) == 48);
|
||||
static_assert(alignof(Subscription) == 8);
|
||||
|
||||
// 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;
|
||||
|
||||
u16 _unused : 14;
|
||||
};
|
||||
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;
|
||||
|
||||
u16 _unused : 15;
|
||||
};
|
||||
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 {
|
||||
u8 tag;
|
||||
union {
|
||||
PreStatDir dir;
|
||||
};
|
||||
|
||||
void serialize_into(Array<Bytes, 1> bytes) const;
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
using SerializationComponents = TypeList<Size, ROFlags>;
|
||||
|
||||
void serialize_into(Array<Bytes, 2> bytes) const;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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, 0);
|
||||
m_fd_map.insert(1, 1);
|
||||
m_fd_map.insert(2, 2);
|
||||
}
|
||||
|
||||
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);
|
||||
ErrorOr<Result<void>> impl$proc_exit(Configuration&, ExitCode); // Note: noreturn.
|
||||
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());
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue