Replace WABT's WebAssembly runtime with a custom implementation

This commit is contained in:
刘皓 2025-02-11 20:40:55 -05:00
parent c90c659517
commit 206e8508b6
No known key found for this signature in database
GPG key ID: 7901753DB465B711
19 changed files with 347 additions and 178 deletions

View file

@ -902,7 +902,17 @@ jobs:
mkdir ~/retro-phase2
cd build
CLICOLOR_FORCE=1 ninja -v
mv mkxp-z_libretro.a ~/retro-phase2
mv mkxp-z_libretro.a ~
- name: Build RetroArch
run: |
cd ~
git clone https://github.com/libretro/RetroArch retroarch --depth 1 -b $(curl -s https://api.github.com/repos/libretro/RetroArch/releases/latest | jq -r '.tag_name')
mv mkxp-z_libretro.a retroarch/libretro_ctr.a
cd retroarch
CLICOLOR_FORCE=1 make -f Makefile.ctr LIBRETRO=mkxp-z USE_CTRULIB_2=1
mv retroarch_3ds.cia ~/retro-phase2/mkxp-z_libretro.cia
mv retroarch_3ds.3dsx ~/retro-phase2/mkxp-z_libretro.3dsx
- name: Upload artifact
uses: actions/upload-artifact@v4
@ -956,7 +966,16 @@ jobs:
mkdir ~/retro-phase2
cd build
CLICOLOR_FORCE=1 ninja -v
mv mkxp-z_libretro.a ~/retro-phase2
mv mkxp-z_libretro.a ~
- name: Build RetroArch
run: |
cd ~
git clone https://github.com/libretro/RetroArch retroarch --depth 1 -b $(curl -s https://api.github.com/repos/libretro/RetroArch/releases/latest | jq -r '.tag_name')
mv mkxp-z_libretro.a retroarch/libretro_vita.a
cd retroarch
CLICOLOR_FORCE=1 make -f Makefile.vita LIBRETRO=mkxp-z
mv retroarch_vita.self ~/retro-phase2/mkxp-z_libretro.self
- name: Upload artifact
uses: actions/upload-artifact@v4
@ -1012,7 +1031,16 @@ jobs:
mkdir ~/retro-phase2
cd build
CLICOLOR_FORCE=1 ninja -v
mv mkxp-z_libretro.a ~/retro-phase2
mv mkxp-z_libretro.a ~
- name: Build RetroArch
run: |
cd ~
git clone https://github.com/libretro/RetroArch retroarch --depth 1 -b $(curl -s https://api.github.com/repos/libretro/RetroArch/releases/latest | jq -r '.tag_name')
mv mkxp-z_libretro.a retroarch/libretro_wiiu.a
cd retroarch
CLICOLOR_FORCE=1 make -f Makefile.wiiu LIBRETRO=mkxp-z
mv retroarch_wiiu.rpx ~/retro-phase2/mkxp-z_libretro.rpx
- name: Upload artifact
uses: actions/upload-artifact@v4
@ -1068,7 +1096,17 @@ jobs:
mkdir ~/retro-phase2
cd build
CLICOLOR_FORCE=1 ninja -v
mv mkxp-z_libretro.a ~/retro-phase2
mv mkxp-z_libretro.a ~
- name: Build RetroArch
run: |
cd ~
git clone https://github.com/libretro/RetroArch retroarch --depth 1 -b $(curl -s https://api.github.com/repos/libretro/RetroArch/releases/latest | jq -r '.tag_name')
mv mkxp-z_libretro.a retroarch/libretro_libnx.a
cd retroarch
CLICOLOR_FORCE=1 make -f Makefile.libnx LIBRETRO=mkxp-z
mv retroarch_switch.nro ~/retro-phase2/mkxp-z_libretro.nro
mv retroarch_switch.elf ~/retro-phase2/mkxp-z_libretro.elf
- name: Upload artifact
uses: actions/upload-artifact@v4

View file

