diff --git a/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h b/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h index a5b9bb94..ecea043a 100644 --- a/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h +++ b/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h @@ -5,35 +5,117 @@ namespace boost { + namespace detail + { + class sp_counted_base + { + protected: + struct vftable_t + { + be destructor; + be dispose; + be destroy; + be get_deleter; + }; + + xpointer vftable_; + be use_count_; + be weak_count_; + + public: + // TODO + sp_counted_base() = delete; + + void add_ref() + { + be original, incremented; + do + { + original = use_count_; + incremented = original + 1; + } while (InterlockedCompareExchange((unsigned long*)&use_count_, incremented.value, original.value) != original.value); + } + + void release() + { + be original, decremented; + do + { + original = use_count_; + decremented = original - 1; + } while (InterlockedCompareExchange((unsigned long*)&use_count_, decremented.value, original.value) != original.value); + + if (decremented == 0) + { + GuestToHostFunction(vftable_->dispose, this); + weak_release(); + } + } + + void weak_release() + { + be original, decremented; + do + { + original = weak_count_; + decremented = original - 1; + } while (InterlockedCompareExchange((unsigned long*)&weak_count_, decremented.value, original.value) != original.value); + + if (decremented == 0) + { + GuestToHostFunction(vftable_->destroy, this); + } + } + + uint32_t use_count() const + { + return use_count_; + } + }; + + template< class T > struct sp_dereference + { + typedef T& type; + }; + + template<> struct sp_dereference< void > + { + typedef void type; + }; + } + template class shared_ptr { private: - xpointer m_pObject; - xpointer m_pRefCount; + xpointer px; + xpointer pn; + + void add_ref() + { + if (pn) + pn->add_ref(); + } void release() { - if (m_pRefCount && --(*m_pRefCount) == 0) - { - delete m_pObject; - delete m_pRefCount; - } + if (pn) + pn->release(); } public: - shared_ptr() : m_pObject(nullptr), m_pRefCount(nullptr) {} + shared_ptr() : px(nullptr), pn(nullptr) {} - explicit shared_ptr(T* p) : m_pObject(p), m_pRefCount(new uint32_t(1)) {} + // TODO + explicit shared_ptr(T* p) = delete; - shared_ptr(const shared_ptr& other) : m_pObject(other.m_pObject), m_pRefCount(other.m_pRefCount) + shared_ptr(const shared_ptr& other) : px(other.px), pn(other.pn) { - if (m_pRefCount) - ++(*m_pRefCount); + add_ref(); } - shared_ptr(shared_ptr&& other) noexcept : m_pObject(std::exchange(other.m_pObject, nullptr)), - m_pRefCount(std::exchange(other.m_pRefCount, nullptr)) {} + shared_ptr(shared_ptr&& other) noexcept : px(std::exchange(other.px, nullptr)), + pn(std::exchange(other.pn, nullptr)) {} ~shared_ptr() { @@ -46,11 +128,10 @@ namespace boost { release(); - m_pObject = other.m_pObject; - m_pRefCount = other.m_pRefCount; + px = other.px; + pn = other.pn; - if (m_pRefCount) - ++(*m_pRefCount); + add_ref(); } return *this; @@ -62,20 +143,22 @@ namespace boost { release(); - m_pObject = std::exchange(other.m_pObject, nullptr); - m_pRefCount = std::exchange(other.m_pRefCount, nullptr); + px = std::exchange(other.px, nullptr); + pn = std::exchange(other.pn, nullptr); } return *this; } - T* get() const { return m_pObject; } + T* get() const { return px; } - T& operator*() const { assert(m_pObject); return *m_pObject; } - T* operator->() const { assert(m_pObject); return m_pObject; } + detail::sp_dereference operator*() const { assert(px); return *px; } + T* operator->() const { assert(px); return px; } - explicit operator bool() const { return m_pObject != nullptr; } + explicit operator bool() const { return px != nullptr; } - size_t use_count() const { return m_pRefCount ? *m_pRefCount : 0; } + size_t use_count() const { return pn ? pn->use_count() : 0; } }; + + using anonymous_shared_ptr = shared_ptr; } diff --git a/UnleashedRecomp/cpu/guest_stack_var.h b/UnleashedRecomp/cpu/guest_stack_var.h new file mode 100644 index 00000000..541e3651 --- /dev/null +++ b/UnleashedRecomp/cpu/guest_stack_var.h @@ -0,0 +1,117 @@ +#pragma once + +#include "ppc_context.h" +#include + +// DO NOT use this type as anything other than a local variable. +// This includes returning. It'll cause memory to leak in the guest stack! + +template +class guest_stack_var +{ +private: + uint32_t m_ptr = NULL; + uint32_t m_oldStackPtr = NULL; + + void AllocGuestStackMemory() + { + auto ctx = GetPPCContext(); + m_oldStackPtr = ctx->r1.u32; + m_ptr = (ctx->r1.u32 - sizeof(T)) & ~(std::max(alignof(T), 8) - 1); + ctx->r1.u32 = m_ptr; + } + +public: + T* get() + { + return reinterpret_cast(g_memory.Translate(m_ptr)); + } + + const T* get() const + { + return reinterpret_cast(g_memory.Translate(m_ptr)); + } + + template + guest_stack_var(Args&&... args) + { + AllocGuestStackMemory(); + new (get()) T(std::forward(args)...); + } + + guest_stack_var(const guest_stack_var& other) + { + AllocGuestStackMemory(); + new (get()) T(*other->get()); + } + + guest_stack_var(guest_stack_var&& other) + { + AllocGuestStackMemory(); + new (get()) T(std::move(*other->get())); + } + + ~guest_stack_var() + { + get()->~T(); + + auto ctx = GetPPCContext(); + // This assert will fail if the type was used as anything other than a local variable. + assert(ctx->r1.u32 == m_ptr); + ctx->r1.u32 = m_oldStackPtr; + } + + void operator=(const guest_stack_var& other) + { + if (this != &other) + *get() = *other->get(); + } + + void operator=(guest_stack_var&& other) + { + if (this != &other) + *get() = std::move(*other->get()); + } + + void operator=(const T& other) + { + if (get() != &other) + *get() = *other; + } + + void operator=(T&& other) + { + if (get() != &other) + *get() = std::move(*other); + } + + operator const T* () const + { + return get(); + } + + operator T* () + { + return get(); + } + + const T* operator->() const + { + return get(); + } + + T* operator->() + { + return get(); + } + + const T& operator*() const + { + return *get(); + } + + T& operator*() + { + return *get(); + } +}; diff --git a/UnleashedRecomp/exports.cpp b/UnleashedRecomp/exports.cpp index c792646f..fbf01c7e 100644 --- a/UnleashedRecomp/exports.cpp +++ b/UnleashedRecomp/exports.cpp @@ -1,25 +1,23 @@ #include #include #include +#include #include +#include SWA_API void Game_PlaySound(const char* pName) { - void* soundPlayerSharedPtr = g_userHeap.Alloc(8); - GuestToHostFunction(sub_82B4DF50, soundPlayerSharedPtr, ((be*)g_memory.Translate(0x83367900))->get(), 7, 0, 0); + guest_stack_var soundPlayer; + GuestToHostFunction(sub_82B4DF50, soundPlayer.get(), ((be*)g_memory.Translate(0x83367900))->get(), 7, 0, 0); - auto soundPlayer = (be*)g_memory.Translate(*(be*)soundPlayerSharedPtr); - auto soundPlayerVtable = (be*)g_memory.Translate(*soundPlayer); + auto soundPlayerVtable = (be*)g_memory.Translate(*(be*)soundPlayer->get()); uint32_t virtualFunction = *(soundPlayerVtable + 1); size_t strLen = strlen(pName); void* strAllocation = g_userHeap.Alloc(strLen + 1); memcpy(strAllocation, pName, strLen + 1); - GuestToHostFunction(virtualFunction, soundPlayer, strAllocation, 0); + GuestToHostFunction(virtualFunction, soundPlayer->get(), strAllocation, 0); g_userHeap.Free(strAllocation); - - GuestToHostFunction(sub_822C0890, *((be*)soundPlayerSharedPtr + 1)); - g_userHeap.Free(soundPlayerSharedPtr); } SWA_API void Window_SetFullscreen(bool isEnabled) diff --git a/UnleashedRecomp/kernel/function.h b/UnleashedRecomp/kernel/function.h index 7c110fcc..e52e4ba9 100644 --- a/UnleashedRecomp/kernel/function.h +++ b/UnleashedRecomp/kernel/function.h @@ -306,8 +306,8 @@ FORCEINLINE T GuestToHostFunction(const TFunction& func, TArgs... argv) { auto args = std::make_tuple(argv...); auto& currentCtx = *GetPPCContext(); - auto newCtx = PPCContext{}; + PPCContext newCtx; // NOTE: No need for zero initialization, has lots of unnecessary code generation. newCtx.fn = currentCtx.fn; newCtx.r1 = currentCtx.r1; newCtx.r13 = currentCtx.r13;