@@ -36,19 +36,23 @@ class MCStackIdCache
36
36
MCStackIdCache (void );
37
37
~MCStackIdCache (void );
38
38
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);
42
42
43
43
bool RehashBuckets (index_t p_new_count_delta);
44
44
45
45
private:
46
46
static hash_t HashId (uint32_t id);
47
47
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 );
50
49
uindex_t FindBucketAfterRehash (uint32_t id, hash_t hash);
51
50
51
+ inline uindex_t FindBucketIfExists (uint32_t id, hash_t hash)
52
+ {
53
+ return FindBucket (id, hash, true );
54
+ }
55
+
52
56
uindex_t m_capacity_idx;
53
57
uindex_t m_count;
54
58
uintptr_t *m_buckets;
@@ -106,10 +110,21 @@ MCStackIdCache::MCStackIdCache(void)
106
110
107
111
MCStackIdCache::~MCStackIdCache (void )
108
112
{
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);
110
125
}
111
126
112
- void MCStackIdCache::CacheObject (MCObject * p_object)
127
+ void MCStackIdCache::CacheObject (MCObjectHandle p_object)
113
128
{
114
129
if (p_object -> getinidcache ())
115
130
return ;
@@ -121,7 +136,7 @@ void MCStackIdCache::CacheObject(MCObject *p_object)
121
136
t_hash = HashId (t_id);
122
137
123
138
uindex_t t_target_slot;
124
- t_target_slot = FindBucket (t_id, t_hash);
139
+ t_target_slot = FindBucket (t_id, t_hash, false );
125
140
126
141
if (t_target_slot == UINDEX_MAX)
127
142
{
@@ -135,11 +150,11 @@ void MCStackIdCache::CacheObject(MCObject *p_object)
135
150
return ;
136
151
137
152
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 ()) ;
139
154
m_count += 1 ;
140
155
}
141
156
142
- void MCStackIdCache::UncacheObject (MCObject * p_object)
157
+ void MCStackIdCache::UncacheObject (MCObjectHandle p_object)
143
158
{
144
159
if (!p_object -> getinidcache ())
145
160
return ;
@@ -155,13 +170,14 @@ void MCStackIdCache::UncacheObject(MCObject *p_object)
155
170
156
171
if (t_target_slot != UINDEX_MAX)
157
172
{
158
- p_object -> setinidcache (false );
173
+ p_object.ExternalRelease ();
174
+ p_object -> setinidcache (false );
159
175
m_buckets[t_target_slot] = UINTPTR_MAX;
160
176
m_count -= 1 ;
161
177
}
162
178
}
163
179
164
- MCObject * MCStackIdCache::FindObject (uint32_t p_id)
180
+ MCObjectHandle MCStackIdCache::FindObject (uint32_t p_id)
165
181
{
166
182
hash_t t_hash;
167
183
t_hash = HashId (p_id);
@@ -170,7 +186,7 @@ MCObject *MCStackIdCache::FindObject(uint32_t p_id)
170
186
t_target_slot = FindBucketIfExists (p_id, t_hash);
171
187
172
188
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]) ;
174
190
175
191
return nil;
176
192
}
@@ -183,55 +199,7 @@ hash_t MCStackIdCache::HashId(uint32_t h)
183
199
return h ^ (h >> 7 ) ^ (h >> 4 );
184
200
}
185
201
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)
235
203
{
236
204
uindex_t t_capacity;
237
205
t_capacity = __kMCValueHashTableSizes[m_capacity_idx];
@@ -243,8 +211,8 @@ uindex_t MCStackIdCache::FindBucketIfExists(uint32_t p_id, hash_t p_hash)
243
211
t_h1 = p_hash % t_capacity;
244
212
#endif
245
213
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 ;
248
216
249
217
for (uindex_t i = 0 ; i < t_capacity; i++)
250
218
{
@@ -254,17 +222,41 @@ uindex_t MCStackIdCache::FindBucketIfExists(uint32_t p_id, hash_t p_hash)
254
222
if (t_bucket == UINTPTR_MIN)
255
223
return UINDEX_MAX;
256
224
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
+ }
260
249
261
250
t_probe += 1 ;
262
251
263
252
if (t_capacity <= t_probe)
264
253
t_probe -= t_capacity;
265
254
}
266
255
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;
268
260
}
269
261
270
262
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)
344
336
{
345
337
if (t_old_buckets[i] != UINTPTR_MIN && t_old_buckets[i] != UINTPTR_MAX)
346
338
{
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
+
350
351
hash_t t_hash;
351
352
t_hash = HashId (t_id);
352
353
@@ -356,6 +357,8 @@ bool MCStackIdCache::RehashBuckets(index_t p_new_item_count_delta)
356
357
// This assertion should never trigger - something is very wrong if it does!
357
358
MCAssert (t_target_slot != UINDEX_MAX);
358
359
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.
359
362
m_buckets[t_target_slot] = t_old_buckets[i];
360
363
}
361
364
}
@@ -383,15 +386,15 @@ void MCStack::cacheobjectbyid(MCObject *p_object)
383
386
}
384
387
385
388
if (m_id_cache != nil)
386
- m_id_cache -> CacheObject (p_object);
389
+ m_id_cache -> CacheObject (p_object-> GetHandle () );
387
390
}
388
391
389
392
void MCStack::uncacheobjectbyid (MCObject *p_object)
390
393
{
391
394
if (m_id_cache == nil)
392
395
return ;
393
396
394
- m_id_cache -> UncacheObject (p_object);
397
+ m_id_cache -> UncacheObject (p_object-> GetHandle () );
395
398
}
396
399
397
400
MCObject *MCStack::findobjectbyid (uint32_t p_id)
0 commit comments