mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-09-05 21:53:03 +02:00
Implement stackful coroutine-based executor for libretro builds
This executor has the advantage of being able to work correctly when there are Ruby stack frames underneath C/C++ stack frames in the stack. Still need to implement handling Ruby fibers.
This commit is contained in:
parent
4a94a326b5
commit
2a204178fe
16 changed files with 177 additions and 74 deletions
2
.github/workflows/autobuild.yml
vendored
2
.github/workflows/autobuild.yml
vendored
|
@ -488,7 +488,7 @@ jobs:
|
||||||
PATH="$HOMEBREW_PREFIX/opt/gpatch/libexec/gnubin:$PATH" meson setup build --buildtype release -Db_lto=true -Dretro=true -Dretro_phase1_path=retro/build/retro-phase1
|
PATH="$HOMEBREW_PREFIX/opt/gpatch/libexec/gnubin:$PATH" meson setup build --buildtype release -Db_lto=true -Dretro=true -Dretro_phase1_path=retro/build/retro-phase1
|
||||||
cd build
|
cd build
|
||||||
ninja -v
|
ninja -v
|
||||||
strip libretro-mkxp-z.dylib
|
strip -x libretro-mkxp-z.dylib
|
||||||
mv libretro-mkxp-z.dylib ${{ runner.temp }}/retro-phase2
|
mv libretro-mkxp-z.dylib ${{ runner.temp }}/retro-phase2
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
|
|
16
meson.build
16
meson.build
|
@ -55,8 +55,8 @@ if get_option('retro') == true
|
||||||
'ENABLE_LIB_ONLY': true,
|
'ENABLE_LIB_ONLY': true,
|
||||||
})
|
})
|
||||||
|
|
||||||
lzma_options = cmake.subproject_options()
|
liblzma_options = cmake.subproject_options()
|
||||||
lzma_options.add_cmake_defines({
|
liblzma_options.add_cmake_defines({
|
||||||
'CMAKE_POSITION_INDEPENDENT_CODE': true,
|
'CMAKE_POSITION_INDEPENDENT_CODE': true,
|
||||||
'BUILD_SHARED_LIBS': false,
|
'BUILD_SHARED_LIBS': false,
|
||||||
'ENABLE_NLS': false,
|
'ENABLE_NLS': false,
|
||||||
|
@ -113,9 +113,19 @@ if get_option('retro') == true
|
||||||
'retro-' + meson.project_name(),
|
'retro-' + meson.project_name(),
|
||||||
dependencies: [
|
dependencies: [
|
||||||
cmake.subproject('boost_asio', options: boost_options).dependency('boost_asio'),
|
cmake.subproject('boost_asio', options: boost_options).dependency('boost_asio'),
|
||||||
|
cmake.subproject('boost_mp11', options: boost_options).dependency('boost_mp11'),
|
||||||
|
cmake.subproject('boost_describe', options: boost_options).dependency('boost_describe'),
|
||||||
|
cmake.subproject('boost_config', options: boost_options).dependency('boost_config'),
|
||||||
|
cmake.subproject('boost_assert', options: boost_options).dependency('boost_assert'),
|
||||||
|
cmake.subproject('boost_static_assert', options: boost_options).dependency('boost_static_assert'),
|
||||||
|
cmake.subproject('boost_throw_exception', options: boost_options).dependency('boost_throw_exception'),
|
||||||
|
cmake.subproject('boost_core', options: boost_options).dependency('boost_core'),
|
||||||
|
cmake.subproject('boost_container_hash', options: boost_options).dependency('boost_container_hash'),
|
||||||
|
cmake.subproject('boost_type_index', options: boost_options).dependency('boost_type_index'),
|
||||||
|
cmake.subproject('boost_any', options: boost_options).dependency('boost_any'),
|
||||||
cmake.subproject('zlib', options: zlib_options).dependency('zlibstatic'),
|
cmake.subproject('zlib', options: zlib_options).dependency('zlibstatic'),
|
||||||
cmake.subproject('bzip2', options: bzip2_options).dependency('bz2_static'),
|
cmake.subproject('bzip2', options: bzip2_options).dependency('bz2_static'),
|
||||||
cmake.subproject('liblzma', options: lzma_options).dependency('liblzma'),
|
cmake.subproject('liblzma', options: liblzma_options).dependency('liblzma'),
|
||||||
cmake.subproject('zstd', options: zstd_options).dependency('libzstd_static'),
|
cmake.subproject('zstd', options: zstd_options).dependency('libzstd_static'),
|
||||||
cmake.subproject('libzip', options: libzip_options).dependency('zip'),
|
cmake.subproject('libzip', options: libzip_options).dependency('zip'),
|
||||||
],
|
],
|
||||||
|
|
|
@ -155,7 +155,10 @@ HEADER_START = <<~HEREDOC
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/any.hpp>
|
||||||
#include <boost/asio/coroutine.hpp>
|
#include <boost/asio/coroutine.hpp>
|
||||||
|
#include <boost/asio/yield.hpp>
|
||||||
#{MODULE_INCLUDE}
|
#{MODULE_INCLUDE}
|
||||||
#include "src/sandbox/types.h"
|
#include "src/sandbox/types.h"
|
||||||
|
|
||||||
|
@ -168,20 +171,61 @@ HEADER_START = <<~HEREDOC
|
||||||
typedef wasm_size_t VALUE;
|
typedef wasm_size_t VALUE;
|
||||||
typedef wasm_size_t ID;
|
typedef wasm_size_t ID;
|
||||||
|
|
||||||
struct SandboxBind {
|
namespace mkxp_sandbox {
|
||||||
private:
|
struct bindings {
|
||||||
wasm_ptr_t next_func_ptr;
|
private:
|
||||||
std::shared_ptr<struct w2c_#{MODULE_NAME}> instance;
|
wasm_ptr_t next_func_ptr;
|
||||||
wasm_ptr_t sbindgen_malloc(wasm_ptr_t);
|
std::shared_ptr<struct w2c_#{MODULE_NAME}> instance;
|
||||||
wasm_ptr_t sbindgen_create_func_ptr();
|
size_t depth;
|
||||||
|
std::vector<boost::any> stack;
|
||||||
|
wasm_ptr_t sbindgen_malloc(wasm_ptr_t);
|
||||||
|
wasm_ptr_t sbindgen_create_func_ptr();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SandboxBind(std::shared_ptr<struct w2c_#{MODULE_NAME}>);
|
bindings(std::shared_ptr<struct w2c_#{MODULE_NAME}>);
|
||||||
|
|
||||||
|
template <typename T> struct stack_frame {
|
||||||
|
friend struct bindings;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct bindings &bindings;
|
||||||
|
T &inner;
|
||||||
|
static inline T &init(struct bindings &bindings) {
|
||||||
|
if (bindings.depth == bindings.stack.size()) {
|
||||||
|
bindings.stack.push_back(T(bindings));
|
||||||
|
} else if (bindings.depth > bindings.stack.size()) {
|
||||||
|
throw SandboxTrapException();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return boost::any_cast<T &>(bindings.stack[bindings.depth++]);
|
||||||
|
} catch (boost::bad_any_cast &) {
|
||||||
|
throw SandboxTrapException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack_frame(struct bindings &b) : bindings(b), inner(init(b)) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
~stack_frame() {
|
||||||
|
if (inner.is_complete()) {
|
||||||
|
bindings.stack.pop_back();
|
||||||
|
}
|
||||||
|
--bindings.depth;
|
||||||
|
}
|
||||||
|
inline T &operator()() {
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct stack_frame<T> bind() {
|
||||||
|
return (struct stack_frame<T>)(*this);
|
||||||
|
}
|
||||||
|
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
HEADER_END = <<~HEREDOC
|
HEADER_END = <<~HEREDOC
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif // MKXP_SANDBOX_BINDGEN_H
|
#endif // MKXP_SANDBOX_BINDGEN_H
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
|
@ -210,7 +254,6 @@ PRELUDE = <<~HEREDOC
|
||||||
// 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!
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <boost/asio/yield.hpp>
|
|
||||||
#include "mkxp-sandbox-bindgen.h"
|
#include "mkxp-sandbox-bindgen.h"
|
||||||
|
|
||||||
#if WABT_BIG_ENDIAN
|
#if WABT_BIG_ENDIAN
|
||||||
|
@ -223,10 +266,13 @@ PRELUDE = <<~HEREDOC
|
||||||
#define SERIALIZE_PTR(value) SERIALIZE_#{MEMORY64 ? '64' : '32'}(value)
|
#define SERIALIZE_PTR(value) SERIALIZE_#{MEMORY64 ? '64' : '32'}(value)
|
||||||
|
|
||||||
|
|
||||||
SandboxBind::SandboxBind(std::shared_ptr<struct w2c_#{MODULE_NAME}> m) : next_func_ptr(-1), instance(m) {}
|
using namespace mkxp_sandbox;
|
||||||
|
|
||||||
|
|
||||||
wasm_ptr_t SandboxBind::sbindgen_malloc(wasm_size_t size) {
|
bindings::bindings(std::shared_ptr<struct w2c_#{MODULE_NAME}> m) : next_func_ptr(-1), instance(m), depth(0) {}
|
||||||
|
|
||||||
|
|
||||||
|
wasm_ptr_t bindings::sbindgen_malloc(wasm_size_t size) {
|
||||||
wasm_ptr_t buf = w2c_#{MODULE_NAME}_#{MALLOC_FUNC}(instance.get(), size);
|
wasm_ptr_t buf = w2c_#{MODULE_NAME}_#{MALLOC_FUNC}(instance.get(), size);
|
||||||
|
|
||||||
// Verify that the entire allocated buffer is in valid memory
|
// Verify that the entire allocated buffer is in valid memory
|
||||||
|
@ -239,7 +285,7 @@ PRELUDE = <<~HEREDOC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wasm_ptr_t SandboxBind::sbindgen_create_func_ptr() {
|
wasm_ptr_t bindings::sbindgen_create_func_ptr() {
|
||||||
if (next_func_ptr == (wasm_ptr_t)-1) {
|
if (next_func_ptr == (wasm_ptr_t)-1) {
|
||||||
next_func_ptr = instance->w2c_T0.size;
|
next_func_ptr = instance->w2c_T0.size;
|
||||||
}
|
}
|
||||||
|
@ -426,21 +472,19 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
|
|
||||||
coroutine_vars.append("#{coroutine_ret} r") if handler[:primitive] != :void
|
coroutine_vars.append("#{coroutine_ret} r") if handler[:primitive] != :void
|
||||||
|
|
||||||
coroutine_args = ['SandboxBind &bind']
|
coroutine_args = (0...args.length).map do |i|
|
||||||
coroutine_args.append((0...args.length).map do |i|
|
|
||||||
args[i] == '...' ? '...'
|
args[i] == '...' ? '...'
|
||||||
: !ARG_HANDLERS[args[i]][:formatter].nil? ? ARG_HANDLERS[args[i]][:formatter].call("a#{i}")
|
: !ARG_HANDLERS[args[i]][:formatter].nil? ? ARG_HANDLERS[args[i]][:formatter].call("a#{i}")
|
||||||
: !ARG_HANDLERS[args[i]][:keep] ? "#{VAR_TYPE_TABLE[ARG_HANDLERS[args[i]][:primitive]]} a#{i}"
|
: !ARG_HANDLERS[args[i]][:keep] ? "#{VAR_TYPE_TABLE[ARG_HANDLERS[args[i]][:primitive]]} a#{i}"
|
||||||
: "#{args[i]} a#{i}"
|
: "#{args[i]} a#{i}"
|
||||||
end)
|
end
|
||||||
|
|
||||||
declaration_args = ['SandboxBind &']
|
declaration_args = (0...args.length).map do |i|
|
||||||
declaration_args.append((0...args.length).map do |i|
|
|
||||||
args[i] == '...' ? '...'
|
args[i] == '...' ? '...'
|
||||||
: !ARG_HANDLERS[args[i]][:formatter].nil? ? ARG_HANDLERS[args[i]][:formatter].call('')
|
: !ARG_HANDLERS[args[i]][:formatter].nil? ? ARG_HANDLERS[args[i]][:formatter].call('')
|
||||||
: !ARG_HANDLERS[args[i]][:keep] ? "#{VAR_TYPE_TABLE[ARG_HANDLERS[args[i]][:primitive]]}"
|
: !ARG_HANDLERS[args[i]][:keep] ? "#{VAR_TYPE_TABLE[ARG_HANDLERS[args[i]][:primitive]]}"
|
||||||
: "#{args[i]}"
|
: "#{args[i]}"
|
||||||
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}" : "a#{i}" }).join(', ')});
|
#{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}" : "a#{i}" }).join(', ')});
|
||||||
|
@ -451,6 +495,7 @@ File.readlines('tags', chomp: true).each do |line|
|
||||||
coroutine_finalizer = (0...buffers.length).map { |i| "w2c_#{MODULE_NAME}_#{FREE_FUNC}(bind.instance.get(), #{buffers[buffers.length - 1 - i]});" }
|
coroutine_finalizer = (0...buffers.length).map { |i| "w2c_#{MODULE_NAME}_#{FREE_FUNC}(bind.instance.get(), #{buffers[buffers.length - 1 - i]});" }
|
||||||
|
|
||||||
coroutine_definition = <<~HEREDOC
|
coroutine_definition = <<~HEREDOC
|
||||||
|
#{func_name}::#{func_name}(bindings &bind) : bind(bind) {}
|
||||||
#{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")}
|
||||||
reenter (this) {
|
reenter (this) {
|
||||||
#{coroutine_initializer.empty? ? '' : (coroutine_initializer.split("\n").map { |line| " #{line}" }.join("\n") + "\n\n")} for (;;) {
|
#{coroutine_initializer.empty? ? '' : (coroutine_initializer.split("\n").map { |line| " #{line}" }.join("\n") + "\n\n")} for (;;) {
|
||||||
|
@ -462,8 +507,13 @@ 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<struct #{func_name}>;
|
||||||
#{coroutine_ret} operator()(#{declaration_args.join(', ')});
|
#{coroutine_ret} operator()(#{declaration_args.join(', ')});
|
||||||
#{fields.empty? ? '' : (" private:\n" + fields.map { |field| " #{field};\n" }.join)}};
|
private:
|
||||||
|
#{func_name}(bindings &bind);
|
||||||
|
bindings &bind;
|
||||||
|
#{fields.empty? ? '' : fields.map { |field| " #{field};\n" }.join}};
|
||||||
HEREDOC
|
HEREDOC
|
||||||
|
|
||||||
func_names.append(func_name)
|
func_names.append(func_name)
|
||||||
|
@ -474,11 +524,11 @@ 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 func_name in func_names
|
for func_name in func_names
|
||||||
file.write(" friend struct #{func_name};\n")
|
file.write(" friend struct #{func_name};\n")
|
||||||
end
|
end
|
||||||
file.write("};\n")
|
file.write(" };\n")
|
||||||
for declaration in declarations
|
for declaration in declarations
|
||||||
file.write("\n" + declaration)
|
file.write("\n" + declaration.split("\n").map { |line| " #{line}" }.join("\n").rstrip)
|
||||||
end
|
end
|
||||||
file.write(HEADER_END)
|
file.write(HEADER_END)
|
||||||
end
|
end
|
||||||
|
@ -486,6 +536,6 @@ File.open('mkxp-sandbox-bindgen.cpp', 'w') do |file|
|
||||||
file.write(PRELUDE)
|
file.write(PRELUDE)
|
||||||
for coroutine in coroutines
|
for coroutine in coroutines
|
||||||
file.write("\n\n")
|
file.write("\n\n")
|
||||||
file.write(coroutine)
|
file.write(coroutine.rstrip)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
47
src/core.cpp
47
src/core.cpp
|
@ -24,24 +24,30 @@
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/asio/coroutine.hpp>
|
|
||||||
#include <boost/asio/yield.hpp>
|
|
||||||
#include "core.h"
|
|
||||||
#include "sandbox/sandbox.h"
|
#include "sandbox/sandbox.h"
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
#define AWAIT(coroutine, ...) do { coroutine(__VA_ARGS__); if (coroutine.is_complete()) break; yield; } while (1)
|
#define SANDBOX_AWAIT(coroutine, ...) \
|
||||||
|
do { \
|
||||||
|
{ \
|
||||||
|
auto frame = sandbox->bindings.bind<struct coroutine>(); \
|
||||||
|
frame()(__VA_ARGS__); \
|
||||||
|
if (frame().is_complete()) break; \
|
||||||
|
} \
|
||||||
|
yield; \
|
||||||
|
} while (1)
|
||||||
|
|
||||||
using namespace mkxp_retro;
|
using namespace mkxp_retro;
|
||||||
|
|
||||||
static void fallback_log(enum retro_log_level level, const char *fmt, ...) {
|
static void fallback_log(enum retro_log_level level, const char *fmt, ...) {
|
||||||
va_list va;
|
std::va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
vfprintf(stderr, fmt, va);
|
std::vfprintf(stderr, fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t *frame_buf;
|
static uint32_t *frame_buf;
|
||||||
static std::unique_ptr<Sandbox> sandbox;
|
static std::unique_ptr<struct mkxp_sandbox::sandbox> sandbox;
|
||||||
static const char *game_path = NULL;
|
static const char *game_path = NULL;
|
||||||
|
|
||||||
static VALUE my_cpp_func(w2c_ruby *ruby, int32_t argc, wasm_ptr_t argv, VALUE self) {
|
static VALUE my_cpp_func(w2c_ruby *ruby, int32_t argc, wasm_ptr_t argv, VALUE self) {
|
||||||
|
@ -50,24 +56,17 @@ static VALUE my_cpp_func(w2c_ruby *ruby, int32_t argc, wasm_ptr_t argv, VALUE se
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool init_sandbox() {
|
static bool init_sandbox() {
|
||||||
struct runtime : boost::asio::coroutine {
|
struct main : boost::asio::coroutine {
|
||||||
struct rb_eval_string eval;
|
|
||||||
struct rb_define_global_function define;
|
|
||||||
|
|
||||||
void operator()() {
|
void operator()() {
|
||||||
reenter (this) {
|
reenter (this) {
|
||||||
AWAIT(eval, sandbox->bind, "puts 'Hello, World!'");
|
SANDBOX_AWAIT(mkxp_sandbox::rb_eval_string, "puts 'Hello, World!'");
|
||||||
|
|
||||||
eval = rb_eval_string();
|
SANDBOX_AWAIT(mkxp_sandbox::rb_eval_string, "require 'zlib'; p Zlib::Deflate::deflate('hello')");
|
||||||
AWAIT(eval, sandbox->bind, "require 'zlib'; p Zlib::Deflate::deflate('hello')");
|
|
||||||
|
|
||||||
AWAIT(define, sandbox->bind, "my_cpp_func", (VALUE (*)(void *, ANYARGS))my_cpp_func, -1);
|
SANDBOX_AWAIT(mkxp_sandbox::rb_define_global_function, "my_cpp_func", (VALUE (*)(void *, ANYARGS))my_cpp_func, -1);
|
||||||
|
SANDBOX_AWAIT(mkxp_sandbox::rb_eval_string, "my_cpp_func(1, nil, 3, 'this is a string', :symbol, 2)");
|
||||||
|
|
||||||
eval = rb_eval_string();
|
SANDBOX_AWAIT(mkxp_sandbox::rb_eval_string, "p Dir.glob '/mkxp-retro-game/*'");
|
||||||
AWAIT(eval, sandbox->bind, "my_cpp_func(1, nil, 3, 'this is a string', :symbol, 2)");
|
|
||||||
|
|
||||||
eval = rb_eval_string();
|
|
||||||
AWAIT(eval, sandbox->bind, "p Dir.glob '/mkxp-retro-game/*'");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -75,12 +74,8 @@ static bool init_sandbox() {
|
||||||
sandbox.reset();
|
sandbox.reset();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sandbox.reset(new Sandbox(game_path));
|
sandbox.reset(new struct mkxp_sandbox::sandbox(game_path));
|
||||||
|
sandbox->run<struct main>();
|
||||||
struct runtime runtime;
|
|
||||||
|
|
||||||
// TODO: Replace this loop with a stackful executor, otherwise you won't be able to call into the Ruby API from inside of a C/C++ function that is itself called from inside of Ruby.
|
|
||||||
do runtime(); while (w2c_ruby_mkxp_sandbox_yield(&sandbox->module_instance()));
|
|
||||||
} catch (SandboxException) {
|
} catch (SandboxException) {
|
||||||
log_printf(RETRO_LOG_ERROR, "Failed to initialize Ruby\n");
|
log_printf(RETRO_LOG_ERROR, "Failed to initialize Ruby\n");
|
||||||
sandbox.reset();
|
sandbox.reset();
|
||||||
|
|
|
@ -38,12 +38,14 @@
|
||||||
#define WASM_MEM(address) ((void *)&ruby->w2c_memory.data[address])
|
#define WASM_MEM(address) ((void *)&ruby->w2c_memory.data[address])
|
||||||
#define AWAIT(statement) do statement; while (w2c_ruby_mkxp_sandbox_yield(RB))
|
#define AWAIT(statement) do statement; while (w2c_ruby_mkxp_sandbox_yield(RB))
|
||||||
|
|
||||||
|
using namespace mkxp_sandbox;
|
||||||
|
|
||||||
// This function is imported by wasm-rt-impl.c from wasm2c
|
// This function is imported by wasm-rt-impl.c from wasm2c
|
||||||
extern "C" void mkxp_sandbox_trap_handler(wasm_rt_trap_t code) {
|
extern "C" void mkxp_sandbox_trap_handler(wasm_rt_trap_t code) {
|
||||||
throw SandboxTrapException();
|
throw SandboxTrapException();
|
||||||
}
|
}
|
||||||
|
|
||||||
usize Sandbox::sandbox_malloc(usize size) {
|
usize sandbox::sandbox_malloc(usize size) {
|
||||||
usize buf = w2c_ruby_mkxp_sandbox_malloc(RB, size);
|
usize buf = w2c_ruby_mkxp_sandbox_malloc(RB, size);
|
||||||
|
|
||||||
// Verify that the returned pointer is non-null and the entire allocated buffer is in valid memory
|
// Verify that the returned pointer is non-null and the entire allocated buffer is in valid memory
|
||||||
|
@ -55,11 +57,11 @@ usize Sandbox::sandbox_malloc(usize size) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sandbox::sandbox_free(usize ptr) {
|
void sandbox::sandbox_free(usize ptr) {
|
||||||
w2c_ruby_mkxp_sandbox_free(RB, ptr);
|
w2c_ruby_mkxp_sandbox_free(RB, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sandbox::Sandbox(const char *game_path) : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby, game_path)), bind(ruby) {
|
sandbox::sandbox(const char *game_path) : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby, game_path)), bindings(ruby) {
|
||||||
try {
|
try {
|
||||||
// Initialize the sandbox
|
// Initialize the sandbox
|
||||||
wasm_rt_init();
|
wasm_rt_init();
|
||||||
|
@ -138,14 +140,10 @@ Sandbox::Sandbox(const char *game_path) : ruby(new struct w2c_ruby), wasi(new wa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sandbox::~Sandbox() {
|
sandbox::~sandbox() {
|
||||||
try {
|
try {
|
||||||
w2c_ruby_mkxp_sandbox_deinit(RB);
|
w2c_ruby_mkxp_sandbox_deinit(RB);
|
||||||
} catch (SandboxTrapException) {}
|
} catch (SandboxTrapException) {}
|
||||||
wasm2c_ruby_free(RB);
|
wasm2c_ruby_free(RB);
|
||||||
wasm_rt_free();
|
wasm_rt_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
w2c_ruby &Sandbox::module_instance() {
|
|
||||||
return *ruby;
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,19 +26,29 @@
|
||||||
#include <mkxp-sandbox-bindgen.h>
|
#include <mkxp-sandbox-bindgen.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
struct Sandbox {
|
namespace mkxp_sandbox {
|
||||||
private:
|
struct sandbox {
|
||||||
std::shared_ptr<struct w2c_ruby> ruby;
|
private:
|
||||||
std::unique_ptr<struct w2c_wasi__snapshot__preview1> wasi;
|
std::shared_ptr<struct w2c_ruby> ruby;
|
||||||
|
std::unique_ptr<struct w2c_wasi__snapshot__preview1> wasi;
|
||||||
|
usize sandbox_malloc(usize size);
|
||||||
|
void sandbox_free(usize ptr);
|
||||||
|
|
||||||
usize sandbox_malloc(usize size);
|
public:
|
||||||
void sandbox_free(usize ptr);
|
struct mkxp_sandbox::bindings bindings;
|
||||||
|
sandbox(const char *game_path);
|
||||||
|
~sandbox();
|
||||||
|
|
||||||
public:
|
// TODO: handle Ruby fibers properly instead of crashing whenever Ruby switches to a different fiber than the main one
|
||||||
SandboxBind bind;
|
template <typename T> inline void run() {
|
||||||
Sandbox(const char *game_path);
|
T coroutine = T();
|
||||||
~Sandbox();
|
do {
|
||||||
struct w2c_ruby &module_instance();
|
coroutine();
|
||||||
};
|
w2c_ruby_mkxp_sandbox_yield(ruby.get());
|
||||||
|
} while (!coroutine.is_complete());
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif // MKXPZ_SANDBOX_H
|
#endif // MKXPZ_SANDBOX_H
|
||||||
|
|
4
subprojects/boost_any.wrap
Normal file
4
subprojects/boost_any.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/any
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_assert.wrap
Normal file
4
subprojects/boost_assert.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/assert
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_config.wrap
Normal file
4
subprojects/boost_config.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/config
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_container_hash.wrap
Normal file
4
subprojects/boost_container_hash.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/container_hash
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_core.wrap
Normal file
4
subprojects/boost_core.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/core
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_describe.wrap
Normal file
4
subprojects/boost_describe.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/describe
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_mp11.wrap
Normal file
4
subprojects/boost_mp11.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/mp11
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_static_assert.wrap
Normal file
4
subprojects/boost_static_assert.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/static_assert
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_throw_exception.wrap
Normal file
4
subprojects/boost_throw_exception.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/throw_exception
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
4
subprojects/boost_type_index.wrap
Normal file
4
subprojects/boost_type_index.wrap
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/type_index
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
Loading…
Add table
Reference in a new issue