@ -22,7 +22,7 @@
#ifndef MKXPZ_SANDBOX_AUDIO_BINDING_H
#define MKXPZ_SANDBOX_AUDIO_BINDING_H
#include "binding-sandbox/core.h"
#include "core.h"
#include "sandbox.h"
namespace mkxp_sandbox {

View file

@ -21,7 +21,7 @@
#include "binding-base.h"
#if WABT_BIG_ENDIAN
#if MKXPZ_BIG_ENDIAN
# define SERIALIZE_32(value) __builtin_bswap32(value)
# define SERIALIZE_64(value) __builtin_bswap64(value)
#else
@ -83,39 +83,6 @@ 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);
}

View file

@ -32,9 +32,9 @@
#include <boost/type_index.hpp>
#include <boost/asio/coroutine.hpp>
#include <mkxp-retro-ruby.h>
#include "binding-sandbox/types.h"
#include "types.h"
#if WABT_BIG_ENDIAN
#ifdef MKXPZ_BIG_ENDIAN
# define SERIALIZE_32(value) __builtin_bswap32(value)
# define SERIALIZE_64(value) __builtin_bswap64(value)
#else
@ -82,7 +82,6 @@ namespace mkxp_sandbox {
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);

View file

@ -23,7 +23,7 @@
#define MKXPZ_BINDING_SANDBOX_H
#include <zlib.h>
#include "binding-sandbox/core.h"
#include "core.h"
#include "sandbox.h"
#include "binding-util.h"
#include "audio-binding.h"

View file

@ -22,7 +22,7 @@
#ifndef MKXPZ_SANDBOX_BINDING_UTIL_H
#define MKXPZ_SANDBOX_BINDING_UTIL_H
#include "binding-sandbox/core.h"
#include "core.h"
#include "sandbox.h"
#define GFX_GUARD_EXC(exp) exp // TODO: implement

View file

@ -23,7 +23,7 @@
#define MKXPZ_CORE_H
#include <libretro.h>
#include "../binding-sandbox/sandbox.h"
#include "sandbox.h"
#include "audio.h"
#include "filesystem.h"
#include "input.h"

View file

@ -40,11 +40,6 @@
using namespace mkxp_sandbox;
// This function is imported by wasm-rt-impl.c from wasm2c
extern "C" void mkxp_sandbox_trap_handler(wasm_rt_trap_t code) {
throw SandboxTrapException();
}
usize sandbox::sandbox_malloc(usize size) {
usize buf = w2c_ruby_mkxp_sandbox_malloc(RB, size);
@ -64,7 +59,6 @@ void sandbox::sandbox_free(usize ptr) {
sandbox::sandbox() : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby)), bindings(ruby), yielding(false) {
try {
// Initialize the sandbox
wasm_rt_init();
wasm2c_ruby_instantiate(RB, wasi.get());
w2c_ruby_mkxp_sandbox_init(RB);
@ -120,18 +114,9 @@ sandbox::sandbox() : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby)), bindings
AWAIT(enc = w2c_ruby_rb_enc_from_encoding(RB, encoding));
AWAIT(w2c_ruby_rb_enc_set_default_internal(RB, enc));
AWAIT(w2c_ruby_rb_enc_set_default_external(RB, enc));
} catch (SandboxNodeException e) {
} catch (SandboxException &) {
wasm2c_ruby_free(RB);
wasm_rt_free();
throw e;
} catch (SandboxOutOfMemoryException e) {
wasm2c_ruby_free(RB);
wasm_rt_free();
throw e;
} catch (SandboxTrapException e) {
wasm2c_ruby_free(RB);
wasm_rt_free();
throw e;
throw;
}
}
@ -141,5 +126,4 @@ sandbox::~sandbox() {
}
bindings.reset(); // Destroy the bindings before destroying the runtime since the bindings destructor requires the runtime to be alive
wasm2c_ruby_free(RB);
wasm_rt_free();
}

View file

