mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-26 20:31:41 +00:00
Add guest_stack_var, improve shared_ptr implementation.
This commit is contained in:
parent
588b5677eb
commit
3c2922a583
4 changed files with 232 additions and 34 deletions
|
|
@ -5,35 +5,117 @@
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
class sp_counted_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
struct vftable_t
|
||||||
|
{
|
||||||
|
be<uint32_t> destructor;
|
||||||
|
be<uint32_t> dispose;
|
||||||
|
be<uint32_t> destroy;
|
||||||
|
be<uint32_t> get_deleter;
|
||||||
|
};
|
||||||
|
|
||||||
|
xpointer<vftable_t> vftable_;
|
||||||
|
be<uint32_t> use_count_;
|
||||||
|
be<uint32_t> weak_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// TODO
|
||||||
|
sp_counted_base() = delete;
|
||||||
|
|
||||||
|
void add_ref()
|
||||||
|
{
|
||||||
|
be<uint32_t> original, incremented;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
original = use_count_;
|
||||||
|
incremented = original + 1;
|
||||||
|
} while (InterlockedCompareExchange((unsigned long*)&use_count_, incremented.value, original.value) != original.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
be<uint32_t> 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<void>(vftable_->dispose, this);
|
||||||
|
weak_release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void weak_release()
|
||||||
|
{
|
||||||
|
be<uint32_t> 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<void>(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<typename T>
|
template<typename T>
|
||||||
class shared_ptr
|
class shared_ptr
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
xpointer<T> m_pObject;
|
xpointer<T> px;
|
||||||
xpointer<uint32_t> m_pRefCount;
|
xpointer<boost::detail::sp_counted_base> pn;
|
||||||
|
|
||||||
|
void add_ref()
|
||||||
|
{
|
||||||
|
if (pn)
|
||||||
|
pn->add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
void release()
|
void release()
|
||||||
{
|
{
|
||||||
if (m_pRefCount && --(*m_pRefCount) == 0)
|
if (pn)
|
||||||
{
|
pn->release();
|
||||||
delete m_pObject;
|
|
||||||
delete m_pRefCount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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)
|
add_ref();
|
||||||
++(*m_pRefCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr(shared_ptr&& other) noexcept : m_pObject(std::exchange(other.m_pObject, nullptr)),
|
shared_ptr(shared_ptr&& other) noexcept : px(std::exchange(other.px, nullptr)),
|
||||||
m_pRefCount(std::exchange(other.m_pRefCount, nullptr)) {}
|
pn(std::exchange(other.pn, nullptr)) {}
|
||||||
|
|
||||||
~shared_ptr()
|
~shared_ptr()
|
||||||
{
|
{
|
||||||
|
|
@ -46,11 +128,10 @@ namespace boost
|
||||||
{
|
{
|
||||||
release();
|
release();
|
||||||
|
|
||||||
m_pObject = other.m_pObject;
|
px = other.px;
|
||||||
m_pRefCount = other.m_pRefCount;
|
pn = other.pn;
|
||||||
|
|
||||||
if (m_pRefCount)
|
add_ref();
|
||||||
++(*m_pRefCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -62,20 +143,22 @@ namespace boost
|
||||||
{
|
{
|
||||||
release();
|
release();
|
||||||
|
|
||||||
m_pObject = std::exchange(other.m_pObject, nullptr);
|
px = std::exchange(other.px, nullptr);
|
||||||
m_pRefCount = std::exchange(other.m_pRefCount, nullptr);
|
pn = std::exchange(other.pn, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* get() const { return m_pObject; }
|
T* get() const { return px; }
|
||||||
|
|
||||||
T& operator*() const { assert(m_pObject); return *m_pObject; }
|
detail::sp_dereference<T> operator*() const { assert(px); return *px; }
|
||||||
T* operator->() const { assert(m_pObject); return m_pObject; }
|
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<void>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
117
UnleashedRecomp/cpu/guest_stack_var.h
Normal file
117
UnleashedRecomp/cpu/guest_stack_var.h
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ppc_context.h"
|
||||||
|
#include <kernel/memory.h>
|
||||||
|
|
||||||
|
// 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<typename T>
|
||||||
|
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<uint32_t>(alignof(T), 8) - 1);
|
||||||
|
ctx->r1.u32 = m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
T* get()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(g_memory.Translate(m_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* get() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const T*>(g_memory.Translate(m_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
guest_stack_var(Args&&... args)
|
||||||
|
{
|
||||||
|
AllocGuestStackMemory();
|
||||||
|
new (get()) T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
guest_stack_var(const guest_stack_var<T>& other)
|
||||||
|
{
|
||||||
|
AllocGuestStackMemory();
|
||||||
|
new (get()) T(*other->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
guest_stack_var(guest_stack_var<T>&& 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<T>& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
*get() = *other->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(guest_stack_var<T>&& 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,25 +1,23 @@
|
||||||
#include <kernel/function.h>
|
#include <kernel/function.h>
|
||||||
#include <kernel/heap.h>
|
#include <kernel/heap.h>
|
||||||
#include <kernel/memory.h>
|
#include <kernel/memory.h>
|
||||||
|
#include <cpu/guest_stack_var.h>
|
||||||
#include <ui/window.h>
|
#include <ui/window.h>
|
||||||
|
#include <api/boost/smart_ptr/shared_ptr.h>
|
||||||
|
|
||||||
SWA_API void Game_PlaySound(const char* pName)
|
SWA_API void Game_PlaySound(const char* pName)
|
||||||
{
|
{
|
||||||
void* soundPlayerSharedPtr = g_userHeap.Alloc(8);
|
guest_stack_var<boost::anonymous_shared_ptr> soundPlayer;
|
||||||
GuestToHostFunction<void>(sub_82B4DF50, soundPlayerSharedPtr, ((be<uint32_t>*)g_memory.Translate(0x83367900))->get(), 7, 0, 0);
|
GuestToHostFunction<void>(sub_82B4DF50, soundPlayer.get(), ((be<uint32_t>*)g_memory.Translate(0x83367900))->get(), 7, 0, 0);
|
||||||
|
|
||||||
auto soundPlayer = (be<uint32_t>*)g_memory.Translate(*(be<uint32_t>*)soundPlayerSharedPtr);
|
auto soundPlayerVtable = (be<uint32_t>*)g_memory.Translate(*(be<uint32_t>*)soundPlayer->get());
|
||||||
auto soundPlayerVtable = (be<uint32_t>*)g_memory.Translate(*soundPlayer);
|
|
||||||
uint32_t virtualFunction = *(soundPlayerVtable + 1);
|
uint32_t virtualFunction = *(soundPlayerVtable + 1);
|
||||||
|
|
||||||
size_t strLen = strlen(pName);
|
size_t strLen = strlen(pName);
|
||||||
void* strAllocation = g_userHeap.Alloc(strLen + 1);
|
void* strAllocation = g_userHeap.Alloc(strLen + 1);
|
||||||
memcpy(strAllocation, pName, strLen + 1);
|
memcpy(strAllocation, pName, strLen + 1);
|
||||||
GuestToHostFunction<void>(virtualFunction, soundPlayer, strAllocation, 0);
|
GuestToHostFunction<void>(virtualFunction, soundPlayer->get(), strAllocation, 0);
|
||||||
g_userHeap.Free(strAllocation);
|
g_userHeap.Free(strAllocation);
|
||||||
|
|
||||||
GuestToHostFunction<void>(sub_822C0890, *((be<uint32_t>*)soundPlayerSharedPtr + 1));
|
|
||||||
g_userHeap.Free(soundPlayerSharedPtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SWA_API void Window_SetFullscreen(bool isEnabled)
|
SWA_API void Window_SetFullscreen(bool isEnabled)
|
||||||
|
|
|
||||||
|
|
@ -306,8 +306,8 @@ FORCEINLINE T GuestToHostFunction(const TFunction& func, TArgs... argv)
|
||||||
{
|
{
|
||||||
auto args = std::make_tuple(argv...);
|
auto args = std::make_tuple(argv...);
|
||||||
auto& currentCtx = *GetPPCContext();
|
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.fn = currentCtx.fn;
|
||||||
newCtx.r1 = currentCtx.r1;
|
newCtx.r1 = currentCtx.r1;
|
||||||
newCtx.r13 = currentCtx.r13;
|
newCtx.r13 = currentCtx.r13;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue