@@ -177,8 +177,8 @@ bigval_t *big_objects_marked = NULL;
177
177
// See https://algorithmica.org/en/eytzinger
178
178
static arraylist_t eytzinger_image_tree ;
179
179
static arraylist_t eytzinger_idxs ;
180
- static uintptr_t gc_img_min = 0ull ;
181
- static uintptr_t gc_img_max = ~0ull ;
180
+ static uintptr_t gc_img_min = ( uintptr_t ) 0ull ;
181
+ static uintptr_t gc_img_max = ( uintptr_t ) ~0ull ;
182
182
183
183
// -- Finalization --
184
184
// `ptls->finalizers` and `finalizer_list_marked` might have tagged pointers.
@@ -208,6 +208,34 @@ static int eytzinger(uintptr_t *src, uintptr_t *dest, size_t i, size_t k, size_t
208
208
return i ;
209
209
}
210
210
211
+ static size_t eyt_obj_idx (jl_value_t * obj ) JL_NOTSAFEPOINT {
212
+ size_t n = eytzinger_image_tree .len ;
213
+ if (n == 0 ) {
214
+ return eytzinger_image_tree .len ;
215
+ }
216
+ assert (eytzinger_image_tree .len % 2 == 0 && "Eytzinger tree not even length!" );
217
+ uintptr_t cmp = (uintptr_t ) obj ;
218
+ if (cmp < gc_img_min || cmp > gc_img_max ) {
219
+ return eytzinger_image_tree .len ;
220
+ }
221
+ uintptr_t * tree = (uintptr_t * )eytzinger_image_tree .items ;
222
+ size_t k = 1 ;
223
+ // note that k preserves the history of how we got to the current node
224
+ while (k <= n ) {
225
+ int greater = (cmp > tree [k - 1 ]);
226
+ k <<= 1 ;
227
+ k |= greater ;
228
+ }
229
+ // Free to assume k is nonzero, since we start with k = 1
230
+ // This shift does a fast revert of the path until we get
231
+ // to a node that evaluated less than cmp.
232
+ k >>= (__builtin_ctzll (k ) + 1 );
233
+ assert (k != 0 );
234
+ assert (k <= n && "Eytzinger tree index out of bounds!" );
235
+ assert (tree [k - 1 ] < cmp && "Failed to find lower bound for object!" );
236
+ return k - 1 ;
237
+ }
238
+
211
239
//used in staticdata.c after we add an image
212
240
void rebuild_image_blob_tree (void ) {
213
241
size_t orig = eytzinger_image_tree .len ;
@@ -227,43 +255,56 @@ void rebuild_image_blob_tree(void) {
227
255
eytzinger_idxs .items [i ] = (void * )(val + 3 - (i & 1 ));
228
256
}
229
257
qsort (eytzinger_idxs .items , eytzinger_idxs .len , sizeof (void * ), ptr_cmp );
258
+ // for (size_t i = orig; i < eytzinger_idxs.len; i++) {
259
+ // jl_safe_printf("idxs[%lu] = %p\n", i, eytzinger_idxs.items[i]);
260
+ // }
230
261
gc_img_min = (uintptr_t ) eytzinger_idxs .items [0 ];
231
262
gc_img_max = (uintptr_t ) eytzinger_idxs .items [eytzinger_idxs .len - 1 ];
232
263
eytzinger ((uintptr_t * )eytzinger_idxs .items , (uintptr_t * )eytzinger_image_tree .items , 0 , 1 , eytzinger_idxs .len );
233
- }
234
-
235
- static int eyt_obj_in_img (jl_value_t * obj ) {
236
- size_t n = eytzinger_image_tree .len ;
237
- if (n == 0 ) {
238
- return 0 ;
239
- }
240
- assert (eytzinger_image_tree .len % 2 == 0 && "Eytzinger tree not even length!" );
241
- uintptr_t cmp = (uintptr_t ) obj ;
242
- assert (cmp % 4 == 0 && "Object not 4-byte aligned!" );
243
- if (cmp < gc_img_min || cmp > gc_img_max ) {
264
+ // Reuse the scratch memory to store the indices
265
+ // Still O(nlogn) because binary search
266
+ for (size_t i = 0 ; i < jl_linkage_blobs .len ; i ++ ) {
267
+ uintptr_t val = (uintptr_t ) jl_linkage_blobs .items [i ];
268
+ // This is exactly equal to start + 4/end + 3
269
+ uintptr_t cmp = val + 4 - (i & 1 );
270
+ // This is the same computation as in the prior for loop
271
+ uintptr_t eyt_val = val + 3 - (i & 1 );
272
+ size_t eyt_idx = eyt_obj_idx ((jl_value_t * )cmp );
273
+ // jl_safe_printf("eyt_idx: %lu, eytzinger_image_tree.len: %lu\n", eyt_idx, eytzinger_image_tree.len);
274
+ // jl_safe_printf("val: %p, cmp: %p, eytzinger_image_tree.items[eyt_idx]: %p\n", (void*)val, (void*)cmp, eyt_idx == eytzinger_image_tree.len ? NULL : eytzinger_image_tree.items[eyt_idx]);
275
+ assert (((i % 2 == 1 ) || eytzinger_image_tree .items [eyt_idx ] == (void * )eyt_val ) && "Eytzinger tree failed to find object!" );
276
+ assert (((i % 2 == 0 ) || eytzinger_image_tree .items [eyt_idx ] == (void * )eyt_val || cmp == gc_img_max + 1 ) && "Eytzinger tree failed to find object!" );
277
+ if (i & 1 ) {
278
+ eytzinger_idxs .items [eyt_idx ] = (void * )n_linkage_blobs ();
279
+ } else {
280
+ eytzinger_idxs .items [eyt_idx ] = (void * )(i / 2 );
281
+ }
282
+ }
283
+ }
284
+
285
+ static int eyt_obj_in_img (jl_value_t * obj ) JL_NOTSAFEPOINT {
286
+ assert ((uintptr_t ) obj % 4 == 0 && "Object not 4-byte aligned!" );
287
+ int idx = eyt_obj_idx (obj );
288
+ if (idx == eytzinger_image_tree .len ) {
244
289
return 0 ;
245
290
}
246
- uintptr_t * tree = (uintptr_t * )eytzinger_image_tree .items ;
247
- size_t k = 1 ;
248
- // note that k preserves the history of how we got to the current node
249
- while (k <= n ) {
250
- int greater = (cmp > tree [k - 1 ]);
251
- k <<= 1 ;
252
- k |= greater ;
253
- }
254
- // Free to assume k is nonzero, since we start with k = 1
255
- // This shift does a fast revert of the path until we get
256
- // to a node that evaluated less than cmp.
257
- k >>= (__builtin_ctzll (k ) + 1 );
258
- assert (k != 0 );
259
- assert (k <= n && "Eytzinger tree index out of bounds!" );
260
- assert (tree [k - 1 ] < cmp && "Failed to find lower bound for object!" );
261
- // Now we use a tiny trick: tree[k - 1] & 1 is whether or not tree[k - 1] is a start or an end
291
+ // Now we use a tiny trick: tree[idx] & 1 is whether or not tree[idx] is a start or an end
262
292
// of a blob. If it's a start, then the object is in the image, otherwise it's not.
263
- int in_image = (uintptr_t ) eytzinger_image_tree .items [k - 1 ] & 1 ;
293
+ int in_image = (uintptr_t ) eytzinger_image_tree .items [idx ] & 1 ;
264
294
return in_image ;
265
295
}
266
296
297
+ size_t external_blob_index (jl_value_t * v ) JL_NOTSAFEPOINT {
298
+ assert ((uintptr_t ) v % 4 == 0 && "Object not 4-byte aligned!" );
299
+ int eyt_idx = eyt_obj_idx (v );
300
+ if (eyt_idx == eytzinger_image_tree .len ) {
301
+ return n_linkage_blobs ();
302
+ }
303
+ // We fill the invalid slots with the length, so we can just return that
304
+ size_t idx = (size_t ) eytzinger_idxs .items [eyt_idx ];
305
+ return idx ;
306
+ }
307
+
267
308
uint8_t jl_object_in_image (jl_value_t * obj ) JL_NOTSAFEPOINT {
268
309
return eyt_obj_in_img (obj );
269
310
}
0 commit comments