@ -32,7 +32,7 @@
// Internal utility macros
#define _WASM_CAT(x, y) x##y
#define WASM_CAT(x, y) _WASM_CAT(x, y)
#if WABT_BIG_ENDIAN
#ifdef MKXPZ_BIG_ENDIAN
#define WASM_ORDER_u8(value) (value)
#define WASM_ORDER_s8(value) (value)
#define WASM_ORDER_u16(value) __builtin_bswap16(value)
@ -54,7 +54,7 @@
#define WASM_ORDER_s64(value) (value)
#define WASM_ORDER_f32(value) (value)
#define WASM_ORDER_f64(value) (value)
#endif // WABT_BIG_ENDIAN
#endif // MKXPZ_BIG_ENDIAN
#define WASM_ORDER_usize(value) WASM_CAT(WASM_ORDER_, usize)(value)
// Memory manipulation macros

View file

@ -0,0 +1,89 @@
/*
** wasm-rt.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 <cstdlib>
#include <vector>
#include "core.h"
#include "wasm-rt.h"
#define PAGE_SIZE 65536U
#define MIN_PAGES 1024U // tentative
extern "C" bool wasm_rt_is_initialized(void) {
return true;
}
extern "C" void wasm_rt_trap(wasm_rt_trap_t error) {
mkxp_retro::log_printf(RETRO_LOG_ERROR, "Sandbox error %d\n", error);
std::abort();
}
extern "C" void wasm_rt_allocate_memory(wasm_rt_memory_t *memory, uint32_t initial_pages, uint32_t max_pages, bool is64) {
memory->data = (uint8_t *)std::malloc(std::max(initial_pages, MIN_PAGES) * PAGE_SIZE);
if (memory->data == NULL) {
throw std::bad_alloc();
}
memory->pages = initial_pages;
memory->size = initial_pages * PAGE_SIZE;
}
extern "C" uint32_t wasm_rt_grow_memory(wasm_rt_memory_t *memory, uint32_t pages) {
uint32_t new_pages;
if (__builtin_add_overflow(memory->pages, pages, &new_pages)) {
return -1;
}
uint8_t *new_data = new_pages <= MIN_PAGES ? memory->data : (uint8_t *)std::realloc(memory->data, new_pages * PAGE_SIZE);
if (new_data == NULL) {
return -1;
}
#ifdef MKXPZ_BIG_ENDIAN
std::memmove(new_data + pages * PAGE_SIZE, new_data, memory->size);
#endif // MKXPZ_BIG_ENDIAN
uint32_t old_pages = memory->pages;
memory->pages = new_pages;
memory->size = new_pages * PAGE_SIZE;
memory->data = new_data;
return old_pages;
}
extern "C" void wasm_rt_free_memory(wasm_rt_memory_t *memory) {
std::free(memory->data);
}
extern "C" void wasm_rt_allocate_funcref_table(wasm_rt_funcref_table_t *table, uint32_t elements, uint32_t max_elements) {
table->private_data = new std::vector<wasm_rt_funcref_t>(elements);
table->data = ((std::vector<wasm_rt_funcref_t> *)table->private_data)->data();
table->size = elements;
}
extern "C" void wasm_rt_free_funcref_table(wasm_rt_funcref_table_t *table) {
delete (std::vector<wasm_rt_funcref_t> *)table->private_data;
}
extern "C" uint32_t wasm_rt_push_funcref(wasm_rt_funcref_table_t *table, wasm_rt_funcref_t funcref) {
if (table->size == (uint32_t)-1) {
throw std::bad_alloc();
}
((std::vector<wasm_rt_funcref_t> *)table->private_data)->push_back(funcref);
table->data = ((std::vector<wasm_rt_funcref_t> *)table->private_data)->data();
return table->size++;
}

139
binding-sandbox/wasm-rt.h Normal file
View file

@ -0,0 +1,139 @@
/*
** wasm-rt.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_WASM_RT_H
#define MKXPZ_SANDBOX_WASM_RT_H
#include <stdbool.h>
#include <stdint.h>
#ifndef __GNUC__
# include <string.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MKXPZ_BIG_ENDIAN
# define WABT_BIG_ENDIAN 1
#endif
#ifndef LIKELY
# ifdef __GNUC__
# define LIKELY(x) __builtin_expect(x, 1)
# else
# define LIKELY(x) (x)
# endif
#endif
#ifndef UNLIKELY
# ifdef __GNUC__
# define UNLIKELY(x) __builtin_expect(x, 0)
# else
# define UNLIKELY(x) (x)
# endif
#endif
#ifdef __GNUC__
# define wasm_rt_memcpy __builtin_memcpy
#else
# define wasm_rt_memcpy memcpy
#endif
/* Don't define this as an enum. It causes builds using devkitARM or Vita SDK to successfully compile but crash on startup. */
typedef int wasm_rt_type_t;
#define WASM_RT_I32 0
#define WASM_RT_I64 1
#define WASM_RT_F32 2
#define WASM_RT_F64 3
#define WASM_RT_FUNCREF 4
#define WASM_RT_EXTERNREF 5
typedef int wasm_rt_trap_t;
#define WASM_RT_TRAP_NONE 0
#define WASM_RT_TRAP_OOB 1
#define WASM_RT_TRAP_INT_OVERFLOW 2
#define WASM_RT_TRAP_DIV_BY_ZERO 3
#define WASM_RT_TRAP_INVALID_CONVERSION 4
#define WASM_RT_TRAP_UNREACHABLE 5
#define WASM_RT_TRAP_CALL_INDIRECT 6
#define WASM_RT_TRAP_UNCAUGHT_EXCEPTION 7
#define WASM_RT_TRAP_EXHAUSTION 8
typedef const char *wasm_rt_func_type_t;
typedef void (*wasm_rt_function_ptr_t)(void);
typedef struct {
void *fn;
} wasm_rt_tailcallee_t;
typedef struct {
wasm_rt_func_type_t func_type;
wasm_rt_function_ptr_t func;
wasm_rt_tailcallee_t func_tailcallee;
void *module_instance;
} wasm_rt_funcref_t;
#define wasm_rt_funcref_null_value (wasm_rt_funcref_t){NULL, NULL, {NULL}, NULL};
typedef struct {
uint8_t *data;
uint64_t pages;
uint64_t size;
} wasm_rt_memory_t;
typedef struct {
void *private_data;
wasm_rt_funcref_t *data;
uint32_t size;
} wasm_rt_funcref_table_t;
typedef void *wasm_rt_externref_t;
#define wasm_rt_externref_null_value NULL;
typedef struct {
wasm_rt_externref_t *data;
uint32_t size;
} wasm_rt_externref_table_t;
bool wasm_rt_is_initialized(void);
void wasm_rt_trap(wasm_rt_trap_t error);
void wasm_rt_allocate_memory(wasm_rt_memory_t *memory, uint32_t initial_pages, uint32_t max_pages, bool is64);
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t *memory, uint32_t pages);
void wasm_rt_free_memory(wasm_rt_memory_t *memory);
void wasm_rt_allocate_funcref_table(wasm_rt_funcref_table_t *table, uint32_t elements, uint32_t max_elements);
void wasm_rt_free_funcref_table(wasm_rt_funcref_table_t *table);
uint32_t wasm_rt_push_funcref(wasm_rt_funcref_table_t *table, wasm_rt_funcref_t funcref);
#ifdef __cplusplus
}
#endif
#endif /* MKXPZ_SANDBOX_WASM_RT_H */

