Skip to content

Commit 4e7eae2

Browse files
author
RunnerScrab
committed
Reimplement Object::IncRef(), Object::DecRef(), Object::GetHandle()
1 parent a2fecf4 commit 4e7eae2

3 files changed

Lines changed: 142 additions & 17 deletions

File tree

include/RE/H/HandlePolicy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace RE::GameScript
2626
std::size_t GetHandleScriptsMovedFrom(std::size_t a_newHandle) const override; // 0A
2727
std::size_t GetSaveRemappedHandle(std::size_t a_saveHandle) const override; // 0B
2828
void* GetObjectForHandle(std::uint32_t a_type, std::size_t a_handle) const override; // 0C
29-
void PersistHandle(std::size_t a_handle) override; // 0D
29+
void PersistHandle(std::size_t a_handle) override; // 0D
3030
void ReleaseHandle(std::size_t a_handle) override; // 0E
3131
void ConvertHandleToString(std::size_t a_handle, BSFixedString& a_string) const override; // 0F
3232

include/RE/IDs.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,9 @@ namespace RE::ID
274274

275275
namespace Object
276276
{
277-
inline constexpr REL::ID ctor{ 0 }; // 196025
278-
inline constexpr REL::ID dtor{ 0 }; // 196032
279-
inline constexpr REL::ID GetHandle{ 0 }; // 196069
277+
inline constexpr REL::ID ctor{ 137778 }; // 196025
278+
inline constexpr REL::ID dtor{ 0 }; // 196032 - inlined
279+
inline constexpr REL::ID GetHandle{ 0 }; // 196069 - inlined
280280
inline constexpr REL::ID SetHandle{ 0 }; // 196079
281281
inline constexpr REL::ID IncRef{ 0 }; // 37879
282282
inline constexpr REL::ID DecRef{ 0 }; // 196057

include/RE/O/Object.h

Lines changed: 138 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,150 @@ namespace RE::BSScript
4444
[[nodiscard]] constexpr bool IsInitialized() const noexcept { return static_cast<bool>(initialized); }
4545
[[nodiscard]] constexpr bool IsValid() const noexcept { return static_cast<bool>(valid); }
4646

47-
[[nodiscard]] std::uint32_t DecRef() const
47+
[[nodiscard]] std::uint32_t DecRef()
4848
{
49-
using func_t = decltype(&Object::DecRef);
50-
static REL::Relocation<func_t> func{ ID::BSScript::Object::DecRef };
51-
return func(this);
49+
std::int32_t iVar1;
50+
std::uint32_t uVar2;
51+
bool bVar3;
52+
53+
uVar2 = 0;
54+
do
55+
{
56+
while (true)
57+
{
58+
while (iVar1 = this->refCountAndHandleLock, iVar1 < 0)
59+
{
60+
if (uVar2 == 0)
61+
{
62+
_mm_pause();
63+
uVar2 = 1;
64+
}
65+
else
66+
{
67+
bVar3 = 9999 < uVar2;
68+
if (!bVar3)
69+
{
70+
uVar2 = uVar2 + 1;
71+
}
72+
REX::W32::Sleep(static_cast<unsigned int>(bVar3));
73+
}
74+
}
75+
76+
if (iVar1 != 2)
77+
break;
78+
79+
bVar3 = _InterlockedCompareExchange(reinterpret_cast<volatile long*>(&(this->refCountAndHandleLock)),
80+
-0x7ffffffe, 2) == 2;
81+
if (bVar3)
82+
{
83+
_mm_mfence();
84+
this->handlePolicy->ReleaseHandle(this->handle);
85+
_mm_mfence();
86+
this->refCountAndHandleLock = 1;
87+
return 1;
88+
}
89+
}
90+
bVar3 = _InterlockedCompareExchange(reinterpret_cast<volatile long*>(&(this->refCountAndHandleLock)),
91+
iVar1 - 1, iVar1) == iVar1;
92+
93+
} while (!bVar3);
94+
return iVar1 - 1;
5295
}
5396

54-
[[nodiscard]] std::size_t GetHandle() const
97+
[[nodiscard]] std::size_t GetHandle()
5598
{
56-
using func_t = decltype(&Object::GetHandle);
57-
static REL::Relocation<func_t> func{ ID::BSScript::Object::GetHandle };
58-
return func(this);
99+
std::uint32_t uVar1;
100+
std::uint32_t uVar2;
101+
bool bVar3;
102+
//The hexadecimal numbers next to the member functions in
103+
// IObjectHandlePolicy are vtable indices, NOT byte offsets
104+
this->handlePolicy->EmptyHandle();
105+
uVar2 = 0;
106+
do {
107+
while (uVar1 = this->refCountAndHandleLock, (int) uVar1 < 0) {
108+
if (uVar2 == 0)
109+
{
110+
_mm_pause();
111+
uVar2 = 1;
112+
}
113+
else
114+
{
115+
bVar3 = 9999 < uVar2;
116+
if (!bVar3) {
117+
uVar2 = uVar2 + 1;
118+
}
119+
REX::W32::Sleep(static_cast<std::uint32_t>(bVar3));
120+
}
121+
}
122+
123+
bVar3 = _InterlockedCompareExchange(reinterpret_cast<volatile long*>(&(this->refCountAndHandleLock)),
124+
uVar1 | 0x80000000, uVar1) == uVar1;
125+
126+
} while (!bVar3);
127+
_mm_mfence();
128+
this->refCountAndHandleLock = uVar1;
129+
_mm_mfence();
130+
return this->handle;
59131
}
60132

61-
void IncRef() const
133+
void IncRef()
62134
{
63-
using func_t = decltype(&Object::IncRef);
64-
static REL::Relocation<func_t> func{ ID::BSScript::Object::IncRef };
65-
return func(this);
135+
std::uint32_t uVar1;
136+
std::uint32_t uVar2;
137+
std::uint64_t uVar3;
138+
std::uint32_t uVar4;
139+
bool bVar5;
140+
141+
uVar4 = 0;
142+
do
143+
{
144+
while (true)
145+
{
146+
_mm_mfence();
147+
while (uVar2 = this->refCountAndHandleLock, (int)uVar2 < 0)
148+
{
149+
if (uVar4 == 0)
150+
{
151+
_mm_pause();
152+
uVar4 = 1;
153+
}
154+
else
155+
{
156+
bVar5 = 9999 < uVar4;
157+
if (!bVar5)
158+
{
159+
uVar4 = uVar4 + 1;
160+
}
161+
REX::W32::Sleep(static_cast<std::uint32_t>(bVar5));
162+
}
163+
}
164+
if (uVar2 != 1)
165+
break;
166+
167+
bVar5 = _InterlockedCompareExchange(reinterpret_cast<volatile long*>(&(this->refCountAndHandleLock)),
168+
-0x7fffffff, 1) == 1;
169+
if (bVar5)
170+
{
171+
_mm_mfence();
172+
this->handlePolicy->PersistHandle(this->handle);
173+
_mm_mfence();
174+
this->refCountAndHandleLock = 2;
175+
return;
176+
}
177+
}
178+
179+
bVar5 = _InterlockedCompareExchange(reinterpret_cast<volatile long*>(&(this->refCountAndHandleLock)),
180+
uVar2 + 1, uVar2) == uVar2;
181+
if (bVar5)
182+
{
183+
uVar1 = uVar2;
184+
return;
185+
}
186+
187+
} while (!bVar5);
188+
189+
this->refCountAndHandleLock = uVar1;
190+
return;
66191
}
67192

68193
SF_HEAP_REDEFINE_NEW();
@@ -84,7 +209,7 @@ namespace RE::BSScript
84209
void* lockStructure; // 30
85210
IObjectHandlePolicy* handlePolicy; // 38
86211
std::size_t handle; // 40
87-
std::uint32_t refCountAndHandleLock; // 48
212+
volatile std::uint32_t refCountAndHandleLock; // 48
88213
};
89214
static_assert(sizeof(Object) == 0x50);
90215
}

0 commit comments

Comments
 (0)