From 1a275a18662600e0a65548c28fe348a54baeae86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Sun, 6 Jul 2025 11:08:44 -0400 Subject: [PATCH] Properly set `assumingRubyGC` when deserializing bitmaps from libretro save states --- binding-sandbox/binding-base.h | 2 +- binding-sandbox/sandbox-serial-util.cpp | 23 +++++++++++++++++++---- src/core.cpp | 4 ++-- src/display/bitmap.cpp | 11 ++++++++--- src/display/bitmap.h | 4 ++-- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/binding-sandbox/binding-base.h b/binding-sandbox/binding-base.h index 6a52e64a..4f2097d3 100644 --- a/binding-sandbox/binding-base.h +++ b/binding-sandbox/binding-base.h @@ -262,7 +262,7 @@ namespace mkxp_sandbox { bool (*serialize)(const void *self, void *&data, wasm_size_t &max_size); bool (*deserialize)(void *self, const void *&data, wasm_size_t &max_size); void (*deserialize_begin)(void *self, bool is_new); - void (*deserialize_end)(void *self); + void (*deserialize_end)(void *self, bool is_sandbox_object); void (*reinit)(void *self); }; diff --git a/binding-sandbox/sandbox-serial-util.cpp b/binding-sandbox/sandbox-serial-util.cpp index c0bec717..f184d45e 100644 --- a/binding-sandbox/sandbox-serial-util.cpp +++ b/binding-sandbox/sandbox-serial-util.cpp @@ -99,13 +99,18 @@ template static typename std::enable_if static typename std::enable_if::value && !boost::is_detected::value>::type deserialize_begin(void *self, bool is_new) {} -template using deserialize_end_declaration = decltype(std::declval()->sandbox_deserialize_end()); +template using deserialize_end_declaration_with_is_sandbox_object = decltype(std::declval()->sandbox_deserialize_end(std::declval())); +template using deserialize_end_declaration_without_is_sandbox_object = decltype(std::declval()->sandbox_deserialize_end()); -template static typename std::enable_if::value>::type deserialize_end(void *self) { +template static typename std::enable_if::value>::type deserialize_end(void *self, bool is_sandbox_object) { + ((T *)self)->sandbox_deserialize_end(is_sandbox_object); +} + +template static typename std::enable_if::value && boost::is_detected::value>::type deserialize_end(void *self, bool is_sandbox_object) { ((T *)self)->sandbox_deserialize_end(); } -template static typename std::enable_if::value>::type deserialize_end(void *self) {} +template static typename std::enable_if::value && !boost::is_detected::value>::type deserialize_end(void *self, bool is_sandbox_object) {} template using reinit_declaration = decltype(std::declval()->sandbox_reinit()); @@ -115,7 +120,17 @@ template static typename std::enable_if static typename std::enable_if::value>::type reinit(void *self) {} -#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) {construct, destroy, dispose, disposed, serialize, deserialize, deserialize_begin, deserialize_end, reinit}, +#define _SANDBOX_DEF_TYPENUM_TABLE_ENTRY(_r, _data, T) { \ + construct, \ + destroy, \ + dispose, \ + disposed, \ + serialize, \ + deserialize, \ + deserialize_begin, \ + deserialize_end, \ + reinit, \ +}, 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; diff --git a/src/core.cpp b/src/core.cpp index 23aad651..9c5e53d5 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -2062,11 +2062,11 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) { } if (sb().trans_map != nullptr) { - sb().trans_map->sandbox_deserialize_end(); + sb().trans_map->sandbox_deserialize_end(false); } for (const auto &object : sb()->objects) { if (object.typenum > 0) { - typenum_table[object.typenum - 1].deserialize_end(object.ptr); + typenum_table[object.typenum - 1].deserialize_end(object.ptr, true); } } sb()->vacant_object_keys = boost::container::priority_deque(std::less(), std::move(vacant_object_keys)); diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index f13e9382..611a040b 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -3634,9 +3634,9 @@ int Bitmap::maxSize(){ return glState.caps.maxTexSize; } -void Bitmap::assumeRubyGC() +void Bitmap::assumeRubyGC(bool value) { - p->assumingRubyGC = true; + p->assumingRubyGC = value; } void Bitmap::releaseResources() @@ -4158,9 +4158,11 @@ void Bitmap::sandbox_deserialize_begin(bool is_new) deserModified = is_new; deserSizeChanged = is_new; + + assumeRubyGC(false); } -void Bitmap::sandbox_deserialize_end() +void Bitmap::sandbox_deserialize_end(bool is_sandbox_object) { if (isDisposed()) return; if (p->selfLores != nullptr) { @@ -4174,6 +4176,9 @@ void Bitmap::sandbox_deserialize_end() if ((p->selfHires != nullptr && p->selfHires->deserModified) || (p->selfLores != nullptr && p->selfLores->deserModified)) { deserModified = true; } + + if (isDisposed()) return; + assumeRubyGC(is_sandbox_object && p->selfHires != nullptr); } void Bitmap::sandbox_reinit() diff --git a/src/display/bitmap.h b/src/display/bitmap.h index db6a72d6..e7b64fd8 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -215,13 +215,13 @@ public: static int maxSize(); - void assumeRubyGC(); + void assumeRubyGC(bool value = true); #ifdef MKXPZ_RETRO bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); void sandbox_deserialize_begin(bool is_new); - void sandbox_deserialize_end(); + void sandbox_deserialize_end(bool is_sandbox_object); void sandbox_reinit(); #endif // MKXPZ_RETRO