Skip to content
This repository was archived by the owner on Jul 3, 2025. It is now read-only.

Commit 3bae3cb

Browse files
Convert the ID cache to use object handles
1 parent 282aca6 commit 3bae3cb

File tree

1 file changed

+76
-73
lines changed

1 file changed

+76
-73
lines changed

engine/src/stackcache.cpp

Lines changed: 76 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,23 @@ class MCStackIdCache
3636
MCStackIdCache(void);
3737
~MCStackIdCache(void);
3838

39-
void CacheObject(MCObject *object);
40-
void UncacheObject(MCObject *object);
41-
MCObject *FindObject(uint32_t id);
39+
void CacheObject(MCObjectHandle object);
40+
void UncacheObject(MCObjectHandle object);
41+
MCObjectHandle FindObject(uint32_t id);
4242

4343
bool RehashBuckets(index_t p_new_count_delta);
4444

4545
private:
4646
static hash_t HashId(uint32_t id);
4747

48-
uindex_t FindBucket(uint32_t id, hash_t hash);
49-
uindex_t FindBucketIfExists(uint32_t id, hash_t hash);
48+
uindex_t FindBucket(uint32_t id, hash_t hash, bool p_only_if_exists = false);
5049
uindex_t FindBucketAfterRehash(uint32_t id, hash_t hash);
5150

51+
inline uindex_t FindBucketIfExists(uint32_t id, hash_t hash)
52+
{
53+
return FindBucket(id, hash, true);
54+
}
55+
5256
uindex_t m_capacity_idx;
5357
uindex_t m_count;
5458
uintptr_t *m_buckets;
@@ -106,10 +110,21 @@ MCStackIdCache::MCStackIdCache(void)
106110

107111
MCStackIdCache::~MCStackIdCache(void)
108112
{
109-
MCMemoryDeleteArray(m_buckets);
113+
// Clear all handles from the array
114+
for (uindex_t i = 0; i < __kMCValueHashTableSizes[m_capacity_idx]; i++)
115+
{
116+
uintptr_t t_bucket = m_buckets[i];
117+
if (t_bucket == UINTPTR_MIN || t_bucket == UINTPTR_MAX)
118+
continue;
119+
120+
MCObjectHandle t_handle = reinterpret_cast<MCObjectProxy<MCObject>*>(m_buckets[i]);
121+
t_handle.ExternalRelease();
122+
}
123+
124+
MCMemoryDeleteArray(m_buckets);
110125
}
111126

112-
void MCStackIdCache::CacheObject(MCObject *p_object)
127+
void MCStackIdCache::CacheObject(MCObjectHandle p_object)
113128
{
114129
if (p_object -> getinidcache())
115130
return;
@@ -121,7 +136,7 @@ void MCStackIdCache::CacheObject(MCObject *p_object)
121136
t_hash = HashId(t_id);
122137

123138
uindex_t t_target_slot;
124-
t_target_slot = FindBucket(t_id, t_hash);
139+
t_target_slot = FindBucket(t_id, t_hash, false);
125140

126141
if (t_target_slot == UINDEX_MAX)
127142
{
@@ -135,11 +150,11 @@ void MCStackIdCache::CacheObject(MCObject *p_object)
135150
return;
136151

137152
p_object -> setinidcache(true);
138-
m_buckets[t_target_slot] = (uintptr_t)p_object;
153+
m_buckets[t_target_slot] = uintptr_t(p_object.ExternalRetain());
139154
m_count += 1;
140155
}
141156

142-
void MCStackIdCache::UncacheObject(MCObject *p_object)
157+
void MCStackIdCache::UncacheObject(MCObjectHandle p_object)
143158
{
144159
if (!p_object -> getinidcache())
145160
return;
@@ -155,13 +170,14 @@ void MCStackIdCache::UncacheObject(MCObject *p_object)
155170

156171
if (t_target_slot != UINDEX_MAX)
157172
{
158-
p_object -> setinidcache(false);
173+
p_object.ExternalRelease();
174+
p_object -> setinidcache(false);
159175
m_buckets[t_target_slot] = UINTPTR_MAX;
160176
m_count -= 1;
161177
}
162178
}
163179

164-
MCObject *MCStackIdCache::FindObject(uint32_t p_id)
180+
MCObjectHandle MCStackIdCache::FindObject(uint32_t p_id)
165181
{
166182
hash_t t_hash;
167183
t_hash = HashId(p_id);
@@ -170,7 +186,7 @@ MCObject *MCStackIdCache::FindObject(uint32_t p_id)
170186
t_target_slot = FindBucketIfExists(p_id, t_hash);
171187

172188
if (t_target_slot != UINDEX_MAX)
173-
return (MCObject *)m_buckets[t_target_slot];
189+
return reinterpret_cast<MCObjectProxy<MCObject>*>(m_buckets[t_target_slot]);
174190

175191
return nil;
176192
}
@@ -183,55 +199,7 @@ hash_t MCStackIdCache::HashId(uint32_t h)
183199
return h ^ (h >> 7) ^ (h >> 4);
184200
}
185201

