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);
|
||||
}
|
||||
|
||||
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})) {}
|
||||
|
||||
|
@ -210,16 +210,16 @@ struct binding_base::object &binding_base::object::operator=(struct object &&obj
|
|||
|
||||
binding_base::object::~object() {
|
||||
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 *)) {
|
||||
if (typenum == 0 || ptr == nullptr || destructor == nullptr) {
|
||||
wasm_objkey_t binding_base::create_object(wasm_size_t typenum, void *ptr) {
|
||||
if (ptr == nullptr || typenum == 0 || typenum > typenum_table_size) {
|
||||
std::abort();
|
||||
}
|
||||
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()) {
|
||||
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);
|
||||
next_free_objkey = object.inner.next;
|
||||
object.typenum = typenum;
|
||||
object.inner.inner.ptr = ptr;
|
||||
object.inner.inner.destructor = destructor;
|
||||
object.inner.ptr = ptr;
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
@ -241,10 +240,10 @@ void *binding_base::get_object(wasm_objkey_t key) {
|
|||
std::abort();
|
||||
}
|
||||
struct object &object = objects[key - 1];
|
||||
if (object.typenum == 0) {
|
||||
if (object.typenum == 0 || object.typenum > typenum_table_size) {
|
||||
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) {
|
||||
|
@ -252,7 +251,7 @@ bool binding_base::check_object_type(wasm_objkey_t key, wasm_size_t typenum) {
|
|||
std::abort();
|
||||
}
|
||||
struct object &object = objects[key - 1];
|
||||
if (object.typenum == 0) {
|
||||
if (object.typenum == 0 || object.typenum > typenum_table_size) {
|
||||
std::abort();
|
||||
}
|
||||
return object.typenum == typenum;
|
||||
|
@ -263,11 +262,11 @@ void binding_base::destroy_object(wasm_objkey_t key) {
|
|||
std::abort();
|
||||
}
|
||||
struct object &object = objects[key - 1];
|
||||
if (object.typenum == 0) {
|
||||
if (object.typenum == 0 || object.typenum > typenum_table_size) {
|
||||
std::abort();
|
||||
}
|
||||
typenum_table[object.typenum - 1].destructor(object.inner.ptr);
|
||||
object.typenum = 0;
|
||||
object.inner.inner.destructor(object.inner.inner.ptr);
|
||||
object.inner.next = next_free_objkey;
|
||||
next_free_objkey = key;
|
||||
}
|
||||
|
|
|
@ -196,6 +196,13 @@ namespace mkxp_sandbox {
|
|||
#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 {
|
||||
private:
|
||||
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.
|
||||
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.
|
||||
// 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 {
|
||||
struct {
|
||||
void *ptr;
|
||||
void (*destructor)(void *);
|
||||
} inner;
|
||||
wasm_size_t next;
|
||||
void *ptr;
|
||||
} 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(struct object &&object) noexcept;
|
||||
struct object &operator=(const struct object &object) = delete;
|
||||
|
@ -291,7 +295,7 @@ namespace mkxp_sandbox {
|
|||
}
|
||||
|
||||
// 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.
|
||||
void *get_object(wasm_objkey_t key);
|
||||
|
|
|
@ -24,6 +24,19 @@
|
|||
|
||||
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) {
|
||||
sb()->destroy_object(key);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <type_traits>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include "core.h"
|
||||
#include "exception.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_L(...) SANDBOX_GUARD_LF(, __VA_ARGS__)
|
||||
|
||||
#define _SANDBOX_DEF_TYPENUM(num, T) \
|
||||
static_assert(num != 0, "typenum cannot be 0"); \
|
||||
template <> struct get_typenum<T> { static constexpr wasm_size_t value = num; };
|
||||
#define SANDBOX_TYPENUM_TYPES \
|
||||
(Bitmap) \
|
||||
(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 {
|
||||
template <typename T> struct get_typenum;
|
||||
_SANDBOX_DEF_TYPENUM(1, Bitmap);
|
||||
_SANDBOX_DEF_TYPENUM(2, Color);
|
||||
_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);
|
||||
static constexpr size_t _get_typenum_counter_start = __COUNTER__;
|
||||
BOOST_PP_SEQ_FOR_EACH(_SANDBOX_DEF_GET_TYPENUM, _, SANDBOX_TYPENUM_TYPES);
|
||||
|
||||
// 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.
|
||||
|
@ -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`.
|
||||
// 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.
|
||||
|
@ -521,7 +523,7 @@ namespace mkxp_sandbox {
|
|||
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.
|
||||
|
@ -587,6 +589,4 @@ namespace mkxp_sandbox {
|
|||
};
|
||||
}
|
||||
|
||||
#undef _SANDBOX_DEF_TYPENUM
|
||||
|
||||
#endif // MKXPZ_SANDBOX_BINDING_UTIL_H
|
||||
|
|
|
@ -33,6 +33,7 @@ if is_libretro
|
|||
subproject('boost_asio').get_variable('boost_asio'),
|
||||
subproject('boost_container_hash').get_variable('boost_container_hash'),
|
||||
subproject('boost_optional').get_variable('boost_optional'),
|
||||
subproject('boost_preprocessor').get_variable('boost_preprocessor'),
|
||||
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