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 "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, ...) \
|
||||
do { \
|
||||
|
|
|
@ -24,8 +24,20 @@
|
|||
|
||||
#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
|
||||
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
|
||||
#define WASM_RT_CORE_TYPES_DEFINED
|
||||
|
|
|
@ -263,6 +263,7 @@ if get_option('retro') == true
|
|||
'src/etc/table.cpp',
|
||||
'src/filesystem/filesystem.cpp',
|
||||
'src/input/input-retro.cpp',
|
||||
'binding-sandbox/binding-base.cpp',
|
||||
'binding-sandbox/binding-util.cpp',
|
||||
'binding-sandbox/sandbox.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`
|
||||
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
|
||||
MALLOC_FUNC = 'mkxp_sandbox_malloc'
|
||||
|
||||
# The name of the `free()` binding defined in ruby-bindings.h
|
||||
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[
|
||||
|
@ -65,21 +49,21 @@ ARG_HANDLERS = {
|
|||
'const char *' => {
|
||||
keep: true,
|
||||
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 *' => {
|
||||
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`
|
||||
buf_size: 'PREV_ARG * sizeof(VALUE)',
|
||||
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
|
||||
},
|
||||
'volatile VALUE *' => {
|
||||
keep: true,
|
||||
buf_size: 'sizeof(VALUE)',
|
||||
serialize: <<~HEREDOC
|
||||
*(VALUE *)(bind.instance->w2c_memory.data + BUF) = *ARG;
|
||||
*(VALUE *)(*bind + BUF) = *ARG;
|
||||
HEREDOC
|
||||
},
|
||||
'void *' => {
|
||||
|
@ -148,10 +132,10 @@ VAR_TYPE_TABLE = {
|
|||
}
|
||||
|
||||
FUNC_TYPE_TABLE = {
|
||||
ssize: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
||||
size: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
||||
value: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
||||
ptr: MEMORY64 ? 'WASM_RT_I64' : 'WASM_RT_I32',
|
||||
ssize: 'WASM_RT_ISIZE',
|
||||
size: 'WASM_RT_ISIZE',
|
||||
value: 'WASM_RT_ISIZE',
|
||||
ptr: 'WASM_RT_ISIZE',
|
||||
s32: 'WASM_RT_I32',
|
||||
u32: 'WASM_RT_I32',
|
||||
s64: 'WASM_RT_I64',
|
||||
|
@ -210,17 +194,7 @@ HEADER_START = <<~HEREDOC
|
|||
#ifndef MKXP_SANDBOX_BINDGEN_H
|
||||
#define MKXP_SANDBOX_BINDGEN_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>
|
||||
#{MODULE_INCLUDE}
|
||||
#include "binding-sandbox/types.h"
|
||||
#include "binding-sandbox/binding-base.h"
|
||||
|
||||
// Autogenerated by sandbox-bindgen.rb. Don't manually modify this file - modify sandbox-bindgen.rb instead!
|
||||
|
||||
|
@ -231,189 +205,28 @@ HEADER_START = <<~HEREDOC
|
|||
# define SERIALIZE_32(value) (value)
|
||||
# define SERIALIZE_64(value) (value)
|
||||
#endif
|
||||
#define SERIALIZE_VALUE(value) SERIALIZE_#{MEMORY64 ? '64' : '32'}(value)
|
||||
|
||||
#define ANYARGS ...
|
||||
typedef int#{MEMORY64 ? '64' : '32'}_t wasm_ssize_t;
|
||||
typedef uint#{MEMORY64 ? '64' : '32'}_t wasm_size_t;
|
||||
typedef wasm_size_t wasm_ptr_t;
|
||||
typedef wasm_size_t VALUE;
|
||||
typedef wasm_size_t ID;
|
||||
#ifdef MKXPZ_RETRO_MEMORY64
|
||||
# define SERIALIZE_VALUE(value) SERIALIZE_64(value)
|
||||
#else
|
||||
# define SERIALIZE_VALUE(value) SERIALIZE_32(value)
|
||||
#endif
|
||||
|
||||
namespace mkxp_sandbox {
|
||||
struct bindings {
|
||||
private:
|
||||
|
||||
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 bindings : binding_base {
|
||||
bindings(std::shared_ptr<struct w2c_#{MODULE_NAME}> m);
|
||||
|
||||
struct rb_data_type {
|
||||
friend struct bindings;
|
||||
inline rb_data_type() : ptr(0) {}
|
||||
inline wasm_ptr_t get() const {
|
||||
if (ptr == 0) throw SandboxTrapException();
|
||||
return ptr;
|
||||
}
|
||||
rb_data_type();
|
||||
wasm_ptr_t get() const;
|
||||
private:
|
||||
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);
|
||||
|
||||
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
|
||||
|
||||
HEADER_END = <<~HEREDOC
|
||||
|
@ -462,57 +275,27 @@ PRELUDE = <<~HEREDOC
|
|||
# define SERIALIZE_32(value) (value)
|
||||
# define SERIALIZE_64(value) (value)
|
||||
#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;
|
||||
|
||||
bindings::rb_data_type::rb_data_type() : ptr(0) {}
|
||||
|
||||
wasm_ptr_t bindings::sandbox_malloc(wasm_size_t size) {
|
||||
wasm_ptr_t buf = w2c_#{MODULE_NAME}_#{MALLOC_FUNC}(instance.get(), size);
|
||||
bindings::rb_data_type::rb_data_type(wasm_ptr_t ptr) : ptr(ptr) {}
|
||||
|
||||
// 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;
|
||||
wasm_ptr_t bindings::rb_data_type::get() const {
|
||||
if (ptr == 0) throw SandboxTrapException();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
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++;
|
||||
}
|
||||
bindings::bindings(std::shared_ptr<struct w2c_#{MODULE_NAME}> m) : binding_base(m) {}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -520,10 +303,6 @@ 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) {
|
||||
wasm_ptr_t ptrs[6] = {0};
|
||||
bool oom = false;
|
||||
|
@ -547,10 +326,10 @@ POSTSCRIPT = <<~HEREDOC
|
|||
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) {
|
||||
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 = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
||||
.func_tailcallee = {.fn = NULL},
|
||||
|
@ -559,7 +338,7 @@ POSTSCRIPT = <<~HEREDOC
|
|||
}
|
||||
|
||||
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 = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
||||
.func_tailcallee = {.fn = NULL},
|
||||
|
@ -568,7 +347,7 @@ POSTSCRIPT = <<~HEREDOC
|
|||
}
|
||||
|
||||
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 = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:size, [:value]])},
|
||||
.func_tailcallee = {.fn = NULL},
|
||||
|
@ -577,7 +356,7 @@ POSTSCRIPT = <<~HEREDOC
|
|||
}
|
||||
|
||||
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 = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:void, [:value]])},
|
||||
.func_tailcallee = {.fn = NULL},
|
||||
|
@ -586,15 +365,19 @@ POSTSCRIPT = <<~HEREDOC
|
|||
}
|
||||
|
||||
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 *)(instance->w2c_memory.data + ptrs[0]))[6] = SERIALIZE_VALUE(parent);
|
||||
((wasm_ptr_t *)(instance->w2c_memory.data + 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]))[5] = 0;
|
||||
((wasm_ptr_t *)(**this + ptrs[0]))[6] = SERIALIZE_VALUE(parent);
|
||||
((wasm_ptr_t *)(**this + ptrs[0]))[7] = SERIALIZE_VALUE(data);
|
||||
((wasm_ptr_t *)(**this + ptrs[0]))[8] = SERIALIZE_VALUE(flags);
|
||||
|
||||
return ptrs[0];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
HEREDOC
|
||||
|
||||
################################################################################
|
||||
|
@ -686,7 +469,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
coroutine_initializer += <<~HEREDOC
|
||||
switch (a#{args.length - 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 = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:s32, :ptr, :value]])},
|
||||
.func_tailcallee = {.fn = NULL},
|
||||
|
@ -694,7 +477,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
};
|
||||
break;
|
||||
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 = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:value, :value]])},
|
||||
.func_tailcallee = {.fn = NULL},
|
||||
|
@ -705,7 +488,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
for j in 0..16
|
||||
case_str = <<~HEREDOC
|
||||
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 = (wasm_rt_function_ptr_t)_sbindgen_call_#{call_type_hash([:value, [:value] * (j + 1)])},
|
||||
.func_tailcallee = {.fn = NULL},
|
||||
|
@ -722,7 +505,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
HEREDOC
|
||||
else
|
||||
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 = (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},
|
||||
|
@ -758,7 +541,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
std::va_list a;
|
||||
va_start(a, a#{args.length - 2});
|
||||
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);
|
||||
HEREDOC
|
||||
|
@ -779,7 +562,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
throw SandboxOutOfMemoryException();
|
||||
}
|
||||
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
|
||||
coroutine_initializer += "\n"
|
||||
|
@ -814,8 +597,8 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
end
|
||||
|
||||
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(', ')});
|
||||
if (w2c_#{MODULE_NAME}_asyncify_get_state(bind.instance.get()) != 1) break;
|
||||
#{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()) != 1) break;
|
||||
BOOST_ASIO_CORO_YIELD;
|
||||
HEREDOC
|
||||
|
||||
|
@ -826,6 +609,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
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")}
|
||||
BOOST_ASIO_CORO_REENTER (this) {
|
||||
#{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
|
||||
struct #{func_name} : boost::asio::coroutine {
|
||||
friend struct bindings;
|
||||
friend struct bindings::stack_frame_guard<struct #{func_name}>;
|
||||
BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
#{coroutine_ret} operator()(#{declaration_args.join(', ')});
|
||||
#{coroutine_destructor.empty? ? '' : "~#{func_name}();\n "}private:
|
||||
struct bindings &bind;
|
||||
inline #{func_name}(struct bindings &b) : #{(['bind(b)'] + buffers.map { |buffer| "#{buffer}(0)" }).join(', ')} {}
|
||||
struct binding_base &bind;
|
||||
#{func_name}(struct binding_base &b);
|
||||
#{fields.empty? ? '' : fields.map { |field| " #{field};\n" }.join}};
|
||||
HEREDOC
|
||||
|
||||
|
@ -855,10 +638,7 @@ end
|
|||
File.open('mkxp-sandbox-bindgen.h', 'w') do |file|
|
||||
file.write(HEADER_START)
|
||||
for global_name in globals
|
||||
file.write(" inline VALUE #{global_name}() const noexcept { return *(VALUE *)(instance->w2c_memory.data + instance->w2c_#{global_name}); }\n")
|
||||
end
|
||||
for func_name in func_names
|
||||
file.write(" friend struct #{func_name};\n")
|
||||
file.write(" inline VALUE #{global_name}() const noexcept { return *(VALUE *)(**this + instance().w2c_#{global_name}); }\n")
|
||||
end
|
||||
file.write(" };")
|
||||
for declaration in declarations
|
||||
|
@ -866,12 +646,18 @@ File.open('mkxp-sandbox-bindgen.h', 'w') do |file|
|
|||
end
|
||||
file.write("\n\n")
|
||||
file.write("#if WABT_BIG_ENDIAN\n")
|
||||
file.write("# ifdef MKXPZ_RETRO_MEMORY64\n")
|
||||
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
|
||||
file.write("# else\n")
|
||||
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
|
||||
file.write("# endif\n")
|
||||
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(HEADER_END)
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
#include <fluidlite.h>
|
||||
#include <fluidsynth_priv.h>
|
||||
#include "git-hash.h"
|
||||
#include "../binding-sandbox/sandbox.h"
|
||||
#include "../binding-sandbox/binding-sandbox.h"
|
||||
#include "../binding-sandbox/core.h"
|
||||
#include "binding-sandbox/sandbox.h"
|
||||
#include "binding-sandbox/binding-sandbox.h"
|
||||
#include "binding-sandbox/core.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
using namespace mkxp_retro;
|
||||
|
|
Loading…
Add table
Reference in a new issue