View file

@ -190,14 +190,11 @@ if get_option('retro') == true
retro_defines = [
'-DMKXPZ_VERSION="@0@"'.format(meson.project_version()),
'-DWASM_RT_SKIP_SIGNAL_RECOVERY',
'-DWASM_RT_TRAP_HANDLER=mkxp_sandbox_trap_handler',
'-DMKXPZ_RETRO',
'-DSHARED_FLUID',
]
if host_endian == 'big'
retro_defines += '-DMKXPZ_BIG_ENDIAN'
retro_defines += '-DWABT_BIG_ENDIAN=1'
endif
if host_system == 'emscripten' or not compilers['cpp'].compiles('struct E {}; int main() { throw E(); }', name: 'check if C++ exceptions are enabled')
retro_defines += '-DMKXPZ_NO_EXCEPTIONS'
@ -279,8 +276,10 @@ if get_option('retro') == true
cpp_args: ['-Wno-unused-command-line-argument'] + retro_cppflags + retro_defines,
link_args: retro_link_args,
gnu_symbol_visibility: 'hidden',
install: true, # Prevents Meson from creating thin archives when building with `--default-library static`; see https://github.com/mesonbuild/meson/issues/9479
include_directories: [
include_directories('.'),
include_directories('binding-sandbox'),
include_directories('src'),
include_directories('src/audio'),
include_directories('src/crypto'),
@ -298,7 +297,6 @@ if get_option('retro') == true
include_directories('src/util/sigslot'),
include_directories('src/util/sigslot/adapter'),
include_directories(retro_phase1),
include_directories(join_paths(retro_phase1, 'wasm2c')),
include_directories(join_paths(retro_phase1, 'mkxp-retro-ruby')),
include_directories(join_paths(retro_phase1, 'sdl/include')),
],
@ -331,12 +329,11 @@ if get_option('retro') == true
'binding-sandbox/binding-util.cpp',
'binding-sandbox/sandbox.cpp',
'binding-sandbox/wasi.cpp',
'binding-sandbox/wasm-rt.cpp',
'binding/module_rpg.cpp',
join_paths(retro_phase1, 'GMGSx.sf2.c'),
join_paths(retro_phase1, 'wasm2c/wasm-rt-impl.c'),
join_paths(retro_phase1, 'wasm2c/wasm-rt-mem-impl.c'),
join_paths(retro_phase1, 'GMGSx.sf2.cpp'),
join_paths(retro_phase1, 'mkxp-sandbox-bindgen.cpp'),
join_paths(retro_phase1, 'mkxp-retro-dist.zip.c'),
join_paths(retro_phase1, 'mkxp-retro-dist.zip.cpp'),
join_paths(retro_phase1, 'mkxp-retro-ruby/mkxp-retro-ruby_0.c'),
join_paths(retro_phase1, 'mkxp-retro-ruby/mkxp-retro-ruby_1.c'),
join_paths(retro_phase1, 'mkxp-retro-ruby/mkxp-retro-ruby_2.c'),
@ -352,7 +349,6 @@ else
global_sources += vcs_tag(command: ['git', 'rev-parse', '--short', 'HEAD'], fallback: 'unknown', input: 'src/git-hash.h.in', output: 'git-hash.h')
if host_endian == 'big'
global_args += '-DMKXPZ_BIG_ENDIAN'
global_args += '-DWABT_BIG_ENDIAN=1'
endif
if host_system == 'emscripten' or not compilers['cpp'].compiles('struct E {}; int main() { throw E(); }', name: 'check if C++ exceptions are enabled')
retro_defines += '-DMKXPZ_NO_EXCEPTIONS'

