diff --git a/binding-sandbox/binding-base.cpp b/binding-sandbox/binding-base.cpp index 82b25e5b..01428af1 100644 --- a/binding-sandbox/binding-base.cpp +++ b/binding-sandbox/binding-base.cpp @@ -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; } diff --git a/binding-sandbox/binding-base.h b/binding-sandbox/binding-base.h index 98d9bb75..dfcd8229 100644 --- a/binding-sandbox/binding-base.h +++ b/binding-sandbox/binding-base.h @@ -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 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); diff --git a/binding-sandbox/binding-util.cpp b/binding-sandbox/binding-util.cpp index 9913bd02..31d5b4db 100644 --- a/binding-sandbox/binding-util.cpp +++ b/binding-sandbox/binding-util.cpp @@ -24,6 +24,19 @@ using namespace mkxp_sandbox; +template static typename std::enable_if::value>::type destructor(void *ptr) { + static_assert(!(std::is_same::value || std::is_same::value), "this type should not have a public destructor"); + delete (T *)ptr; +} + +template static typename std::enable_if::value>::type destructor(void *ptr) { + static_assert(std::is_same::value || std::is_same::value, "this type should have a public destructor"); +} + +#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {.destructor = destructor}, +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); } diff --git a/binding-sandbox/binding-util.h b/binding-sandbox/binding-util.h index 5b206121..29bde544 100644 --- a/binding-sandbox/binding-util.h +++ b/binding-sandbox/binding-util.h @@ -24,6 +24,8 @@ #include #include +#include +#include #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 { 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 { \ + 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 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 std::enable_if::value>::type _set_private_data_destructor(void *ptr) { - static_assert(!(std::is_same::value || std::is_same::value), "this type should not have a public destructor"); - delete (T *)ptr; - } - - template typename std::enable_if::value>::type _set_private_data_destructor(void *ptr) { - static_assert(std::is_same::value || std::is_same::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::value, ptr, _set_private_data_destructor); + key = ptr == nullptr ? 0 : sb()->create_object(get_typenum::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 diff --git a/src/meson.build b/src/meson.build index 85cef143..f129d798 100755 --- a/src/meson.build +++ b/src/meson.build @@ -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'), ] diff --git a/subprojects/boost_preprocessor.wrap b/subprojects/boost_preprocessor.wrap new file mode 100644 index 00000000..244ded9c --- /dev/null +++ b/subprojects/boost_preprocessor.wrap @@ -0,0 +1,5 @@ +[wrap-git] +url = https://github.com/boostorg/preprocessor +revision = boost-1.87.0 +depth = 1 +patch_directory = boost_preprocessor diff --git a/subprojects/packagefiles/boost_preprocessor/meson.build b/subprojects/packagefiles/boost_preprocessor/meson.build new file mode 100644 index 00000000..5e22014e --- /dev/null +++ b/subprojects/packagefiles/boost_preprocessor/meson.build @@ -0,0 +1,4 @@ +project('boost_preprocessor', 'cpp', meson_version: '>=1.3.0') +boost_preprocessor = declare_dependency( + include_directories: 'include', +)