186-
uindex_t MCStackIdCache::FindBucket(uint32_t p_id, hash_t p_hash)
187-
{
188-
uindex_t t_capacity;
189-
t_capacity = __kMCValueHashTableSizes[m_capacity_idx];
190-
191-
uindex_t t_h1;
192-
#if defined(__ARM__) && 0 // TODO
193-
t_h1 = __MCHashFold(p_hash, m_capacity_idx);
194-
#else
195-
t_h1 = p_hash % t_capacity;
196-
#endif
197-
198-
uindex_t t_probe;
199-
t_probe = t_h1;
200-
201-
uindex_t t_target_slot;
202-
t_target_slot = UINDEX_MAX;
203-
204-
for(uindex_t i = 0; i < t_capacity; i++)
205-
{
206-
uintptr_t t_bucket;
207-
t_bucket = m_buckets[t_probe];
208-
if (t_bucket == UINTPTR_MIN)
209-
{
210-
if (t_target_slot == UINDEX_MAX)
211-
t_target_slot = t_probe;
212-
break;
213-
}
214-
else if (t_bucket == UINTPTR_MAX)
215-
{
216-
if (t_target_slot == UINDEX_MAX)
217-
t_target_slot = t_probe;
218-
}
219-
else
220-
{
221-
if (p_id == ((MCObject *)t_bucket) -> getid())
222-
return t_probe;
223-
}
224-
225-
t_probe += 1;
226-
227-
if (t_capacity <= t_probe)
228-
t_probe -= t_capacity;
229-
}
230-
231-
return t_target_slot;
232-
}
233-
234-
uindex_t MCStackIdCache::FindBucketIfExists(uint32_t p_id, hash_t p_hash)
202+
uindex_t MCStackIdCache::FindBucket(uint32_t p_id, hash_t p_hash, bool p_only_if_exists)
235203
{
236204
uindex_t t_capacity;
237205
t_capacity = __kMCValueHashTableSizes[m_capacity_idx];
@@ -243,8 +211,8 @@ uindex_t MCStackIdCache::FindBucketIfExists(uint32_t p_id, hash_t p_hash)
243211
t_h1 = p_hash % t_capacity;
244212
#endif
245213

246-
uindex_t t_probe;
247-
t_probe = t_h1;
214+
uindex_t t_probe = t_h1;
215+
uindex_t t_candidate_slot = UINDEX_MAX;
248216

249217
for(uindex_t i = 0; i < t_capacity; i++)
250218
{
@@ -254,17 +222,41 @@ uindex_t MCStackIdCache::FindBucketIfExists(uint32_t p_id, hash_t p_hash)
254222
if (t_bucket == UINTPTR_MIN)
255223
return UINDEX_MAX;
256224

257-
if (t_bucket != UINTPTR_MAX &&
258-
((MCObject *)t_bucket) -> getid() == p_id)
259-
return t_probe;
225+
if (t_bucket != UINTPTR_MAX)
226+
{
227+
MCObjectHandle t_handle = reinterpret_cast<MCObjectProxy<MCObject>*>(t_bucket);
228+
229+
if (t_handle)
230+
{
231+
if (p_id == t_handle->getid())
232+
return t_probe;
233+
}
234+
else
235+
{
236+
// Object is dead, remove it from the cache
237+
t_handle.ExternalRelease();
238+
m_buckets[t_probe] = UINTPTR_MAX;
239+
m_count -= 1;
240+
}
241+
}
242+
else
243+
{
244+
// The entry could be placed here but we keep searching in case a
245+
// later entry already holds the same object.
246+
if (t_candidate_slot != UINDEX_MAX)
247+
t_candidate_slot = t_probe;
248+
}
260249

261250
t_probe += 1;
262251

263252
if (t_capacity <= t_probe)
264253
t_probe -= t_capacity;
265254
}
266255

267-
return UINDEX_MAX;
256+
// If we get here, the object was not found in the cache. Return an invalid
257+
// index if existance was required or a slot where it could be placed
258+
// otherwise.
259+
return p_only_if_exists ? UINDEX_MAX : t_candidate_slot;
268260
}
269261

270262
uindex_t MCStackIdCache::FindBucketAfterRehash(uint32_t p_id, hash_t p_hash)
@@ -344,9 +336,18 @@ bool MCStackIdCache::RehashBuckets(index_t p_new_item_count_delta)
344336
{
345337
if (t_old_buckets[i] != UINTPTR_MIN && t_old_buckets[i] != UINTPTR_MAX)
346338
{
347-
uint32_t t_id;
348-
t_id = ((MCObject *)t_old_buckets[i]) -> getid();
349-
339+
MCObjectHandle t_handle = reinterpret_cast<MCObjectProxy<MCObject>*>(t_old_buckets[i]);
340+
341+
// If the object is dead, don't transfer it to the new table
342+
if (!t_handle)
343+
{
344+
t_handle.ExternalRelease();
345+
m_count -= 1;
346+
continue;
347+
}
348+
349+
uint32_t t_id = t_handle->getid();
350+
350351
hash_t t_hash;
351352
t_hash = HashId(t_id);
352353

@@ -356,6 +357,8 @@ bool MCStackIdCache::RehashBuckets(index_t p_new_item_count_delta)
356357
// This assertion should never trigger - something is very wrong if it does!
357358
MCAssert(t_target_slot != UINDEX_MAX);
358359

360+
// No retain/release pair is done when moving the entries to the new
361+
// hash table as the ref count for each object doesn't change.
359362
m_buckets[t_target_slot] = t_old_buckets[i];
360363
}
361364
}
@@ -383,15 +386,15 @@ void MCStack::cacheobjectbyid(MCObject *p_object)
383386
}
384387

385388
if (m_id_cache != nil)
386-
m_id_cache -> CacheObject(p_object);
389+
m_id_cache -> CacheObject(p_object->GetHandle());
387390
}
388391

389392
void MCStack::uncacheobjectbyid(MCObject *p_object)
390393
{
391394
if (m_id_cache == nil)
392395
return;
393396

394-
m_id_cache -> UncacheObject(p_object);
397+
m_id_cache -> UncacheObject(p_object->GetHandle());
395398
}
396399

397400
MCObject *MCStack::findobjectbyid(uint32_t p_id)

0 commit comments

Comments
 (0)