View file

@ -48,18 +48,18 @@ WASI_TOOLCHAIN := CC=$(WASI_CC) CXX=$(WASI_CXX) LD=$(WASI_LD) AR=$(WASI_AR) RANL
all default: deps ruby-dist ruby-bindings
ruby-dist: $(OUTDIR)/mkxp-retro-dist.zip.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby.h $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby-impl.h $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_0.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_1.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_2.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_3.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_4.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_5.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_6.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_7.c
ruby-dist: $(OUTDIR)/mkxp-retro-dist.zip.cpp $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby.h $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby-impl.h $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_0.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_1.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_2.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_3.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_4.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_5.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_6.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_7.c
ruby-bindings: $(OUTDIR)/mkxp-sandbox-bindgen.cpp $(OUTDIR)/mkxp-sandbox-bindgen.h
deps: $(OUTDIR)/GMGSx.sf2.c $(OUTDIR)/libretro.h $(OUTDIR)/wasm2c/wasm-rt.h $(OUTDIR)/wasm2c/wasm-rt-impl.c $(OUTDIR)/wasm2c/wasm-rt-mem-impl.c $(OUTDIR)/sdl/include/SDL.h
deps: $(OUTDIR)/GMGSx.sf2.cpp $(OUTDIR)/libretro.h $(OUTDIR)/sdl/include/SDL.h
clean: clean-ruby-dist clean-ruby-bindings clean-deps
rm -rf $(LIBDIR)/*
rm -rf $(DOWNLOADS)/*
clean-ruby-dist:
rm -f $(OUTDIR)/mkxp-retro-dist.zip.c
rm -f $(OUTDIR)/mkxp-retro-dist.zip.cpp
rm -rf $(LIBDIR)/mkxp-retro-ruby
clean-ruby-bindings:
@ -69,27 +69,19 @@ clean-ruby-bindings:
rm -f $(LIBDIR)/tags
clean-deps:
rm -f $(OUTDIR)/GMGSx.sf2.c
rm -f $(OUTDIR)/GMGSx.sf2.cpp
rm -f $(OUTDIR)/libretro.h
rm -rf $(OUTDIR)/wasm2c
rm -rf $(OUTDIR)/sdl
rm -rf $(DOWNLOADS)/wabt
$(OUTDIR)/GMGSx.sf2.c: GMGSx.sf2
$(OUTDIR)/GMGSx.sf2.cpp: GMGSx.sf2
mkdir -p $(OUTDIR)
$(XXD) -i GMGSx.sf2 $(OUTDIR)/GMGSx.sf2.c
$(XXD) -i GMGSx.sf2 $(OUTDIR)/GMGSx.sf2.cpp
$(OUTDIR)/libretro.h:
mkdir -p $(OUTDIR)
$(CURL) -s -L -o $(OUTDIR)/libretro.h https://raw.githubusercontent.com/libretro/libretro-common/$(LIBRETRO_REF)/include/libretro.h
$(OUTDIR)/wasm2c/wasm-rt.h $(OUTDIR)/wasm2c/wasm-rt-impl.c $(OUTDIR)/wasm2c/wasm-rt-mem-impl.c &:
mkdir -p $(DOWNLOADS)
mkdir -p $(OUTDIR)
$(CLONE) $(GITHUB)/WebAssembly/wabt $(DOWNLOADS)/wabt -b $(WASM_RT_VERSION)
$(SED) -i 's/# *define * WASM_RT_C11_AVAILABLE//g' $(DOWNLOADS)/wabt/wasm2c/wasm-rt.h # Stop wasm-rt from trying to use threads because it causes compiler errors on some game console toolchains, and also because OpenAL Soft defines a header file named "threads.h" which conflicts with the C11 threads.h that this file tries to include
cp -r $(DOWNLOADS)/wabt/wasm2c $(OUTDIR)
$(OUTDIR)/sdl/include/SDL.h:
mkdir -p $(OUTDIR)
$(CLONE) $(GITHUB)/libsdl-org/SDL $(OUTDIR)/sdl -b release-$(SDL_VERSION)
@ -99,16 +91,10 @@ $(OUTDIR)/sdl/include/SDL.h:
$(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby.h $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby-impl.h $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_0.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_1.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_2.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_3.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_4.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_5.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_6.c $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_7.c &: $(LIBDIR)/mkxp-retro-dist/bin/ruby
mkdir -p $(OUTDIR)/mkxp-retro-ruby
$(WASM2C) $(LIBDIR)/mkxp-retro-dist/bin/ruby -n ruby --num-outputs=8 -o $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby.c
# If we don't do this, the devkitARM and Vita SDK compilers will throw this warning due to some idiosyncrasy in how integer types work in those toolchains:
# warning: 'wasm_rt_type_t' is promoted to 'int' when passed through '...'
# note: (so you should pass 'int' not 'wasm_rt_type_t' to 'va_arg')
# note: if this code is reached, the program will abort
# The code will still compile, but like it says, the compiler will sprinkle trap instructions everywhere, so when you run the code it'll crash. Scary! Let's make sure that doesn't happen.
if ! for i in $$(seq 0 7); do $(SED) -i 's/va_arg(\([a-z_][A-Za-z0-9_]*\), *wasm_rt_type_t)/va_arg(\1, int)/g' $(OUTDIR)/mkxp-retro-ruby/mkxp-retro-ruby_$$i.c; done; then rm -rf $(OUTDIR)/mkxp-retro-ruby; exit 1; fi
$(OUTDIR)/mkxp-retro-dist.zip.c: $(LIBDIR)/mkxp-retro-dist.zip
$(OUTDIR)/mkxp-retro-dist.zip.cpp: $(LIBDIR)/mkxp-retro-dist.zip
mkdir -p $(OUTDIR)
cd $(LIBDIR) && $(XXD) -i mkxp-retro-dist.zip $(OUTDIR)/mkxp-retro-dist.zip.c
cd $(LIBDIR) && $(XXD) -i mkxp-retro-dist.zip $(OUTDIR)/mkxp-retro-dist.zip.cpp
$(LIBDIR)/mkxp-retro-dist.zip: $(LIBDIR)/mkxp-retro-dist/bin/ruby
rm -rf $(LIBDIR)/_mkxp-retro-dist

View file

@ -48,12 +48,6 @@ MKXP_SANDBOX_API void mkxp_sandbox_init(void) {
async_buf_init(&mkxp_sandbox_async_buf);
}
/* This function should be called immediately before deinitializing the sandbox. */
MKXP_SANDBOX_API void mkxp_sandbox_deinit(void) {
void __wasm_call_dtors(void); /* Defined by wasi-libc from the WASI SDK */
__wasm_call_dtors();
}
/* Exposes the `malloc()` function. */
MKXP_SANDBOX_API void *mkxp_sandbox_malloc(size_t size) {
return malloc(size);

View file

@ -304,75 +304,56 @@ 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;
wasm_ptr_t buf;
wasm_ptr_t str;
ptrs[0] = sandbox_malloc(9 * sizeof(wasm_ptr_t));
ptrs[1] = sandbox_malloc(std::strlen(wrap_struct_name) + 1);
for (size_t i = 0; i < 2; ++i) {
if (ptrs[i] == 0) oom = true;
buf = sandbox_malloc(9 * sizeof(wasm_ptr_t));
if (buf == 0) {
throw SandboxOutOfMemoryException();
}
for (size_t i = 2; i < 6; ++i) {
if ((i == 2 && dmark == NULL) || (i == 3 && dfree == NULL) || (i == 4 && dsize == NULL) || (i == 5 && dcompact == NULL)) continue;
ptrs[i] = sandbox_create_func_ptr();
if (ptrs[i] == (wasm_ptr_t)-1) oom = true;
}
if (oom) {
for (size_t i = 0; i < 2; ++i) {
if (ptrs[i] != 0) sandbox_free(ptrs[i]);
}
str = sandbox_malloc(std::strlen(wrap_struct_name) + 1);
if (str == 0) {
sandbox_free(buf);
throw SandboxOutOfMemoryException();
}
std::strcpy((char *)(**this + ptrs[1]), wrap_struct_name);
std::strcpy((char *)(**this + str), wrap_struct_name);
((wasm_ptr_t *)(**this + buf))[0] = SERIALIZE_VALUE(str);
if (dmark != NULL) {
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},
.module_instance = (void *)dmark,
};
}
((wasm_ptr_t *)(**this + buf))[1] = dmark == NULL ? 0 : SERIALIZE_VALUE(wasm_rt_push_funcref(&instance().w2c_T0, 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},
.module_instance = (void *)dmark,
}));
if (dfree != NULL) {
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},
.module_instance = (void *)dfree,
};
}
((wasm_ptr_t *)(**this + buf))[2] = dfree == NULL ? 0 : SERIALIZE_VALUE(wasm_rt_push_funcref(&instance().w2c_T0, 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},
.module_instance = (void *)dfree,
}));
if (dsize != NULL) {
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},
.module_instance = (void *)dsize,
};
}
((wasm_ptr_t *)(**this + buf))[3] = dsize == NULL ? 0 : SERIALIZE_VALUE(wasm_rt_push_funcref(&instance().w2c_T0, wasm_rt_funcref_t {
.func_type = wasm2c_#{MODULE_NAME}_get_func_type(1, 0, #{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},
.module_instance = (void *)dsize,
}));
if (dcompact != NULL) {
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},
.module_instance = (void *)dcompact,
};
}
((wasm_ptr_t *)(**this + buf))[4] = dcompact == NULL ? 0 : SERIALIZE_VALUE(wasm_rt_push_funcref(&instance().w2c_T0, 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},
.module_instance = (void *)dcompact,
}));
for (size_t i = 1; i < 6; ++i) {
((wasm_ptr_t *)(**this + ptrs[0]))[i - 1] = SERIALIZE_VALUE(ptrs[i]);
}
((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);
((wasm_ptr_t *)(**this + buf))[5] = 0;
((wasm_ptr_t *)(**this + buf))[6] = SERIALIZE_VALUE(parent);
((wasm_ptr_t *)(**this + buf))[7] = SERIALIZE_VALUE(data);
((wasm_ptr_t *)(**this + buf))[8] = SERIALIZE_VALUE(flags);
return ptrs[0];
return buf;
}
//////////////////////////////////////////////////////////////////////////////
@ -461,39 +442,35 @@ File.readlines('tags', chomp: true).each do |line|
# Generate bindings for converting the arguments
if !handler[:func_ptr_args].nil? || handler[:anyargs]
coroutine_initializer += <<~HEREDOC
f#{i} = bind.sandbox_create_func_ptr();
if (f#{i} == (wasm_ptr_t)-1) throw SandboxOutOfMemoryException();
HEREDOC
if handler[:anyargs]
coroutine_initializer += <<~HEREDOC
switch (a#{args.length - 1}) {
case -1:
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
f#{i} = wasm_rt_push_funcref(&bind.instance().w2c_T0, 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},
.module_instance = (void *)a#{i},
};
});
break;
case -2:
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
f#{i} = wasm_rt_push_funcref(&bind.instance().w2c_T0, 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},
.module_instance = (void *)a#{i},
};
});
break;
HEREDOC
for j in 0..16
case_str = <<~HEREDOC
case #{j}:
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
f#{i} = wasm_rt_push_funcref(&bind.instance().w2c_T0, 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},
.module_instance = (void *)a#{i},
};
});
break;
HEREDOC
coroutine_initializer += case_str.split("\n").map { |line| " #{line}".rstrip }.join("\n") + "\n"
@ -505,12 +482,12 @@ File.readlines('tags', chomp: true).each do |line|
HEREDOC
else
coroutine_initializer += <<~HEREDOC
bind.instance().w2c_T0.data[f#{i}] = wasm_rt_funcref_t {
f#{i} = wasm_rt_push_funcref(&bind.instance().w2c_T0, 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},
.module_instance = (void *)a#{i},
};
});
HEREDOC
end
coroutine_initializer += "\n"

View file

@ -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 "sandbox.h"
#include "binding-sandbox.h"
#include "core.h"
#include "filesystem.h"
using namespace mkxp_retro;

View file

@ -20,7 +20,7 @@
*/
#include "input.h"
#include "binding-sandbox/core.h"
#include "core.h"
#define JOYPAD_BUTTON_MAX 16
#define REPEAT_NONE 255

View file

@ -27,7 +27,7 @@
#include <vector>
#ifdef MKXPZ_RETRO
# include "binding-sandbox/core.h"
# include "core.h"
#elif defined(__ANDROID__)
# include <android/log.h>
#endif

View file

@ -1,4 +1,4 @@
# Removes the call to `__android_log_printf()` when targeting Android because we get missing symbol errors on Android otherwise.
# Removes the call to `__android_log_print()` when targeting Android because we get missing symbol errors on Android otherwise.
--- a/core/logging.cpp
+++ b/core/logging.cpp