mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-08-23 23:33:45 +02:00
Refactor the non-autogenerated parts of sandbox-bindgen into separate files
This commit is contained in:
parent
f1ad41814a
commit
1c4d65e02e
7 changed files with 426 additions and 292 deletions
137
binding-sandbox/binding-base.cpp
Normal file
137
binding-sandbox/binding-base.cpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
** binding-base.cpp
|
||||||
|
**
|
||||||
|
** This file is part of mkxp.
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 - 2021 Amaryllis Kulla <ancurio@mapleshrine.eu>
|
||||||
|
**
|
||||||
|
** mkxp is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 2 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** mkxp is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "binding-base.h"
|
||||||
|
|
||||||
|
#if WABT_BIG_ENDIAN
|
||||||
|
# define SERIALIZE_32(value) __builtin_bswap32(value)
|
||||||
|
# define SERIALIZE_64(value) __builtin_bswap64(value)
|
||||||
|
#else
|
||||||
|
# define SERIALIZE_32(value) (value)
|
||||||
|
# define SERIALIZE_64(value) (value)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MKXPZ_RETRO_MEMORY64
|
||||||
|
# define SERIALIZE_VALUE(value) SERIALIZE_64(value)
|
||||||
|
#else
|
||||||
|
# define SERIALIZE_VALUE(value) SERIALIZE_32(value)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace mkxp_sandbox;
|
||||||
|
|
||||||
|
binding_base::stack_frame::stack_frame(struct binding_base &bind, void (*destructor)(void *ptr), boost::typeindex::type_index type, wasm_ptr_t ptr) : bind(bind), destructor(destructor), type(type), ptr(ptr) {}
|
||||||
|
|
||||||
|
binding_base::stack_frame::~stack_frame() {
|
||||||
|
destructor(*bind + ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
binding_base::binding_base(std::shared_ptr<struct w2c_ruby> m) : next_func_ptr(-1), _instance(m) {}
|
||||||
|
|
||||||
|
binding_base::~binding_base() {
|
||||||
|
// Destroy all stack frames in order from top to bottom to enforce a portable, compiler-independent ordering of stack frame destruction
|
||||||
|
// If we let the compiler use its default destructor, the stack frames may not be deallocated in a particular order, which can lead to hard-to-detect bugs if somehow a bug depends on the order in which the stack frames are deallocated
|
||||||
|
for (auto &it : fibers) {
|
||||||
|
while (!it.second.stack.empty()) {
|
||||||
|
it.second.stack.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct w2c_ruby &binding_base::instance() const noexcept {
|
||||||
|
return *_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *binding_base::get() const noexcept {
|
||||||
|
return instance().w2c_memory.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *binding_base::operator*() const noexcept {
|
||||||
|
return get();
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_ptr_t binding_base::sandbox_malloc(wasm_size_t size) {
|
||||||
|
wasm_ptr_t buf = w2c_ruby_mkxp_sandbox_malloc(&instance(), size);
|
||||||
|
|
||||||
|
// Verify that the entire allocated buffer is in valid memory
|
||||||
|
wasm_ptr_t buf_end;
|
||||||
|
if (buf == 0 || __builtin_add_overflow(buf, size, &buf_end) || buf_end >= instance().w2c_memory.size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void binding_base::sandbox_free(wasm_ptr_t ptr) {
|
||||||
|
w2c_ruby_mkxp_sandbox_free(&instance(), ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_ptr_t binding_base::sandbox_create_func_ptr() {
|
||||||
|
if (next_func_ptr == (wasm_ptr_t)-1) {
|
||||||
|
next_func_ptr = instance().w2c_T0.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_func_ptr < instance().w2c_T0.max_size) {
|
||||||
|
return next_func_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that an integer overflow won't occur if we double the max size of the funcref table
|
||||||
|
wasm_size_t new_max_size;
|
||||||
|
if (__builtin_add_overflow(instance().w2c_T0.max_size, instance().w2c_T0.max_size, &new_max_size)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double the max size of the funcref table
|
||||||
|
wasm_size_t old_max_size = instance().w2c_T0.max_size;
|
||||||
|
instance().w2c_T0.max_size = new_max_size;
|
||||||
|
|
||||||
|
// Double the size of the funcref table buffer
|
||||||
|
if (wasm_rt_grow_funcref_table(&instance().w2c_T0, old_max_size, wasm_rt_funcref_t {
|
||||||
|
.func_type = wasm2c_ruby_get_func_type(0, 0),
|
||||||
|
.func = NULL,
|
||||||
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
.module_instance = &instance(),
|
||||||
|
}) != old_max_size) {
|
||||||
|
instance().w2c_T0.max_size = old_max_size;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_func_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_ptr_t binding_base::rtypeddata_data(VALUE obj) const noexcept {
|
||||||
|
return SERIALIZE_VALUE(obj) + *(wasm_size_t *)(instance().w2c_memory.data + instance().w2c_mkxp_sandbox_rtypeddata_data_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void binding_base::rtypeddata_dmark(wasm_ptr_t data, wasm_ptr_t ptr) {
|
||||||
|
w2c_ruby_mkxp_sandbox_rtypeddata_dmark(&instance(), data, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void binding_base::rtypeddata_dfree(wasm_ptr_t data, wasm_ptr_t ptr) {
|
||||||
|
w2c_ruby_mkxp_sandbox_rtypeddata_dfree(&instance(), data, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_size_t binding_base::rtypeddata_dsize(wasm_ptr_t data, wasm_ptr_t ptr) {
|
||||||
|
return w2c_ruby_mkxp_sandbox_rtypeddata_dsize(&instance(), data, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void binding_base::rtypeddata_dcompact(wasm_ptr_t data, wasm_ptr_t ptr) {
|
||||||
|
w2c_ruby_mkxp_sandbox_rtypeddata_dcompact(&instance(), data, ptr);
|
||||||
|
}
|
198
binding-sandbox/binding-base.h
Normal file
198
binding-sandbox/binding-base.h
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
** binding-base.h
|
||||||
|
**
|
||||||
|
** This file is part of mkxp.
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 - 2021 Amaryllis Kulla <ancurio@mapleshrine.eu>
|
||||||
|
**
|
||||||
|
** mkxp is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 2 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** mkxp is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MKXPZ_SANDBOX_BINDING_BASE_H
|
||||||
|
#define MKXPZ_SANDBOX_BINDING_BASE_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/container_hash/hash.hpp>
|
||||||
|
#include <boost/type_index.hpp>
|
||||||
|
#include <boost/asio/coroutine.hpp>
|
||||||
|
#include <mkxp-retro-ruby.h>
|
||||||
|
#include "binding-sandbox/types.h"
|
||||||
|
|
||||||
|
#if WABT_BIG_ENDIAN
|
||||||
|
# define SERIALIZE_32(value) __builtin_bswap32(value)
|
||||||
|
# define SERIALIZE_64(value) __builtin_bswap64(value)
|
||||||
|
#else
|
||||||
|
# define SERIALIZE_32(value) (value)
|
||||||
|
# define SERIALIZE_64(value) (value)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MKXPZ_RETRO_MEMORY64
|
||||||
|
# define SERIALIZE_VALUE(value) SERIALIZE_64(value)
|
||||||
|
#else
|
||||||
|
# define SERIALIZE_VALUE(value) SERIALIZE_32(value)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mkxp_sandbox {
|
||||||
|
struct binding_base {
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::tuple<wasm_ptr_t, wasm_ptr_t, wasm_ptr_t> key_t;
|
||||||
|
|
||||||
|
struct stack_frame {
|
||||||
|
struct binding_base &bind;
|
||||||
|
void (*destructor)(void *ptr);
|
||||||
|
boost::typeindex::type_index type;
|
||||||
|
wasm_ptr_t ptr;
|
||||||
|
stack_frame(struct binding_base &bind, void (*destructor)(void *ptr), boost::typeindex::type_index type, wasm_ptr_t ptr);
|
||||||
|
~stack_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fiber {
|
||||||
|
key_t key;
|
||||||
|
std::vector<struct stack_frame> stack;
|
||||||
|
size_t stack_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
wasm_ptr_t next_func_ptr;
|
||||||
|
std::shared_ptr<struct w2c_ruby> _instance;
|
||||||
|
std::unordered_map<key_t, struct fiber, boost::hash<key_t>> fibers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
binding_base(std::shared_ptr<struct w2c_ruby> m);
|
||||||
|
~binding_base();
|
||||||
|
struct w2c_ruby &instance() const noexcept;
|
||||||
|
uint8_t *get() const noexcept;
|
||||||
|
uint8_t *operator*() const noexcept;
|
||||||
|
wasm_ptr_t sandbox_malloc(wasm_size_t);
|
||||||
|
void sandbox_free(wasm_ptr_t ptr);
|
||||||
|
wasm_ptr_t sandbox_create_func_ptr();
|
||||||
|
wasm_ptr_t rtypeddata_data(VALUE obj) const noexcept;
|
||||||
|
void rtypeddata_dmark(wasm_ptr_t data, wasm_ptr_t ptr);
|
||||||
|
void rtypeddata_dfree(wasm_ptr_t data, wasm_ptr_t ptr);
|
||||||
|
wasm_size_t rtypeddata_dsize(wasm_ptr_t data, wasm_ptr_t ptr);
|
||||||
|
void rtypeddata_dcompact(wasm_ptr_t data, wasm_ptr_t ptr);
|
||||||
|
|
||||||
|
template <typename T> struct stack_frame_guard {
|
||||||
|
friend struct binding_base;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct binding_base &bind;
|
||||||
|
struct fiber &fiber;
|
||||||
|
wasm_ptr_t ptr;
|
||||||
|
|
||||||
|
static void stack_frame_destructor(void *ptr) {
|
||||||
|
((T *)ptr)->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fiber &init_fiber(struct binding_base &bind) {
|
||||||
|
key_t key = {
|
||||||
|
*(wasm_ptr_t *)(*bind + bind.instance().w2c_mkxp_sandbox_fiber_entry_point),
|
||||||
|
*(wasm_ptr_t *)(*bind + bind.instance().w2c_mkxp_sandbox_fiber_arg0),
|
||||||
|
*(wasm_ptr_t *)(*bind + bind.instance().w2c_mkxp_sandbox_fiber_arg1),
|
||||||
|
};
|
||||||
|
if (bind.fibers.count(key) == 0) {
|
||||||
|
bind.fibers[key] = (struct fiber){.key = key};
|
||||||
|
}
|
||||||
|
return bind.fibers[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
static wasm_ptr_t init_inner(struct binding_base &bind, struct fiber &fiber) {
|
||||||
|
wasm_ptr_t sp = w2c_ruby_rb_wasm_get_stack_pointer(&bind.instance());
|
||||||
|
|
||||||
|
if (fiber.stack_ptr == fiber.stack.size()) {
|
||||||
|
fiber.stack.emplace_back(
|
||||||
|
bind,
|
||||||
|
stack_frame_destructor,
|
||||||
|
boost::typeindex::type_id<T>(),
|
||||||
|
(sp -= sizeof(T))
|
||||||
|
);
|
||||||
|
assert(sp % sizeof(VALUE) == 0);
|
||||||
|
new(*bind + sp) T(bind);
|
||||||
|
} else if (fiber.stack_ptr > fiber.stack.size()) {
|
||||||
|
throw SandboxTrapException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fiber.stack[fiber.stack_ptr].type == boost::typeindex::type_id<T>()) {
|
||||||
|
w2c_ruby_rb_wasm_set_stack_pointer(&bind.instance(), sp);
|
||||||
|
return fiber.stack[fiber.stack_ptr++].ptr;
|
||||||
|
} else {
|
||||||
|
while (fiber.stack.size() > fiber.stack_ptr) {
|
||||||
|
fiber.stack.pop_back();
|
||||||
|
}
|
||||||
|
++fiber.stack_ptr;
|
||||||
|
fiber.stack.emplace_back(
|
||||||
|
bind,
|
||||||
|
stack_frame_destructor,
|
||||||
|
boost::typeindex::type_id<T>(),
|
||||||
|
(sp -= sizeof(T))
|
||||||
|
);
|
||||||
|
assert(sp % sizeof(VALUE) == 0);
|
||||||
|
new(*bind + sp) T(bind);
|
||||||
|
w2c_ruby_rb_wasm_set_stack_pointer(&bind.instance(), sp);
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_frame_guard(struct binding_base &b) : bind(b), fiber(init_fiber(b)), ptr(init_inner(b, fiber)) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
~stack_frame_guard() {
|
||||||
|
if (get()->is_complete()) {
|
||||||
|
while (fiber.stack.size() > fiber.stack_ptr) {
|
||||||
|
fiber.stack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for stack corruptions
|
||||||
|
assert(fiber.stack.size() == fiber.stack_ptr);
|
||||||
|
assert(fiber.stack.back().type == boost::typeindex::type_id<T>());
|
||||||
|
|
||||||
|
w2c_ruby_rb_wasm_set_stack_pointer(&bind.instance(), fiber.stack.back().ptr + sizeof(T));
|
||||||
|
fiber.stack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
--fiber.stack_ptr;
|
||||||
|
|
||||||
|
if (fiber.stack.empty()) {
|
||||||
|
bind.fibers.erase(fiber.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T *get() const noexcept {
|
||||||
|
return (T *)(*bind + ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T &operator()() const noexcept {
|
||||||
|
return *get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct stack_frame_guard<T> bind() {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SERIALIZE_32
|
||||||
|
#undef SERIALIZE_64
|
||||||
|
#undef SERIALIZE_VALUE
|
||||||
|
|
||||||
|
#endif // MKXPZ_SANDBOX_BINDING_BASE
|
|
@ -27,7 +27,7 @@
|
||||||
#include <mkxp-sandbox-bindgen.h>
|
#include <mkxp-sandbox-bindgen.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define SANDBOX_COROUTINE(name, definition) struct name : boost::asio::coroutine { BOOST_TYPE_INDEX_REGISTER_CLASS inline name(struct mkxp_sandbox::bindings &bind) {} definition };
|
#define SANDBOX_COROUTINE(name, definition) struct name : boost::asio::coroutine { BOOST_TYPE_INDEX_REGISTER_CLASS inline name(struct mkxp_sandbox::binding_base &bind) {} definition };
|
||||||
|
|
||||||
#define SANDBOX_AWAIT(coroutine, ...) \
|
#define SANDBOX_AWAIT(coroutine, ...) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
@ -24,8 +24,20 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
// WebAssembly pointers are currently 32-bit integers, but this may change if we decide to switch to 64-bit WebAssembly in the future! We define a pointer-sized integer here to make it easier to transition to different pointer sizes later.
|
#ifdef MKXPZ_RETRO_MEMORY64
|
||||||
|
#define usize u64
|
||||||
|
typedef int64_t wasm_ssize_t;
|
||||||
|
typedef uint64_t wasm_size_t;
|
||||||
|
#else
|
||||||
#define usize u32
|
#define usize u32
|
||||||
|
typedef int32_t wasm_ssize_t;
|
||||||
|
typedef uint32_t wasm_size_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ANYARGS ...
|
||||||
|
typedef wasm_size_t wasm_ptr_t;
|
||||||
|
typedef wasm_size_t VALUE;
|
||||||
|
typedef wasm_size_t ID;
|
||||||
|
|
||||||
#ifndef WASM_RT_CORE_TYPES_DEFINED
|
#ifndef WASM_RT_CORE_TYPES_DEFINED
|
||||||
#define WASM_RT_CORE_TYPES_DEFINED
|
#define WASM_RT_CORE_TYPES_DEFINED
|
||||||
|
|
|
@ -263,6 +263,7 @@ if get_option('retro') == true
|
||||||
'src/etc/table.cpp',
|
'src/etc/table.cpp',
|
||||||
'src/filesystem/filesystem.cpp',
|
'src/filesystem/filesystem.cpp',
|
||||||
'src/input/input-retro.cpp',
|
'src/input/input-retro.cpp',
|
||||||
|
'binding-sandbox/binding-base.cpp',
|
||||||
'binding-sandbox/binding-util.cpp',
|
'binding-sandbox/binding-util.cpp',
|
||||||
'binding-sandbox/sandbox.cpp',
|
'binding-sandbox/sandbox.cpp',
|
||||||
'binding-sandbox/wasi.cpp',
|
'binding-sandbox/wasi.cpp',
|
||||||
|
|
|
@ -19,31 +19,15 @@
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
# True if generating bindings for 64-bit WebAssembly, false if generating bindings for 32-bit WebAssembly
|
|
||||||
MEMORY64 = false
|
|
||||||
|
|
||||||
# The name passed as the `-n`/`--module-name` flag to `wasm2c`
|
# The name passed as the `-n`/`--module-name` flag to `wasm2c`
|
||||||
MODULE_NAME = 'ruby'
|
MODULE_NAME = 'ruby'
|
||||||
|
|
||||||
# Include directive for including the header file generated by `wasm2c`
|
|
||||||
MODULE_INCLUDE = '#include <mkxp-retro-ruby.h>'
|
|
||||||
|
|
||||||
# The name of the `malloc()` binding defined in ruby-bindings.h
|
# The name of the `malloc()` binding defined in ruby-bindings.h
|
||||||
MALLOC_FUNC = 'mkxp_sandbox_malloc'
|
MALLOC_FUNC = 'mkxp_sandbox_malloc'
|
||||||
|
|
||||||
# The name of the `free()` binding defined in ruby-bindings.h
|
# The name of the `free()` binding defined in ruby-bindings.h
|
||||||
FREE_FUNC = 'mkxp_sandbox_free'
|
FREE_FUNC = 'mkxp_sandbox_free'
|
||||||
|
|
||||||
RTYPEDDATA_DATA_OFFSET = 'mkxp_sandbox_rtypeddata_data_offset'
|
|
||||||
RTYPEDDATA_DMARK_FUNC = 'mkxp_sandbox_rtypeddata_dmark'
|
|
||||||
RTYPEDDATA_DFREE_FUNC = 'mkxp_sandbox_rtypeddata_dfree'
|
|
||||||
RTYPEDDATA_DSIZE_FUNC = 'mkxp_sandbox_rtypeddata_dsize'
|
|
||||||
RTYPEDDATA_DCOMPACT_FUNC = 'mkxp_sandbox_rtypeddata_dcompact'
|
|
||||||
|
|
||||||
FIBER_ENTRY_POINT = 'mkxp_sandbox_fiber_entry_point'
|
|
||||||
FIBER_ARG0 = 'mkxp_sandbox_fiber_arg0'
|
|
||||||
FIBER_ARG1 = 'mkxp_sandbox_fiber_arg1'
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
IGNORED_FUNCTIONS = Set[
|
IGNORED_FUNCTIONS = Set[
|
||||||
|
@ -65,21 +49,21 @@ ARG_HANDLERS = {
|
||||||
'const char *' => {
|
'const char *' => {
|
||||||
keep: true,
|
keep: true,
|
||||||
buf_size: 'std::strlen(ARG) + 1',
|
buf_size: 'std::strlen(ARG) + 1',
|
||||||
serialize: "std::strcpy((char *)(bind.instance->w2c_memory.data + BUF), ARG);\n",
|
serialize: "std::strcpy((char *)(*bind + BUF), ARG);\n",
|
||||||
},
|
},
|
||||||
'const VALUE *' => {
|
'const VALUE *' => {
|
||||||
keep: true,
|
keep: true,
|
||||||
condition: lambda { |func_name, args, arg_index| arg_index > 0 && args[arg_index - 1] == 'int' }, # Only handle arguments of type `const VALUE *` if the previous argument is of type `int`
|
condition: lambda { |func_name, args, arg_index| arg_index > 0 && args[arg_index - 1] == 'int' }, # Only handle arguments of type `const VALUE *` if the previous argument is of type `int`
|
||||||
buf_size: 'PREV_ARG * sizeof(VALUE)',
|
buf_size: 'PREV_ARG * sizeof(VALUE)',
|
||||||
serialize: <<~HEREDOC
|
serialize: <<~HEREDOC
|
||||||
std::memcpy(bind.instance->w2c_memory.data + BUF, ARG, PREV_ARG * sizeof(VALUE));
|
std::memcpy(*bind + BUF, ARG, PREV_ARG * sizeof(VALUE));
|
||||||
HEREDOC
|
HEREDOC
|
||||||
},
|
},
|
||||||
'volatile VALUE *' => {
|
'volatile VALUE *' => {
|
||||||
keep: true,
|
keep: true,
|
||||||
buf_size: 'sizeof(VALUE)',
|
buf_size: 'sizeof(VALUE)',
|
||||||
serialize: <<~HEREDOC
|
serialize: <<~HEREDOC
|
||||||
*(VALUE *)(bind.instance->w2c_memory.data + BUF) = *ARG;
|
*(VALUE *)(*bind + BUF) = *ARG;
|
||||||
HEREDOC
|
HEREDOC
|
||||||
},
|
},
|
||||||
'void *' => {
|
'void *' => {
|
||||||
|
@ -148,10 +132,10 @@ VAR_TYPE_TABLE = {
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNC_TYPE_TABLE = {
|
FUNC_TYPE_TABLE = {
|
||||||
ssize: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
ssize: 'WASM_RT_ISIZE',
|
||||||
size: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
size: 'WASM_RT_ISIZE',
|
||||||
value: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
value: 'WASM_RT_ISIZE',
|
||||||
ptr: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
ptr: 'WASM_RT_ISIZE',
|
||||||
s32: 'WASM_RT_I32',
|
s32: 'WASM_RT_I32',
|
||||||
u32: 'WASM_RT_I32',
|
u32: 'WASM_RT_I32',
|
||||||
s64: 'WASM_RT_I64',
|
s64: 'WASM_RT_I64',
|
||||||
|
@ -210,210 +194,39 @@ HEADER_START = <<~HEREDOC
|
||||||
#ifndef MKXP_SANDBOX_BINDGEN_H
|
#ifndef MKXP_SANDBOX_BINDGEN_H
|
||||||
#define MKXP_SANDBOX_BINDGEN_H
|
#define MKXP_SANDBOX_BINDGEN_H
|
||||||
|
|
||||||
#include <cassert>
|
#include "binding-sandbox/binding-base.h"
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <boost/container_hash/hash.hpp>
|
|
||||||
#include <boost/type_index.hpp>
|
|
||||||
#include <boost/asio/coroutine.hpp>
|
|
||||||
#{MODULE_INCLUDE}
|
|
||||||
#include "binding-sandbox/types.h"
|
|
||||||
|
|
||||||
// Autogenerated by sandbox-bindgen.rb. Don't manually modify this file - modify sandbox-bindgen.rb instead!
|
// Autogenerated by sandbox-bindgen.rb. Don't manually modify this file - modify sandbox-bindgen.rb instead!
|
||||||
|
|
||||||
#if WABT_BIG_ENDIAN
|
#if WABT_BIG_ENDIAN
|
||||||
#define SERIALIZE_32(value) __builtin_bswap32(value)
|
# define SERIALIZE_32(value) __builtin_bswap32(value)
|
||||||
#define SERIALIZE_64(value) __builtin_bswap64(value)
|
# define SERIALIZE_64(value) __builtin_bswap64(value)
|
||||||
#else
|
#else
|
||||||
#define SERIALIZE_32(value) (value)
|
# define SERIALIZE_32(value) (value)
|
||||||
#define SERIALIZE_64(value) (value)
|
# define SERIALIZE_64(value) (value)
|
||||||
#endif
|
#endif
|
||||||
#define SERIALIZE_VALUE(value) SERIALIZE_#{MEMORY64 ? '64' : '32'}(value)
|
|
||||||
|
|
||||||
#define ANYARGS ...
|
#ifdef MKXPZ_RETRO_MEMORY64
|
||||||
typedef int#{MEMORY64 ? '64' : '32'}_t wasm_ssize_t;
|
# define SERIALIZE_VALUE(value) SERIALIZE_64(value)
|
||||||
typedef uint#{MEMORY64 ? '64' : '32'}_t wasm_size_t;
|
#else
|
||||||
typedef wasm_size_t wasm_ptr_t;
|
# define SERIALIZE_VALUE(value) SERIALIZE_32(value)
|
||||||
typedef wasm_size_t VALUE;
|
#endif
|
||||||
typedef wasm_size_t ID;
|
|
||||||
|
|
||||||
namespace mkxp_sandbox {
|
namespace mkxp_sandbox {
|
||||||
struct bindings {
|
struct bindings : binding_base {
|
||||||
private:
|
bindings(std::shared_ptr<struct w2c_#{MODULE_NAME}> m);
|
||||||
|
|
||||||
typedef std::tuple<wasm_ptr_t, wasm_ptr_t, wasm_ptr_t> key_t;
|
|
||||||
|
|
||||||
struct stack_frame {
|
|
||||||
struct bindings &bind;
|
|
||||||
void (*destructor)(void *ptr);
|
|
||||||
boost::typeindex::type_index type;
|
|
||||||
wasm_ptr_t ptr;
|
|
||||||
inline stack_frame(struct bindings &bind, void (*destructor)(void *ptr), boost::typeindex::type_index type, wasm_ptr_t ptr) : bind(bind), destructor(destructor), type(type), ptr(ptr) {}
|
|
||||||
inline ~stack_frame() {
|
|
||||||
destructor(bind.instance->w2c_memory.data + ptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fiber {
|
|
||||||
key_t key;
|
|
||||||
std::vector<struct stack_frame> stack;
|
|
||||||
size_t stack_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
wasm_ptr_t next_func_ptr;
|
|
||||||
std::shared_ptr<struct w2c_#{MODULE_NAME}> instance;
|
|
||||||
std::unordered_map<key_t, struct fiber, boost::hash<key_t>> fibers;
|
|
||||||
wasm_ptr_t sandbox_create_func_ptr();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
inline bindings(std::shared_ptr<struct w2c_#{MODULE_NAME}> m) : next_func_ptr(-1), instance(m) {}
|
|
||||||
|
|
||||||
inline ~bindings() {
|
|
||||||
// Destroy all stack frames in order from top to bottom to enforce a portable, compiler-independent ordering of stack frame destruction
|
|
||||||
// If we let the compiler use its default destructor, the stack frames may not be deallocated in a particular order, which can lead to hard-to-detect bugs if somehow a bug depends on the order in which the stack frames are deallocated
|
|
||||||
for (auto &it : fibers) {
|
|
||||||
while (!it.second.stack.empty()) {
|
|
||||||
it.second.stack.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wasm_ptr_t sandbox_malloc(wasm_size_t);
|
|
||||||
|
|
||||||
inline void sandbox_free(wasm_ptr_t ptr) { w2c_#{MODULE_NAME}_#{FREE_FUNC}(instance.get(), ptr); }
|
|
||||||
|
|
||||||
inline uint8_t *get() const noexcept { return instance->w2c_memory.data; }
|
|
||||||
|
|
||||||
inline uint8_t *operator*() const noexcept { return get(); }
|
|
||||||
|
|
||||||
inline wasm_ptr_t rtypeddata_data(VALUE obj) const noexcept { return SERIALIZE_VALUE(obj) + *(wasm_size_t *)(instance->w2c_memory.data + instance->w2c_#{RTYPEDDATA_DATA_OFFSET}); }
|
|
||||||
|
|
||||||
inline void rtypeddata_dmark(wasm_ptr_t data, wasm_ptr_t ptr) { w2c_#{MODULE_NAME}_#{RTYPEDDATA_DMARK_FUNC}(instance.get(), data, ptr); }
|
|
||||||
|
|
||||||
inline void rtypeddata_dfree(wasm_ptr_t data, wasm_ptr_t ptr) { w2c_#{MODULE_NAME}_#{RTYPEDDATA_DFREE_FUNC}(instance.get(), data, ptr); }
|
|
||||||
|
|
||||||
inline wasm_size_t rtypeddata_dsize(wasm_ptr_t data, wasm_ptr_t ptr) { return w2c_#{MODULE_NAME}_#{RTYPEDDATA_DSIZE_FUNC}(instance.get(), data, ptr); }
|
|
||||||
|
|
||||||
inline void rtypeddata_dcompact(wasm_ptr_t data, wasm_ptr_t ptr) { w2c_#{MODULE_NAME}_#{RTYPEDDATA_DCOMPACT_FUNC}(instance.get(), data, ptr); }
|
|
||||||
|
|
||||||
struct rb_data_type {
|
struct rb_data_type {
|
||||||
friend struct bindings;
|
friend struct bindings;
|
||||||
inline rb_data_type() : ptr(0) {}
|
rb_data_type();
|
||||||
inline wasm_ptr_t get() const {
|
wasm_ptr_t get() const;
|
||||||
if (ptr == 0) throw SandboxTrapException();
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
wasm_ptr_t ptr;
|
wasm_ptr_t ptr;
|
||||||
inline rb_data_type(wasm_ptr_t ptr) : ptr(ptr) {}
|
rb_data_type(wasm_ptr_t ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rb_data_type rb_data_type(const char *wrap_struct_name, void (*dmark)(wasm_ptr_t), void (*dfree)(wasm_ptr_t), wasm_size_t (*dsize)(wasm_ptr_t), void (*dcompact)(wasm_ptr_t), wasm_ptr_t parent, wasm_ptr_t data, wasm_size_t flags);
|
struct rb_data_type rb_data_type(const char *wrap_struct_name, void (*dmark)(wasm_ptr_t), void (*dfree)(wasm_ptr_t), wasm_size_t (*dsize)(wasm_ptr_t), void (*dcompact)(wasm_ptr_t), wasm_ptr_t parent, wasm_ptr_t data, wasm_size_t flags);
|
||||||
|
|
||||||
template <typename T> struct stack_frame_guard {
|
|
||||||
friend struct bindings;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct bindings &bind;
|
|
||||||
struct fiber &fiber;
|
|
||||||
wasm_ptr_t ptr;
|
|
||||||
|
|
||||||
static void stack_frame_destructor(void *ptr) {
|
|
||||||
((T *)ptr)->~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct fiber &init_fiber(struct bindings &bind) {
|
|
||||||
key_t key = {
|
|
||||||
*(wasm_ptr_t *)(bind.instance->w2c_memory.data + bind.instance->w2c_#{FIBER_ENTRY_POINT}),
|
|
||||||
*(wasm_ptr_t *)(bind.instance->w2c_memory.data + bind.instance->w2c_#{FIBER_ARG0}),
|
|
||||||
*(wasm_ptr_t *)(bind.instance->w2c_memory.data + bind.instance->w2c_#{FIBER_ARG1}),
|
|
||||||
};
|
|
||||||
if (bind.fibers.count(key) == 0) {
|
|
||||||
bind.fibers[key] = (struct fiber){.key = key};
|
|
||||||
}
|
|
||||||
return bind.fibers[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
static wasm_ptr_t init_inner(struct bindings &bind, struct fiber &fiber) {
|
|
||||||
wasm_ptr_t sp = w2c_#{MODULE_NAME}_rb_wasm_get_stack_pointer(bind.instance.get());
|
|
||||||
|
|
||||||
if (fiber.stack_ptr == fiber.stack.size()) {
|
|
||||||
fiber.stack.emplace_back(
|
|
||||||
bind,
|
|
||||||
stack_frame_destructor,
|
|
||||||
boost::typeindex::type_id<T>(),
|
|
||||||
(sp -= sizeof(T))
|
|
||||||
);
|
|
||||||
assert(sp % sizeof(VALUE) == 0);
|
|
||||||
new(bind.instance->w2c_memory.data + sp) T(bind);
|
|
||||||
} else if (fiber.stack_ptr > fiber.stack.size()) {
|
|
||||||
throw SandboxTrapException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fiber.stack[fiber.stack_ptr].type == boost::typeindex::type_id<T>()) {
|
|
||||||
w2c_#{MODULE_NAME}_rb_wasm_set_stack_pointer(bind.instance.get(), sp);
|
|
||||||
return fiber.stack[fiber.stack_ptr++].ptr;
|
|
||||||
} else {
|
|
||||||
while (fiber.stack.size() > fiber.stack_ptr) {
|
|
||||||
fiber.stack.pop_back();
|
|
||||||
}
|
|
||||||
++fiber.stack_ptr;
|
|
||||||
fiber.stack.emplace_back(
|
|
||||||
bind,
|
|
||||||
stack_frame_destructor,
|
|
||||||
boost::typeindex::type_id<T>(),
|
|
||||||
(sp -= sizeof(T))
|
|
||||||
);
|
|
||||||
assert(sp % sizeof(VALUE) == 0);
|
|
||||||
new(bind.instance->w2c_memory.data + sp) T(bind);
|
|
||||||
w2c_#{MODULE_NAME}_rb_wasm_set_stack_pointer(bind.instance.get(), sp);
|
|
||||||
return sp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stack_frame_guard(struct bindings &b) : bind(b), fiber(init_fiber(b)), ptr(init_inner(b, fiber)) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
~stack_frame_guard() {
|
|
||||||
if (get()->is_complete()) {
|
|
||||||
while (fiber.stack.size() > fiber.stack_ptr) {
|
|
||||||
fiber.stack.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for stack corruptions
|
|
||||||
assert(fiber.stack.size() == fiber.stack_ptr);
|
|
||||||
assert(fiber.stack.back().type == boost::typeindex::type_id<T>());
|
|
||||||
|
|
||||||
w2c_#{MODULE_NAME}_rb_wasm_set_stack_pointer(bind.instance.get(), fiber.stack.back().ptr + sizeof(T));
|
|
||||||
fiber.stack.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
--fiber.stack_ptr;
|
|
||||||
|
|
||||||
if (fiber.stack.empty()) {
|
|
||||||
bind.fibers.erase(fiber.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline T *get() const noexcept {
|
|
||||||
return (T *)(bind.instance->w2c_memory.data + ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline T &operator()() const noexcept {
|
|
||||||
return *get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T> struct stack_frame_guard<T> bind() {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
HEADER_END = <<~HEREDOC
|
HEADER_END = <<~HEREDOC
|
||||||
|
@ -456,63 +269,33 @@ PRELUDE = <<~HEREDOC
|
||||||
static_assert(alignof(VALUE) % sizeof(VALUE) == 0, "Alignment of `VALUE` must be divisible by size of `VALUE` for Ruby garbage collection to work. If you compiled Ruby for wasm64, try compiling it for wasm32 instead.");
|
static_assert(alignof(VALUE) % sizeof(VALUE) == 0, "Alignment of `VALUE` must be divisible by size of `VALUE` for Ruby garbage collection to work. If you compiled Ruby for wasm64, try compiling it for wasm32 instead.");
|
||||||
|
|
||||||
#if WABT_BIG_ENDIAN
|
#if WABT_BIG_ENDIAN
|
||||||
#define SERIALIZE_32(value) __builtin_bswap32(value)
|
# define SERIALIZE_32(value) __builtin_bswap32(value)
|
||||||
#define SERIALIZE_64(value) __builtin_bswap64(value)
|
# define SERIALIZE_64(value) __builtin_bswap64(value)
|
||||||
#else
|
#else
|
||||||
#define SERIALIZE_32(value) (value)
|
# define SERIALIZE_32(value) (value)
|
||||||
#define SERIALIZE_64(value) (value)
|
# define SERIALIZE_64(value) (value)
|
||||||
#endif
|
#endif
|
||||||
#define SERIALIZE_VALUE(value) SERIALIZE_#{MEMORY64 ? '64' : '32'}(value)
|
|
||||||
|
|
||||||
|
#ifdef MKXPZ_RETRO_MEMORY64
|
||||||
|
# define SERIALIZE_VALUE(value) SERIALIZE_64(value)
|
||||||
|
# define WASM_RT_ISIZE WASM_RT_I64
|
||||||
|
#else
|
||||||
|
# define SERIALIZE_VALUE(value) SERIALIZE_32(value)
|
||||||
|
# define WASM_RT_ISIZE WASM_RT_I32
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace mkxp_sandbox;
|
using namespace mkxp_sandbox;
|
||||||
|
|
||||||
|
bindings::rb_data_type::rb_data_type() : ptr(0) {}
|
||||||
|
|
||||||
wasm_ptr_t bindings::sandbox_malloc(wasm_size_t size) {
|
bindings::rb_data_type::rb_data_type(wasm_ptr_t ptr) : ptr(ptr) {}
|
||||||
wasm_ptr_t buf = w2c_#{MODULE_NAME}_#{MALLOC_FUNC}(instance.get(), size);
|
|
||||||
|
|
||||||
// Verify that the entire allocated buffer is in valid memory
|
wasm_ptr_t bindings::rb_data_type::get() const {
|
||||||
wasm_ptr_t buf_end;
|
if (ptr == 0) throw SandboxTrapException();
|
||||||
if (buf == 0 || __builtin_add_overflow(buf, size, &buf_end) || buf_end >= instance->w2c_memory.size) {
|
return ptr;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindings::bindings(std::shared_ptr<struct w2c_#{MODULE_NAME}> m) : binding_base(m) {}
|
||||||
wasm_ptr_t bindings::sandbox_create_func_ptr() {
|
|
||||||
if (next_func_ptr == (wasm_ptr_t)-1) {
|
|
||||||
next_func_ptr = instance->w2c_T0.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next_func_ptr < instance->w2c_T0.max_size) {
|
|
||||||
return next_func_ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that an integer overflow won't occur if we double the max size of the funcref table
|
|
||||||
wasm_size_t new_max_size;
|
|
||||||
if (__builtin_add_overflow(instance->w2c_T0.max_size, instance->w2c_T0.max_size, &new_max_size)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double the max size of the funcref table
|
|
||||||
wasm_size_t old_max_size = instance->w2c_T0.max_size;
|
|
||||||
instance->w2c_T0.max_size = new_max_size;
|
|
||||||
|
|
||||||
// Double the size of the funcref table buffer
|
|
||||||
if (wasm_rt_grow_funcref_table(&instance->w2c_T0, old_max_size, wasm_rt_funcref_t {
|
|
||||||
.func_type = wasm2c_ruby_get_func_type(0, 0),
|
|
||||||
.func = NULL,
|
|
||||||
.func_tailcallee = {.fn = NULL},
|
|
||||||
.module_instance = instance.get(),
|
|
||||||
}) != old_max_size) {
|
|
||||||
instance->w2c_T0.max_size = old_max_size;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next_func_ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -520,10 +303,6 @@ HEREDOC
|
||||||
|
|
||||||
POSTSCRIPT = <<~HEREDOC
|
POSTSCRIPT = <<~HEREDOC
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
struct bindings::rb_data_type bindings::rb_data_type(const char *wrap_struct_name, void (*dmark)(wasm_ptr_t), void (*dfree)(wasm_ptr_t), wasm_size_t (*dsize)(wasm_ptr_t), void (*dcompact)(wasm_ptr_t), wasm_ptr_t parent, wasm_ptr_t data, wasm_size_t flags) {
|
struct bindings::rb_data_type bindings::rb_data_type(const char *wrap_struct_name, void (*dmark)(wasm_ptr_t), void (*dfree)(wasm_ptr_t), wasm_size_t (*dsize)(wasm_ptr_t), void (*dcompact)(wasm_ptr_t), wasm_ptr_t parent, wasm_ptr_t data, wasm_size_t flags) {
|
||||||
wasm_ptr_t ptrs[6] = {0};
|
wasm_ptr_t ptrs[6] = {0};
|
||||||
bool oom = false;
|
bool oom = false;
|
||||||
|
@ -547,10 +326,10 @@ POSTSCRIPT = <<~HEREDOC
|
||||||
throw SandboxOutOfMemoryException();
|
throw SandboxOutOfMemoryException();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::strcpy((char *)(instance->w2c_memory.data + ptrs[1]), wrap_struct_name);
|
std::strcpy((char *)(**this + ptrs[1]), wrap_struct_name);
|
||||||
|
|
||||||
if (dmark != NULL) {
|
if (dmark != NULL) {
|
||||||
instance->w2c_T0.data[ptrs[2]] = wasm_rt_funcref_t {
|
instance().w2c_T0.data[ptrs[2]] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 0, #{FUNC_TYPE_TABLE[:ptr]}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 0, #{FUNC_TYPE_TABLE[:ptr]}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -559,7 +338,7 @@ POSTSCRIPT = <<~HEREDOC
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dfree != NULL) {
|
if (dfree != NULL) {
|
||||||
instance->w2c_T0.data[ptrs[3]] = wasm_rt_funcref_t {
|
instance().w2c_T0.data[ptrs[3]] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 0, #{FUNC_TYPE_TABLE[:ptr]}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 0, #{FUNC_TYPE_TABLE[:ptr]}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -568,7 +347,7 @@ POSTSCRIPT = <<~HEREDOC
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dsize != NULL) {
|
if (dsize != NULL) {
|
||||||
instance->w2c_T0.data[ptrs[4]] = wasm_rt_funcref_t {
|
instance().w2c_T0.data[ptrs[4]] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 1, #{FUNC_TYPE_TABLE[:ptr]}, #{FUNC_TYPE_TABLE[:size]}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 1, #{FUNC_TYPE_TABLE[:ptr]}, #{FUNC_TYPE_TABLE[:size]}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:size, [:value]])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:size, [:value]])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -577,7 +356,7 @@ POSTSCRIPT = <<~HEREDOC
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dcompact != NULL) {
|
if (dcompact != NULL) {
|
||||||
instance->w2c_T0.data[ptrs[5]] = wasm_rt_funcref_t {
|
instance().w2c_T0.data[ptrs[5]] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 0, #{FUNC_TYPE_TABLE[:ptr]}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 0, #{FUNC_TYPE_TABLE[:ptr]}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -586,15 +365,19 @@ POSTSCRIPT = <<~HEREDOC
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 1; i < 6; ++i) {
|
for (size_t i = 1; i < 6; ++i) {
|
||||||
((wasm_ptr_t *)(instance->w2c_memory.data + ptrs[0]))[i - 1] = SERIALIZE_VALUE(ptrs[i]);
|
((wasm_ptr_t *)(**this + ptrs[0]))[i - 1] = SERIALIZE_VALUE(ptrs[i]);
|
||||||
}
|
}
|
||||||
((wasm_ptr_t *)(instance->w2c_memory.data + ptrs[0]))[5] = 0;
|
((wasm_ptr_t *)(**this + ptrs[0]))[5] = 0;
|
||||||
((wasm_ptr_t *)(instance->w2c_memory.data + ptrs[0]))[6] = SERIALIZE_VALUE(parent);
|
((wasm_ptr_t *)(**this + ptrs[0]))[6] = SERIALIZE_VALUE(parent);
|
||||||
((wasm_ptr_t *)(instance->w2c_memory.data + ptrs[0]))[7] = SERIALIZE_VALUE(data);
|
((wasm_ptr_t *)(**this + ptrs[0]))[7] = SERIALIZE_VALUE(data);
|
||||||
((wasm_ptr_t *)(instance->w2c_memory.data + ptrs[0]))[8] = SERIALIZE_VALUE(flags);
|
((wasm_ptr_t *)(**this + ptrs[0]))[8] = SERIALIZE_VALUE(flags);
|
||||||
|
|
||||||
return ptrs[0];
|
return ptrs[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -686,7 +469,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
coroutine_initializer += <<~HEREDOC
|
coroutine_initializer += <<~HEREDOC
|
||||||
switch (a#{args.length - 1}) {
|
switch (a#{args.length - 1}) {
|
||||||
case -1:
|
case -1:
|
||||||
bind.instance->w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(3, 1, #{FUNC_TYPE_TABLE[:s32]}, #{FUNC_TYPE_TABLE[:ptr]}, #{FUNC_TYPE_TABLE[:value]}, #{FUNC_TYPE_TABLE[:value]}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(3, 1, #{FUNC_TYPE_TABLE[:s32]}, #{FUNC_TYPE_TABLE[:ptr]}, #{FUNC_TYPE_TABLE[:value]}, #{FUNC_TYPE_TABLE[:value]}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:s32, :ptr, :value]])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:s32, :ptr, :value]])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -694,7 +477,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case -2:
|
case -2:
|
||||||
bind.instance->w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(2, 1, #{FUNC_TYPE_TABLE[:value]}, #{FUNC_TYPE_TABLE[:value]}, #{FUNC_TYPE_TABLE[:value]}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(2, 1, #{FUNC_TYPE_TABLE[:value]}, #{FUNC_TYPE_TABLE[:value]}, #{FUNC_TYPE_TABLE[:value]}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:value, :value]])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:value, :value]])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -705,7 +488,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
for j in 0..16
|
for j in 0..16
|
||||||
case_str = <<~HEREDOC
|
case_str = <<~HEREDOC
|
||||||
case #{j}:
|
case #{j}:
|
||||||
bind.instance->w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(#{j + 1}, 1, #{([FUNC_TYPE_TABLE[:value]] * (j + 2)).join(', ')}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(#{j + 1}, 1, #{([FUNC_TYPE_TABLE[:value]] * (j + 2)).join(', ')}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:value] * (j + 1)])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:value] * (j + 1)])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -722,7 +505,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
HEREDOC
|
HEREDOC
|
||||||
else
|
else
|
||||||
coroutine_initializer += <<~HEREDOC
|
coroutine_initializer += <<~HEREDOC
|
||||||
bind.instance->w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
|
||||||
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(#{handler[:func_ptr_args].length}, #{handler[:func_ptr_rets].length}#{handler[:func_ptr_args].empty? && handler[:func_ptr_rets].empty? ? '' : ', ' + (handler[:func_ptr_args] + handler[:func_ptr_rets]).map { |type| FUNC_TYPE_TABLE[type] }.join(', ')}),
|
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(#{handler[:func_ptr_args].length}, #{handler[:func_ptr_rets].length}#{handler[:func_ptr_args].empty? && handler[:func_ptr_rets].empty? ? '' : ', ' + (handler[:func_ptr_args] + handler[:func_ptr_rets]).map { |type| FUNC_TYPE_TABLE[type] }.join(', ')}),
|
||||||
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([handler[:func_ptr_rets].empty? ? :void : handler[:func_ptr_rets][0], handler[:func_ptr_args]])},
|
.func = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([handler[:func_ptr_rets].empty? ? :void : handler[:func_ptr_rets][0], handler[:func_ptr_args]])},
|
||||||
.func_tailcallee = {.fn = NULL},
|
.func_tailcallee = {.fn = NULL},
|
||||||
|
@ -758,7 +541,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
std::va_list a;
|
std::va_list a;
|
||||||
va_start(a, a#{args.length - 2});
|
va_start(a, a#{args.length - 2});
|
||||||
for (long i = 0; i < a#{args.length - 2}; ++i) {
|
for (long i = 0; i < a#{args.length - 2}; ++i) {
|
||||||
((VALUE *)(bind.instance->w2c_memory.data + f#{args.length - 1}))[i] = va_arg(a, VALUE);
|
((VALUE *)(*bind + f#{args.length - 1}))[i] = va_arg(a, VALUE);
|
||||||
}
|
}
|
||||||
va_end(a);
|
va_end(a);
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
@ -779,7 +562,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
throw SandboxOutOfMemoryException();
|
throw SandboxOutOfMemoryException();
|
||||||
}
|
}
|
||||||
for (wasm_size_t i = 0; i < n; ++i) {
|
for (wasm_size_t i = 0; i < n; ++i) {
|
||||||
((VALUE *)(bind.instance->w2c_memory.data + f#{args.length - 1}))[i] = va_arg(a, VALUE);
|
((VALUE *)(*bind + f#{args.length - 1}))[i] = va_arg(a, VALUE);
|
||||||
}
|
}
|
||||||
HEREDOC
|
HEREDOC
|
||||||
coroutine_initializer += "\n"
|
coroutine_initializer += "\n"
|
||||||
|
@ -814,8 +597,8 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
end
|
end
|
||||||
|
|
||||||
coroutine_inner = <<~HEREDOC
|
coroutine_inner = <<~HEREDOC
|
||||||
#{handler[:primitive] == :void ? '' : 'r = '}w2c_#{MODULE_NAME}_#{func_name}(#{(['bind.instance.get()'] + (0...args.length).map { |i| args[i] == '...' || transformed_args.include?(i) ? "f#{i}" : args[i] == 'VALUE' ? "SERIALIZE_VALUE(a#{i})" : args[i] == 'const rb_data_type_t *' ? "a#{i}.get()" : "a#{i}" }).join(', ')});
|
#{handler[:primitive] == :void ? '' : 'r = '}w2c_#{MODULE_NAME}_#{func_name}(#{(['&bind.instance()'] + (0...args.length).map { |i| args[i] == '...' || transformed_args.include?(i) ? "f#{i}" : args[i] == 'VALUE' ? "SERIALIZE_VALUE(a#{i})" : args[i] == 'const rb_data_type_t *' ? "a#{i}.get()" : "a#{i}" }).join(', ')});
|
||||||
if (w2c_#{MODULE_NAME}_asyncify_get_state(bind.instance.get()) != 1) break;
|
if (w2c_#{MODULE_NAME}_asyncify_get_state(&bind.instance()) != 1) break;
|
||||||
BOOST_ASIO_CORO_YIELD;
|
BOOST_ASIO_CORO_YIELD;
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
|
@ -826,6 +609,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
coroutine_definition = <<~HEREDOC
|
coroutine_definition = <<~HEREDOC
|
||||||
|
#{func_name}::#{func_name}(struct binding_base &b) : #{(['bind(b)'] + buffers.map { |buffer| "#{buffer}(0)" }).join(', ')} {}
|
||||||
#{coroutine_ret} #{func_name}::operator()(#{coroutine_args.join(', ')}) {#{coroutine_vars.empty? ? '' : (coroutine_vars.map { |var| "\n #{var} = 0;" }.join + "\n")}
|
#{coroutine_ret} #{func_name}::operator()(#{coroutine_args.join(', ')}) {#{coroutine_vars.empty? ? '' : (coroutine_vars.map { |var| "\n #{var} = 0;" }.join + "\n")}
|
||||||
BOOST_ASIO_CORO_REENTER (this) {
|
BOOST_ASIO_CORO_REENTER (this) {
|
||||||
#{coroutine_initializer.empty? ? '' : (coroutine_initializer.split("\n").map { |line| " #{line}".rstrip }.join("\n") + "\n\n")} for (;;) {
|
#{coroutine_initializer.empty? ? '' : (coroutine_initializer.split("\n").map { |line| " #{line}".rstrip }.join("\n") + "\n\n")} for (;;) {
|
||||||
|
@ -837,13 +621,12 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
|
|
||||||
coroutine_declaration = <<~HEREDOC
|
coroutine_declaration = <<~HEREDOC
|
||||||
struct #{func_name} : boost::asio::coroutine {
|
struct #{func_name} : boost::asio::coroutine {
|
||||||
friend struct bindings;
|
|
||||||
friend struct bindings::stack_frame_guard<struct #{func_name}>;
|
friend struct bindings::stack_frame_guard<struct #{func_name}>;
|
||||||
BOOST_TYPE_INDEX_REGISTER_CLASS
|
BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||||
#{coroutine_ret} operator()(#{declaration_args.join(', ')});
|
#{coroutine_ret} operator()(#{declaration_args.join(', ')});
|
||||||
#{coroutine_destructor.empty? ? '' : "~#{func_name}();\n "}private:
|
#{coroutine_destructor.empty? ? '' : "~#{func_name}();\n "}private:
|
||||||
struct bindings &bind;
|
struct binding_base &bind;
|
||||||
inline #{func_name}(struct bindings &b) : #{(['bind(b)'] + buffers.map { |buffer| "#{buffer}(0)" }).join(', ')} {}
|
#{func_name}(struct binding_base &b);
|
||||||
#{fields.empty? ? '' : fields.map { |field| " #{field};\n" }.join}};
|
#{fields.empty? ? '' : fields.map { |field| " #{field};\n" }.join}};
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
|
@ -855,10 +638,7 @@ end
|
||||||
File.open('mkxp-sandbox-bindgen.h', 'w') do |file|
|
File.open('mkxp-sandbox-bindgen.h', 'w') do |file|
|
||||||
file.write(HEADER_START)
|
file.write(HEADER_START)
|
||||||
for global_name in globals
|
for global_name in globals
|
||||||
file.write(" inline VALUE #{global_name}() const noexcept { return *(VALUE *)(instance->w2c_memory.data + instance->w2c_#{global_name}); }\n")
|
file.write(" inline VALUE #{global_name}() const noexcept { return *(VALUE *)(**this + instance().w2c_#{global_name}); }\n")
|
||||||
end
|
|
||||||
for func_name in func_names
|
|
||||||
file.write(" friend struct #{func_name};\n")
|
|
||||||
end
|
end
|
||||||
file.write(" };")
|
file.write(" };")
|
||||||
for declaration in declarations
|
for declaration in declarations
|
||||||
|
@ -866,12 +646,18 @@ File.open('mkxp-sandbox-bindgen.h', 'w') do |file|
|
||||||
end
|
end
|
||||||
file.write("\n\n")
|
file.write("\n\n")
|
||||||
file.write("#if WABT_BIG_ENDIAN\n")
|
file.write("#if WABT_BIG_ENDIAN\n")
|
||||||
|
file.write("# ifdef MKXPZ_RETRO_MEMORY64\n")
|
||||||
for const in consts
|
for const in consts
|
||||||
file.write("#define SANDBOX_#{const[0]} 0x#{[const[1]].pack(MEMORY64 ? 'Q<' : 'L<').unpack('H*')[0]}u\n")
|
file.write("# define SANDBOX_#{const[0]} 0x#{[const[1]].pack('Q<').unpack('H*')[0]}u\n")
|
||||||
end
|
end
|
||||||
|
file.write("# else\n")
|
||||||
|
for const in consts
|
||||||
|
file.write("# define SANDBOX_#{const[0]} 0x#{[const[1]].pack('L<').unpack('H*')[0]}u\n")
|
||||||
|
end
|
||||||
|
file.write("# endif\n")
|
||||||
file.write("#else\n")
|
file.write("#else\n")
|
||||||
for const in consts
|
for const in consts
|
||||||
file.write("#define SANDBOX_#{const[0]} 0x#{[const[1]].pack(MEMORY64 ? 'Q>' : 'L>').unpack('H*')[0]}u\n")
|
file.write("# define SANDBOX_#{const[0]} 0x#{[const[1]].pack('L>').unpack('H*')[0]}u\n")
|
||||||
end
|
end
|
||||||
file.write("#endif\n")
|
file.write("#endif\n")
|
||||||
file.write(HEADER_END)
|
file.write(HEADER_END)
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
#include <fluidlite.h>
|
#include <fluidlite.h>
|
||||||
#include <fluidsynth_priv.h>
|
#include <fluidsynth_priv.h>
|
||||||
#include "git-hash.h"
|
#include "git-hash.h"
|
||||||
#include "../binding-sandbox/sandbox.h"
|
#include "binding-sandbox/sandbox.h"
|
||||||
#include "../binding-sandbox/binding-sandbox.h"
|
#include "binding-sandbox/binding-sandbox.h"
|
||||||
#include "../binding-sandbox/core.h"
|
#include "binding-sandbox/core.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
|
|
||||||
using namespace mkxp_retro;
|
using namespace mkxp_retro;
|
||||||
|
|
Loading…
Add table
Reference in a new issue