diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ee525..ceb49fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ include("wasmtime") include("fmt") include("spidermonkey") include("openssl") -include("host_api") +include("${HOST_API}/host_api.cmake") include("build-crates") add_library(extension_api INTERFACE include/extension-api.h runtime/encode.h runtime/decode.h) diff --git a/host-apis/wasi-0.2.0/handles.h b/host-apis/wasi-0.2.0/handles.h new file mode 100644 index 0000000..74fbf1a --- /dev/null +++ b/host-apis/wasi-0.2.0/handles.h @@ -0,0 +1,254 @@ +/** + * NOT PART OF THE PUBLIC INTERFACE! + * + * Types for dealing with WASI handles in the wit-bindgen generated C bindings. + */ + +#ifndef HANDLES_H +#define HANDLES_H + +#include "host_api.h" +#include "bindings/bindings.h" + +#include +#include +#ifdef DEBUG +#include +#endif + +using host_api::HostString; +using std::optional; +using std::string_view; +using std::tuple; +using std::unique_ptr; +using std::vector; + +// The host interface makes the assumption regularly that uint32_t is sufficient space to store a +// pointer. +static_assert(sizeof(uint32_t) == sizeof(void *)); + +typedef wasi_http_types_own_future_incoming_response_t future_incoming_response_t; +typedef wasi_http_types_borrow_future_incoming_response_t borrow_future_incoming_response_t; + +typedef wasi_http_types_own_incoming_body_t incoming_body_t; +typedef wasi_http_types_own_outgoing_body_t outgoing_body_t; + +using field_key = wasi_http_types_field_key_t; +using field_value = wasi_http_types_field_value_t; + +typedef wasi_io_poll_own_pollable_t own_pollable_t; +typedef wasi_io_poll_borrow_pollable_t borrow_pollable_t; +typedef wasi_io_poll_list_borrow_pollable_t list_borrow_pollable_t; + +#ifdef LOG_HANDLE_OPS +#define LOG_HANDLE_OP(...) \ + fprintf(stderr, "%s", __PRETTY_FUNCTION__); \ + fprintf(stderr, __VA_ARGS__) +#else +#define LOG_HANDLE_OP(...) +#endif + +/// The type of handles used by the host interface. +typedef int32_t Handle; +constexpr Handle POISONED_HANDLE = -1; + +class host_api::HandleState { +protected: + HandleState() = default; + +public: + virtual ~HandleState() = default; + virtual bool valid() const = 0; +}; + +template struct HandleOps {}; + +template class WASIHandle : public host_api::HandleState { +#ifdef DEBUG + static inline auto used_handles = std::set(); +#endif + +protected: + Handle handle_; +#ifdef DEBUG + bool owned_; +#endif + +public: + using Borrowed = typename HandleOps::borrowed; + + explicit WASIHandle(typename HandleOps::owned handle) : handle_{handle.__handle} { + LOG_HANDLE_OP("Creating owned handle %d\n", handle.__handle); +#ifdef DEBUG + owned_ = true; + MOZ_ASSERT(!used_handles.contains(handle.__handle)); + used_handles.insert(handle.__handle); +#endif + } + + explicit WASIHandle(typename HandleOps::borrowed handle) : handle_{handle.__handle} { + LOG_HANDLE_OP("Creating borrowed handle %d\n", handle.__handle); +#ifdef DEBUG + owned_ = false; + MOZ_ASSERT(!used_handles.contains(handle.__handle)); + used_handles.insert(handle.__handle); +#endif + } + + ~WASIHandle() override { +#ifdef DEBUG + if (handle_ != POISONED_HANDLE) { + LOG_HANDLE_OP("Deleting (owned? %d) handle %d\n", owned_, handle_); + MOZ_ASSERT(used_handles.contains(handle_)); + used_handles.erase(handle_); + } +#endif + } + + static WASIHandle *cast(HandleState *handle) { + return reinterpret_cast *>(handle); + } + + typename HandleOps::borrowed borrow(HandleState *handle) { return cast(handle)->borrow(); } + + bool valid() const override { + bool valid = handle_ != POISONED_HANDLE; + MOZ_ASSERT_IF(valid, used_handles.contains(handle_)); + return valid; + } + + typename HandleOps::borrowed borrow() const { + MOZ_ASSERT(valid()); + LOG_HANDLE_OP("borrowing handle %d\n", handle_); + return {handle_}; + } + + typename HandleOps::owned take() { + MOZ_ASSERT(valid()); + MOZ_ASSERT(owned_); + LOG_HANDLE_OP("taking handle %d\n", handle_); + typename HandleOps::owned handle = {handle_}; +#ifdef DEBUG + used_handles.erase(handle_); +#endif + handle_ = POISONED_HANDLE; + return handle; + } +}; + +template struct Borrow { + static constexpr typename HandleOps::borrowed invalid{std::numeric_limits::max()}; + typename HandleOps::borrowed handle_{invalid}; + + explicit Borrow(host_api::HandleState *handle) { + handle_ = WASIHandle::cast(handle)->borrow(); + } + + explicit Borrow(typename HandleOps::borrowed handle) { handle_ = handle; } + + explicit Borrow(typename HandleOps::owned handle) { handle_ = {handle.__handle}; } + + operator typename HandleOps::borrowed() const { return handle_; } +}; + +template <> struct HandleOps { + using owned = wasi_io_poll_own_pollable_t; + using borrowed = wasi_io_poll_borrow_pollable_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_headers_t; + using borrowed = wasi_http_types_borrow_fields_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_incoming_request_t; + using borrowed = wasi_http_types_borrow_incoming_request_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_outgoing_request_t; + using borrowed = wasi_http_types_borrow_outgoing_request_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_future_incoming_response_t; + using borrowed = wasi_http_types_borrow_future_incoming_response_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_incoming_response_t; + using borrowed = wasi_http_types_borrow_incoming_response_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_outgoing_response_t; + using borrowed = wasi_http_types_borrow_outgoing_response_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_incoming_body_t; + using borrowed = wasi_http_types_borrow_incoming_body_t; +}; + +template <> struct HandleOps { + using owned = wasi_http_types_own_outgoing_body_t; + using borrowed = wasi_http_types_borrow_outgoing_body_t; +}; + +struct OutputStream {}; +template <> struct HandleOps { + using owned = wasi_io_streams_own_output_stream_t; + using borrowed = wasi_io_streams_borrow_output_stream_t; +}; + +struct InputStream {}; +template <> struct HandleOps { + using owned = wasi_io_streams_own_input_stream_t; + using borrowed = wasi_io_streams_borrow_input_stream_t; +}; + +class IncomingBodyHandle final : public WASIHandle { + HandleOps::owned stream_handle_; + PollableHandle pollable_handle_; + + friend host_api::HttpIncomingBody; + friend host_api::HttpOutgoingBody; + +public: + explicit IncomingBodyHandle(HandleOps::owned handle) + : WASIHandle(handle), pollable_handle_(INVALID_POLLABLE_HANDLE) { + HandleOps::owned stream{}; + if (!wasi_http_types_method_incoming_body_stream(borrow(), &stream)) { + MOZ_ASSERT_UNREACHABLE("Getting a body's stream should never fail"); + } + stream_handle_ = stream; + } + + static IncomingBodyHandle *cast(HandleState *handle) { + return reinterpret_cast(handle); + } +}; + +class OutgoingBodyHandle final : public WASIHandle { + HandleOps::owned stream_handle_; + PollableHandle pollable_handle_; + + friend host_api::HttpOutgoingBody; + +public: + explicit OutgoingBodyHandle(HandleOps::owned handle) + : WASIHandle(handle), pollable_handle_(INVALID_POLLABLE_HANDLE) { + HandleOps::owned stream{}; + if (!wasi_http_types_method_outgoing_body_write(borrow(), &stream)) { + MOZ_ASSERT_UNREACHABLE("Getting a body's stream should never fail"); + } + stream_handle_ = stream; + } + + static OutgoingBodyHandle *cast(HandleState *handle) { + return reinterpret_cast(handle); + } +}; + +#endif diff --git a/cmake/host_api.cmake b/host-apis/wasi-0.2.0/host_api.cmake similarity index 91% rename from cmake/host_api.cmake rename to host-apis/wasi-0.2.0/host_api.cmake index f18193f..82b0e32 100644 --- a/cmake/host_api.cmake +++ b/host-apis/wasi-0.2.0/host_api.cmake @@ -8,6 +8,7 @@ add_library(host_api STATIC target_link_libraries(host_api PRIVATE spidermonkey) target_include_directories(host_api PRIVATE include) +target_include_directories(host_api PRIVATE ${HOST_API}) target_include_directories(host_api PUBLIC ${HOST_API}/include) if (CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/host-apis/wasi-0.2.0/host_api.cpp b/host-apis/wasi-0.2.0/host_api.cpp index 6a7d2c5..bd2772e 100644 --- a/host-apis/wasi-0.2.0/host_api.cpp +++ b/host-apis/wasi-0.2.0/host_api.cpp @@ -1,245 +1,6 @@ #include "host_api.h" #include "bindings/bindings.h" - -#include -#include -#ifdef DEBUG -#include -#endif - -using host_api::HostString; -using std::optional; -using std::string_view; -using std::tuple; -using std::unique_ptr; -using std::vector; - -// The host interface makes the assumption regularly that uint32_t is sufficient space to store a -// pointer. -static_assert(sizeof(uint32_t) == sizeof(void *)); - -typedef wasi_http_types_own_future_incoming_response_t future_incoming_response_t; -typedef wasi_http_types_borrow_future_incoming_response_t borrow_future_incoming_response_t; - -typedef wasi_http_types_own_incoming_body_t incoming_body_t; -typedef wasi_http_types_own_outgoing_body_t outgoing_body_t; - -using field_key = wasi_http_types_field_key_t; -using field_value = wasi_http_types_field_value_t; - -typedef wasi_io_poll_own_pollable_t own_pollable_t; -typedef wasi_io_poll_borrow_pollable_t borrow_pollable_t; -typedef wasi_io_poll_list_borrow_pollable_t list_borrow_pollable_t; - -#ifdef LOG_HANDLE_OPS -#define LOG_HANDLE_OP(...) \ - fprintf(stderr, "%s", __PRETTY_FUNCTION__); \ - fprintf(stderr, __VA_ARGS__) -#else -#define LOG_HANDLE_OP(...) -#endif - -/// The type of handles used by the host interface. -typedef int32_t Handle; -constexpr Handle POISONED_HANDLE = -1; - -class host_api::HandleState { -protected: - HandleState() = default; - -public: - virtual ~HandleState() = default; - virtual bool valid() const = 0; -}; - -template struct HandleOps {}; - -template class WASIHandle : public host_api::HandleState { -#ifdef DEBUG - static inline auto used_handles = std::set(); -#endif - -protected: - Handle handle_; -#ifdef DEBUG - bool owned_; -#endif - -public: - using Borrowed = typename HandleOps::borrowed; - - explicit WASIHandle(typename HandleOps::owned handle) : handle_{handle.__handle} { - LOG_HANDLE_OP("Creating owned handle %d\n", handle.__handle); -#ifdef DEBUG - owned_ = true; - MOZ_ASSERT(!used_handles.contains(handle.__handle)); - used_handles.insert(handle.__handle); -#endif - } - - explicit WASIHandle(typename HandleOps::borrowed handle) : handle_{handle.__handle} { - LOG_HANDLE_OP("Creating borrowed handle %d\n", handle.__handle); -#ifdef DEBUG - owned_ = false; - MOZ_ASSERT(!used_handles.contains(handle.__handle)); - used_handles.insert(handle.__handle); -#endif - } - - ~WASIHandle() override { -#ifdef DEBUG - if (handle_ != POISONED_HANDLE) { - LOG_HANDLE_OP("Deleting (owned? %d) handle %d\n", owned_, handle_); - MOZ_ASSERT(used_handles.contains(handle_)); - used_handles.erase(handle_); - } -#endif - } - - static WASIHandle *cast(HandleState *handle) { - return reinterpret_cast *>(handle); - } - - typename HandleOps::borrowed borrow(HandleState *handle) { return cast(handle)->borrow(); } - - bool valid() const override { - bool valid = handle_ != POISONED_HANDLE; - MOZ_ASSERT_IF(valid, used_handles.contains(handle_)); - return valid; - } - - typename HandleOps::borrowed borrow() const { - MOZ_ASSERT(valid()); - LOG_HANDLE_OP("borrowing handle %d\n", handle_); - return {handle_}; - } - - typename HandleOps::owned take() { - MOZ_ASSERT(valid()); - MOZ_ASSERT(owned_); - LOG_HANDLE_OP("taking handle %d\n", handle_); - typename HandleOps::owned handle = {handle_}; -#ifdef DEBUG - used_handles.erase(handle_); -#endif - handle_ = POISONED_HANDLE; - return handle; - } -}; - -template struct Borrow { - static constexpr typename HandleOps::borrowed invalid{std::numeric_limits::max()}; - typename HandleOps::borrowed handle_{invalid}; - - explicit Borrow(host_api::HandleState *handle) { - handle_ = WASIHandle::cast(handle)->borrow(); - } - - explicit Borrow(typename HandleOps::borrowed handle) { handle_ = handle; } - - explicit Borrow(typename HandleOps::owned handle) { handle_ = {handle.__handle}; } - - operator typename HandleOps::borrowed() const { return handle_; } -}; - -template <> struct HandleOps { - using owned = wasi_io_poll_own_pollable_t; - using borrowed = wasi_io_poll_borrow_pollable_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_headers_t; - using borrowed = wasi_http_types_borrow_fields_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_incoming_request_t; - using borrowed = wasi_http_types_borrow_incoming_request_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_outgoing_request_t; - using borrowed = wasi_http_types_borrow_outgoing_request_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_future_incoming_response_t; - using borrowed = wasi_http_types_borrow_future_incoming_response_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_incoming_response_t; - using borrowed = wasi_http_types_borrow_incoming_response_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_outgoing_response_t; - using borrowed = wasi_http_types_borrow_outgoing_response_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_incoming_body_t; - using borrowed = wasi_http_types_borrow_incoming_body_t; -}; - -template <> struct HandleOps { - using owned = wasi_http_types_own_outgoing_body_t; - using borrowed = wasi_http_types_borrow_outgoing_body_t; -}; - -struct OutputStream {}; -template <> struct HandleOps { - using owned = wasi_io_streams_own_output_stream_t; - using borrowed = wasi_io_streams_borrow_output_stream_t; -}; - -struct InputStream {}; -template <> struct HandleOps { - using owned = wasi_io_streams_own_input_stream_t; - using borrowed = wasi_io_streams_borrow_input_stream_t; -}; - -class IncomingBodyHandle final : public WASIHandle { - HandleOps::owned stream_handle_; - PollableHandle pollable_handle_; - - friend host_api::HttpIncomingBody; - -public: - explicit IncomingBodyHandle(HandleOps::owned handle) - : WASIHandle(handle), pollable_handle_(INVALID_POLLABLE_HANDLE) { - HandleOps::owned stream{}; - if (!wasi_http_types_method_incoming_body_stream(borrow(), &stream)) { - MOZ_ASSERT_UNREACHABLE("Getting a body's stream should never fail"); - } - stream_handle_ = stream; - } - - static IncomingBodyHandle *cast(HandleState *handle) { - return reinterpret_cast(handle); - } -}; - -class OutgoingBodyHandle final : public WASIHandle { - HandleOps::owned stream_handle_; - PollableHandle pollable_handle_; - - friend host_api::HttpOutgoingBody; - -public: - explicit OutgoingBodyHandle(HandleOps::owned handle) - : WASIHandle(handle), pollable_handle_(INVALID_POLLABLE_HANDLE) { - HandleOps::owned stream{}; - if (!wasi_http_types_method_outgoing_body_write(borrow(), &stream)) { - MOZ_ASSERT_UNREACHABLE("Getting a body's stream should never fail"); - } - stream_handle_ = stream; - } - - static OutgoingBodyHandle *cast(HandleState *handle) { - return reinterpret_cast(handle); - } -}; +#include "handles.h" size_t api::AsyncTask::select(std::vector &tasks) { auto count = tasks.size();