Skip to content

Commit 802b82c

Browse files
committed
fix off-by-one in gc_img_max
1 parent 0adc866 commit 802b82c

File tree

1 file changed

+41
-47
lines changed

1 file changed

+41
-47
lines changed

src/gc.c

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ bigval_t *big_objects_marked = NULL;
177177
// See https://algorithmica.org/en/eytzinger
178178
static arraylist_t eytzinger_image_tree;
179179
static arraylist_t eytzinger_idxs;
180-
static uintptr_t gc_img_min = (uintptr_t) 0ull;
181-
static uintptr_t gc_img_max = (uintptr_t) ~0ull;
180+
static uintptr_t gc_img_min;
181+
static uintptr_t gc_img_max;
182182

183183
// -- Finalization --
184184
// `ptls->finalizers` and `finalizer_list_marked` might have tagged pointers.
@@ -190,15 +190,17 @@ arraylist_t finalizer_list_marked;
190190
arraylist_t to_finalize;
191191
JL_DLLEXPORT _Atomic(int) jl_gc_have_pending_finalizers = 0;
192192

193-
static int ptr_cmp(const void *l, const void *r) {
193+
static int ptr_cmp(const void *l, const void *r)
194+
{
194195
uintptr_t left = *(const uintptr_t*)l;
195196
uintptr_t right = *(const uintptr_t*)r;
196197
// jl_safe_printf("cmp %p %p\n", (void*)left, (void*)right);
197198
return (left > right) - (left < right);
198199
}
199200

200201
// Build an eytzinger tree from a sorted array
201-
static int eytzinger(uintptr_t *src, uintptr_t *dest, size_t i, size_t k, size_t n) {
202+
static int eytzinger(uintptr_t *src, uintptr_t *dest, size_t i, size_t k, size_t n)
203+
{
202204
if (k <= n) {
203205
i = eytzinger(src, dest, i, 2 * k, n);
204206
dest[k-1] = src[i];
@@ -208,16 +210,15 @@ static int eytzinger(uintptr_t *src, uintptr_t *dest, size_t i, size_t k, size_t
208210
return i;
209211
}
210212

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!");
213+
static size_t eyt_obj_idx(jl_value_t *obj) JL_NOTSAFEPOINT
214+
{
215+
size_t n = eytzinger_image_tree.len - 1;
216+
if (n == 0)
217+
return n;
218+
assert(n % 2 == 0 && "Eytzinger tree not even length!");
217219
uintptr_t cmp = (uintptr_t) obj;
218-
if (cmp < gc_img_min || cmp > gc_img_max) {
219-
return eytzinger_image_tree.len;
220-
}
220+
if (cmp <= gc_img_min || cmp > gc_img_max)
221+
return n;
221222
uintptr_t *tree = (uintptr_t*)eytzinger_image_tree.items;
222223
size_t k = 1;
223224
// note that k preserves the history of how we got to the current node
@@ -227,6 +228,7 @@ static size_t eyt_obj_idx(jl_value_t *obj) JL_NOTSAFEPOINT {
227228
k |= greater;
228229
}
229230
// Free to assume k is nonzero, since we start with k = 1
231+
// and cmp > gc_img_min
230232
// This shift does a fast revert of the path until we get
231233
// to a node that evaluated less than cmp.
232234
k >>= (__builtin_ctzll(k) + 1);
@@ -237,13 +239,15 @@ static size_t eyt_obj_idx(jl_value_t *obj) JL_NOTSAFEPOINT {
237239
}
238240

239241
//used in staticdata.c after we add an image
240-
void rebuild_image_blob_tree(void) {
241-
size_t orig = eytzinger_image_tree.len;
242-
size_t inc = jl_linkage_blobs.len - orig;
242+
void rebuild_image_blob_tree(void)
243+
{
244+
size_t inc = 1 + jl_linkage_blobs.len - eytzinger_image_tree.len;
243245
assert(eytzinger_idxs.len == eytzinger_image_tree.len);
244246
assert(eytzinger_idxs.max == eytzinger_image_tree.max);
245247
arraylist_grow(&eytzinger_idxs, inc);
246248
arraylist_grow(&eytzinger_image_tree, inc);
249+
eytzinger_idxs.items[eytzinger_idxs.len - 1] = (void*)jl_linkage_blobs.len;
250+
eytzinger_image_tree.items[eytzinger_image_tree.len - 1] = (void*)1; // outside image
247251
for (size_t i = 0; i < jl_linkage_blobs.len; i++) {
248252
assert((uintptr_t) jl_linkage_blobs.items[i] % 4 == 0 && "Linkage blob not 4-byte aligned!");
249253
// We abuse the pointer here a little so that a couple of properties are true:
@@ -252,61 +256,49 @@ void rebuild_image_blob_tree(void) {
252256
// We assume that there exist no 0-size blobs, but that's a safe assumption
253257
// since it means nothing could be there anyways
254258
uintptr_t val = (uintptr_t) jl_linkage_blobs.items[i];
255-
eytzinger_idxs.items[i] = (void*)(val + 3 - (i & 1));
259+
eytzinger_idxs.items[i] = (void*)(val + (i & 1));
256260
}
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-
// }
261+
qsort(eytzinger_idxs.items, eytzinger_idxs.len - 1, sizeof(void*), ptr_cmp);
261262
gc_img_min = (uintptr_t) eytzinger_idxs.items[0];
262-
gc_img_max = (uintptr_t) eytzinger_idxs.items[eytzinger_idxs.len - 1];
263-
eytzinger((uintptr_t*)eytzinger_idxs.items, (uintptr_t*)eytzinger_image_tree.items, 0, 1, eytzinger_idxs.len);
263+
gc_img_max = (uintptr_t) eytzinger_idxs.items[eytzinger_idxs.len - 2] + 1;
264+
eytzinger((uintptr_t*)eytzinger_idxs.items, (uintptr_t*)eytzinger_image_tree.items, 0, 1, eytzinger_idxs.len - 1);
264265
// Reuse the scratch memory to store the indices
265266
// Still O(nlogn) because binary search
266267
for (size_t i = 0; i < jl_linkage_blobs.len; i ++) {
267268
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);
270269
// 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-
(void) eyt_val;
278-
if (i & 1) {
270+
uintptr_t eyt_val = val + (i & 1);
271+
size_t eyt_idx = eyt_obj_idx((jl_value_t*)(eyt_val + 1)); assert(eyt_idx < eytzinger_idxs.len - 1);
272+
assert(eytzinger_image_tree.items[eyt_idx] == (void*)eyt_val && "Eytzinger tree failed to find object!");
273+
if (i & 1)
279274
eytzinger_idxs.items[eyt_idx] = (void*)n_linkage_blobs();
280-
} else {
275+
else
281276
eytzinger_idxs.items[eyt_idx] = (void*)(i / 2);
282-
}
283277
}
284278
}
285279

286-
static int eyt_obj_in_img(jl_value_t *obj) JL_NOTSAFEPOINT {
280+
static int eyt_obj_in_img(jl_value_t *obj) JL_NOTSAFEPOINT
281+
{
287282
assert((uintptr_t) obj % 4 == 0 && "Object not 4-byte aligned!");
288283
int idx = eyt_obj_idx(obj);
289-
if (idx == eytzinger_image_tree.len) {
290-
return 0;
291-
}
292-
// Now we use a tiny trick: tree[idx] & 1 is whether or not tree[idx] is a start or an end
293-
// of a blob. If it's a start, then the object is in the image, otherwise it's not.
294-
int in_image = (uintptr_t) eytzinger_image_tree.items[idx] & 1;
284+
// Now we use a tiny trick: tree[idx] & 1 is whether or not tree[idx] is a
285+
// start (0) or an end (1) of a blob. If it's a start, then the object is
286+
// in the image, otherwise it is not.
287+
int in_image = ((uintptr_t)eytzinger_image_tree.items[idx] & 1) == 0;
295288
return in_image;
296289
}
297290

298-
size_t external_blob_index(jl_value_t *v) JL_NOTSAFEPOINT {
291+
size_t external_blob_index(jl_value_t *v) JL_NOTSAFEPOINT
292+
{
299293
assert((uintptr_t) v % 4 == 0 && "Object not 4-byte aligned!");
300294
int eyt_idx = eyt_obj_idx(v);
301-
if (eyt_idx == eytzinger_image_tree.len) {
302-
return n_linkage_blobs();
303-
}
304295
// We fill the invalid slots with the length, so we can just return that
305296
size_t idx = (size_t) eytzinger_idxs.items[eyt_idx];
306297
return idx;
307298
}
308299

309-
uint8_t jl_object_in_image(jl_value_t *obj) JL_NOTSAFEPOINT {
300+
uint8_t jl_object_in_image(jl_value_t *obj) JL_NOTSAFEPOINT
301+
{
310302
return eyt_obj_in_img(obj);
311303
}
312304

@@ -3375,6 +3367,8 @@ void jl_gc_init(void)
33753367
arraylist_new(&to_finalize, 0);
33763368
arraylist_new(&eytzinger_image_tree, 0);
33773369
arraylist_new(&eytzinger_idxs, 0);
3370+
arraylist_push(&eytzinger_idxs, (void*)0);
3371+
arraylist_push(&eytzinger_image_tree, (void*)1); // outside image
33783372

33793373
gc_num.interval = default_collect_interval;
33803374
last_long_collect_interval = default_collect_interval;

0 commit comments

Comments
 (0)