mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-08-23 15:23:44 +02:00
Store destructors in a global table instead of in the object itself in libretro builds
This commit is contained in:
parent
16e701fc7c
commit
cd628048ef
7 changed files with 75 additions and 49 deletions
|
@ -198,7 +198,7 @@ void binding_base::strncpy(wasm_ptr_t dst_address, const char *src, wasm_size_t
|
||||||
sandbox_strncpy(instance(), dst_address, src, max_size);
|
sandbox_strncpy(instance(), dst_address, src, max_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
binding_base::object::object(wasm_size_t typenum, void *ptr, void (*destructor)(void *)) : typenum(typenum), inner {.inner = {.ptr = ptr, .destructor = destructor}} {}
|
binding_base::object::object(wasm_size_t typenum, void *ptr) : typenum(typenum), inner {.ptr = ptr} {}
|
||||||
|
|
||||||
binding_base::object::object(struct object &&object) noexcept : typenum(std::exchange(object.typenum, 0)), inner(std::exchange(object.inner, (union binding_base::object::inner){.next = 0})) {}
|
binding_base::object::object(struct object &&object) noexcept : typenum(std::exchange(object.typenum, 0)), inner(std::exchange(object.inner, (union binding_base::object::inner){.next = 0})) {}
|
||||||
|
|
||||||
|
@ -210,16 +210,16 @@ struct binding_base::object &binding_base::object::operator=(struct object &&obj
|
||||||
|
|
||||||
binding_base::object::~object() {
|
binding_base::object::~object() {
|
||||||
if (typenum != 0) {
|
if (typenum != 0) {
|
||||||
inner.inner.destructor(inner.inner.ptr);
|
typenum_table[typenum - 1].destructor(inner.ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr, void (*destructor)(void *)) {
|
wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr) {
|
||||||
if (typenum == 0 || ptr == nullptr || destructor == nullptr) {
|
if (ptr == nullptr || typenum == 0 || typenum > typenum_table_size) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
if (next_free_objkey == 0) {
|
if (next_free_objkey == 0) {
|
||||||
objects.emplace_back(typenum, ptr, destructor);
|
objects.emplace_back(typenum, ptr);
|
||||||
if ((size_t)(wasm_objkey_t)objects.size() < objects.size()) {
|
if ((size_t)(wasm_objkey_t)objects.size() < objects.size()) {
|
||||||
MKXPZ_THROW(std::bad_alloc());
|
MKXPZ_THROW(std::bad_alloc());
|
||||||
}
|
}
|
||||||
|
@ -230,8 +230,7 @@ wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr, void (
|
||||||
assert(object.typenum == 0);
|
assert(object.typenum == 0);
|
||||||
next_free_objkey = object.inner.next;
|
next_free_objkey = object.inner.next;
|
||||||
object.typenum = typenum;
|
object.typenum = typenum;
|
||||||
object.inner.inner.ptr = ptr;
|
object.inner.ptr = ptr;
|
||||||
object.inner.inner.destructor = destructor;
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,10 +240,10 @@ void *binding_base::get_object(wasm_objkey_t key) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
struct object &object = objects[key - 1];
|
struct object &object = objects[key - 1];
|
||||||
if (object.typenum == 0) {
|
if (object.typenum == 0 || object.typenum > typenum_table_size) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
return object.inner.inner.ptr;
|
return object.inner.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool binding_base::check_object_type(wasm_objkey_t key, wasm_size_t typenum) {
|
bool binding_base::check_object_type(wasm_objkey_t key, wasm_size_t typenum) {
|
||||||
|
@ -252,7 +251,7 @@ bool binding_base::check_object_type(wasm_objkey_t key, wasm_size_t typenum) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
struct object &object = objects[key - 1];
|
struct object &object = objects[key - 1];
|
||||||
if (object.typenum == 0) {
|
if (object.typenum == 0 || object.typenum > typenum_table_size) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
return object.typenum == typenum;
|
return object.typenum == typenum;
|
||||||
|
@ -263,11 +262,11 @@ void binding_base::destroy_object(wasm_objkey_t key) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
struct object &object = objects[key - 1];
|
struct object &object = objects[key - 1];
|
||||||
if (object.typenum == 0) {
|
if (object.typenum == 0 || object.typenum > typenum_table_size) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
typenum_table[object.typenum - 1].destructor(object.inner.ptr);
|
||||||
object.typenum = 0;
|
object.typenum = 0;
|
||||||
object.inner.inner.destructor(object.inner.inner.ptr);
|
|
||||||
object.inner.next = next_free_objkey;
|
object.inner.next = next_free_objkey;
|
||||||
next_free_objkey = key;
|
next_free_objkey = key;
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,6 +196,13 @@ namespace mkxp_sandbox {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct typenum_table_entry {
|
||||||
|
void (*destructor)(void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct typenum_table_entry typenum_table[];
|
||||||
|
extern const wasm_size_t typenum_table_size;
|
||||||
|
|
||||||
struct binding_base {
|
struct binding_base {
|
||||||
private:
|
private:
|
||||||
typedef std::tuple<wasm_ptr_t, wasm_ptr_t, wasm_ptr_t> key_t;
|
typedef std::tuple<wasm_ptr_t, wasm_ptr_t, wasm_ptr_t> key_t;
|
||||||
|
@ -223,16 +230,13 @@ namespace mkxp_sandbox {
|
||||||
// Otherwise, this is a number corresponding to the type of the object.
|
// Otherwise, this is a number corresponding to the type of the object.
|
||||||
wasm_size_t typenum;
|
wasm_size_t typenum;
|
||||||
// If this is a free object, the `next` field is the key of the next free object, or 0 if this is the last free object.
|
// If this is a free object, the `next` field is the key of the next free object, or 0 if this is the last free object.
|
||||||
// Otherwise, `inner.ptr` is a pointer to the actual object and `inner.destructor` is a pointer to its destructor.
|
// Otherwise, the `ptr` field is a pointer to the actual object.
|
||||||
union inner {
|
union inner {
|
||||||
struct {
|
|
||||||
void *ptr;
|
|
||||||
void (*destructor)(void *);
|
|
||||||
} inner;
|
|
||||||
wasm_size_t next;
|
wasm_size_t next;
|
||||||
|
void *ptr;
|
||||||
} inner;
|
} inner;
|
||||||
|
|
||||||
object(wasm_size_t typenum, void *ptr, void (*destructor)(void *));
|
object(wasm_size_t typenum, void *ptr);
|
||||||
object(const struct object &object) = delete;
|
object(const struct object &object) = delete;
|
||||||
object(struct object &&object) noexcept;
|
object(struct object &&object) noexcept;
|
||||||
struct object &operator=(const struct object &object) = delete;
|
struct object &operator=(const struct object &object) = delete;
|
||||||
|
@ -291,7 +295,7 @@ namespace mkxp_sandbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new object and returns its key.
|
// Creates a new object and returns its key.
|
||||||
wasm_objkey_t create_object(wasm_size_t typenum, void *ptr, void (*destructor)(void *));
|
wasm_objkey_t create_object(wasm_size_t typenum, void *ptr);
|
||||||
|
|
||||||
// Gets the object with the given key.
|
// Gets the object with the given key.
|
||||||
void *get_object(wasm_objkey_t key);
|
void *get_object(wasm_objkey_t key);
|
||||||
|
|
|
@ -24,6 +24,19 @@
|
||||||
|
|
||||||
using namespace mkxp_sandbox;
|
using namespace mkxp_sandbox;
|
||||||
|
|
||||||
|
template <typename T> static typename std::enable_if<std::is_destructible<T>::value>::type destructor(void *ptr) {
|
||||||
|
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public destructor");
|
||||||
|
delete (T *)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static typename std::enable_if<!std::is_destructible<T>::value>::type destructor(void *ptr) {
|
||||||
|
static_assert(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value, "this type should have a public destructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {.destructor = destructor<T>},
|
||||||
|
extern const struct typenum_table_entry mkxp_sandbox::typenum_table[SANDBOX_NUM_TYPENUMS] = {BOOST_PP_SEQ_FOR_EACH(_SANDBOX_DEF_TYPENUM_TABLE_ENTRY, _, SANDBOX_TYPENUM_TYPES)};
|
||||||
|
extern const wasm_size_t mkxp_sandbox::typenum_table_size = SANDBOX_NUM_TYPENUMS;
|
||||||
|
|
||||||
void mkxp_sandbox::dfree(wasm_objkey_t key) {
|
void mkxp_sandbox::dfree(wasm_objkey_t key) {
|
||||||
sb()->destroy_object(key);
|
sb()->destroy_object(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/preprocessor/seq/for_each.hpp>
|
||||||
|
#include <boost/preprocessor/seq/size.hpp>
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "sandbox.h"
|
#include "sandbox.h"
|
||||||
|
@ -455,27 +457,36 @@
|
||||||
#define SANDBOX_GUARD_LF(finalizer, ...) do { GFX_LOCK; SANDBOX_GUARD_F(finalizer; GFX_UNLOCK, __VA_ARGS__); GFX_UNLOCK; } while (0)
|
#define SANDBOX_GUARD_LF(finalizer, ...) do { GFX_LOCK; SANDBOX_GUARD_F(finalizer; GFX_UNLOCK, __VA_ARGS__); GFX_UNLOCK; } while (0)
|
||||||
#define SANDBOX_GUARD_L(...) SANDBOX_GUARD_LF(, __VA_ARGS__)
|
#define SANDBOX_GUARD_L(...) SANDBOX_GUARD_LF(, __VA_ARGS__)
|
||||||
|
|
||||||
#define _SANDBOX_DEF_TYPENUM(num, T) \
|
#define SANDBOX_TYPENUM_TYPES \
|
||||||
static_assert(num != 0, "typenum cannot be 0"); \
|
(Bitmap) \
|
||||||
template <> struct get_typenum<T> { static constexpr wasm_size_t value = num; };
|
(Color) \
|
||||||
|
(Font) \
|
||||||
|
(Plane) \
|
||||||
|
(Rect) \
|
||||||
|
(Sprite) \
|
||||||
|
(Table) \
|
||||||
|
(Tilemap) \
|
||||||
|
(Tilemap::Autotiles) \
|
||||||
|
(TilemapVX) \
|
||||||
|
(TilemapVX::BitmapArray) \
|
||||||
|
(Tone) \
|
||||||
|
(Viewport) \
|
||||||
|
(Window) \
|
||||||
|
(WindowVX) \
|
||||||
|
|
||||||
|
#define SANDBOX_NUM_TYPENUMS BOOST_PP_SEQ_SIZE(SANDBOX_TYPENUM_TYPES)
|
||||||
|
|
||||||
|
#define _SANDBOX_DEF_GET_TYPENUM_DETAIL(T, num) template <> struct get_typenum<T> { \
|
||||||
|
static_assert(num != 0, "typenum should not be 0"); \
|
||||||
|
static_assert(num <= SANDBOX_NUM_TYPENUMS, "typenum should not be greater than the number of typenums"); \
|
||||||
|
static constexpr wasm_size_t value = num; \
|
||||||
|
};
|
||||||
|
#define _SANDBOX_DEF_GET_TYPENUM(_r, _data, T) _SANDBOX_DEF_GET_TYPENUM_DETAIL(T, __COUNTER__ - _get_typenum_counter_start)
|
||||||
|
|
||||||
namespace mkxp_sandbox {
|
namespace mkxp_sandbox {
|
||||||
template <typename T> struct get_typenum;
|
template <typename T> struct get_typenum;
|
||||||
_SANDBOX_DEF_TYPENUM(1, Bitmap);
|
static constexpr size_t _get_typenum_counter_start = __COUNTER__;
|
||||||
_SANDBOX_DEF_TYPENUM(2, Color);
|
BOOST_PP_SEQ_FOR_EACH(_SANDBOX_DEF_GET_TYPENUM, _, SANDBOX_TYPENUM_TYPES);
|
||||||
_SANDBOX_DEF_TYPENUM(3, Font);
|
|
||||||
_SANDBOX_DEF_TYPENUM(4, Plane);
|
|
||||||
_SANDBOX_DEF_TYPENUM(5, Rect);
|
|
||||||
_SANDBOX_DEF_TYPENUM(6, Sprite);
|
|
||||||
_SANDBOX_DEF_TYPENUM(7, Table);
|
|
||||||
_SANDBOX_DEF_TYPENUM(8, Tilemap);
|
|
||||||
_SANDBOX_DEF_TYPENUM(9, Tilemap::Autotiles);
|
|
||||||
_SANDBOX_DEF_TYPENUM(10, TilemapVX);
|
|
||||||
_SANDBOX_DEF_TYPENUM(11, TilemapVX::BitmapArray);
|
|
||||||
_SANDBOX_DEF_TYPENUM(12, Tone);
|
|
||||||
_SANDBOX_DEF_TYPENUM(13, Viewport);
|
|
||||||
_SANDBOX_DEF_TYPENUM(14, Window);
|
|
||||||
_SANDBOX_DEF_TYPENUM(15, WindowVX);
|
|
||||||
|
|
||||||
// We need these helper functions so that the arguments to `SANDBOX_AWAIT`/`SANDBOX_AWAIT_R`/`SANDBOX_AWAIT_S` are evaluated before `sb()->bind` is called instead of after.
|
// We need these helper functions so that the arguments to `SANDBOX_AWAIT`/`SANDBOX_AWAIT_R`/`SANDBOX_AWAIT_S` are evaluated before `sb()->bind` is called instead of after.
|
||||||
// The reverse happening can lead to incorrect behaviour if one or more of the arguments is using `SANDBOX_SLOT` or other macros that need the state of the sandbox.
|
// The reverse happening can lead to incorrect behaviour if one or more of the arguments is using `SANDBOX_SLOT` or other macros that need the state of the sandbox.
|
||||||
|
@ -495,15 +506,6 @@ namespace mkxp_sandbox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> typename std::enable_if<std::is_destructible<T>::value>::type _set_private_data_destructor(void *ptr) {
|
|
||||||
static_assert(!(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value), "this type should not have a public destructor");
|
|
||||||
delete (T *)ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> typename std::enable_if<!std::is_destructible<T>::value>::type _set_private_data_destructor(void *ptr) {
|
|
||||||
static_assert(std::is_same<T, Tilemap::Autotiles>::value || std::is_same<T, TilemapVX::BitmapArray>::value, "this type should have a public destructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a Ruby object `val`, stores the C++ object `ptr` into the private data field of `val`.
|
// Given a Ruby object `val`, stores the C++ object `ptr` into the private data field of `val`.
|
||||||
// You can set `ptr` to `nullptr` if you just want to destroy the current object in the private data field,
|
// You can set `ptr` to `nullptr` if you just want to destroy the current object in the private data field,
|
||||||
// but note that calling `get_private_data` while the private data field is set to `nullptr` will trigger an abort.
|
// but note that calling `get_private_data` while the private data field is set to `nullptr` will trigger an abort.
|
||||||
|
@ -521,7 +523,7 @@ namespace mkxp_sandbox {
|
||||||
sb()->destroy_object(key);
|
sb()->destroy_object(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
key = ptr == nullptr ? 0 : sb()->create_object(get_typenum<T>::value, ptr, _set_private_data_destructor<T>);
|
key = ptr == nullptr ? 0 : sb()->create_object(get_typenum<T>::value, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a Ruby object `val`, retrieves the C++ object in its private data field.
|
// Given a Ruby object `val`, retrieves the C++ object in its private data field.
|
||||||
|
@ -587,6 +589,4 @@ namespace mkxp_sandbox {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef _SANDBOX_DEF_TYPENUM
|
|
||||||
|
|
||||||
#endif // MKXPZ_SANDBOX_BINDING_UTIL_H
|
#endif // MKXPZ_SANDBOX_BINDING_UTIL_H
|
||||||
|
|
|
@ -33,6 +33,7 @@ if is_libretro
|
||||||
subproject('boost_asio').get_variable('boost_asio'),
|
subproject('boost_asio').get_variable('boost_asio'),
|
||||||
subproject('boost_container_hash').get_variable('boost_container_hash'),
|
subproject('boost_container_hash').get_variable('boost_container_hash'),
|
||||||
subproject('boost_optional').get_variable('boost_optional'),
|
subproject('boost_optional').get_variable('boost_optional'),
|
||||||
|
subproject('boost_preprocessor').get_variable('boost_preprocessor'),
|
||||||
subproject('boost_type_traits').get_variable('boost_type_traits'),
|
subproject('boost_type_traits').get_variable('boost_type_traits'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
5
subprojects/boost_preprocessor.wrap
Normal file
5
subprojects/boost_preprocessor.wrap
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/boostorg/preprocessor
|
||||||
|
revision = boost-1.87.0
|
||||||
|
depth = 1
|
||||||
|
patch_directory = boost_preprocessor
|
4
subprojects/packagefiles/boost_preprocessor/meson.build
Normal file
4
subprojects/packagefiles/boost_preprocessor/meson.build
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
project('boost_preprocessor', 'cpp', meson_version: '>=1.3.0')
|
||||||
|
boost_preprocessor = declare_dependency(
|
||||||
|
include_directories: 'include',
|
||||||
|
)
|
Loading…
Add table
Reference in a new issue