Skip to content

Commit 8b1a67e

Browse files
committed
fix off-by-one in gc_img_max
1 parent 0adc866 commit 8b1a67e

File tree

1 file changed

+43
-48
lines changed

1 file changed

+43
-48
lines changed

src/gc.c

+43-48
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,16 @@ 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) {
242+
void rebuild_image_blob_tree(void)
243+
{
241244
size_t orig = eytzinger_image_tree.len;
242-
size_t inc = jl_linkage_blobs.len - orig;
245+
size_t inc = jl_linkage_blobs.len - orig + 1;
243246
assert(eytzinger_idxs.len == eytzinger_image_tree.len);
244247
assert(eytzinger_idxs.max == eytzinger_image_tree.max);
245248
arraylist_grow(&eytzinger_idxs, inc);
246249
arraylist_grow(&eytzinger_image_tree, inc);
250+
eytzinger_idxs.items[eytzinger_idxs.len - 1] = (void*)jl_linkage_blobs.len;
251+
eytzinger_image_tree.items[eytzinger_image_tree.len - 1] = (void*)1; // outside image
247252
for (size_t i = 0; i < jl_linkage_blobs.len; i++) {
248253
assert((uintptr_t) jl_linkage_blobs.items[i] % 4 == 0 && "Linkage blob not 4-byte aligned!");
249254
// We abuse the pointer here a little so that a couple of properties are true:
@@ -252,61 +257,49 @@ void rebuild_image_blob_tree(void) {
252257
// We assume that there exist no 0-size blobs, but that's a safe assumption
253258
// since it means nothing could be there anyways
254259
uintptr_t val = (uintptr_t) jl_linkage_blobs.items[i];
255-
eytzinger_idxs.items[i] = (void*)(val + 3 - (i & 1));
260+
eytzinger_idxs.items[i] = (void*)(val + (i & 1));
256261
}
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-
// }
262+
qsort(eytzinger_idxs.items, eytzinger_idxs.len - 1, sizeof(void*), ptr_cmp);
261263
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);
264+
gc_img_max = (uintptr_t) eytzinger_idxs.items[eytzinger_idxs.len - 2] + 1;
265+
eytzinger((uintptr_t*)eytzinger_idxs.items, (uintptr_t*)eytzinger_image_tree.items, 0, 1, eytzinger_idxs.len - 1);
264266
// Reuse the scratch memory to store the indices
265267
// Still O(nlogn) because binary search
266268
for (size_t i = 0; i < jl_linkage_blobs.len; i ++) {
267269
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);
270270
// 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) {
271+
uintptr_t eyt_val = val + (i & 1);
272+
size_t eyt_idx = eyt_obj_idx((jl_value_t*)(eyt_val + 1)); assert(eyt_idx < eytzinger_idxs.len - 1);
273+
assert(eytzinger_image_tree.items[eyt_idx] == (void*)eyt_val && "Eytzinger tree failed to find object!");
274+
if (i & 1)
279275
eytzinger_idxs.items[eyt_idx] = (void*)n_linkage_blobs();
280-
} else {
276+
else
281277
eytzinger_idxs.items[eyt_idx] = (void*)(i / 2);
282-
}
283278
}
284279
}
285280

286-
static int eyt_obj_in_img(jl_value_t *obj) JL_NOTSAFEPOINT {
281+
static int eyt_obj_in_img(jl_value_t *obj) JL_NOTSAFEPOINT
282+
{
287283
assert((uintptr_t) obj % 4 == 0 && "Object not 4-byte aligned!");
288284
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;
285+
// Now we use a tiny trick: tree[idx] & 1 is whether or not tree[idx] is a
286+
// start (0) or an end (1) of a blob. If it's a start, then the object is
287+
// in the image, otherwise it is not.
288+
int in_image = ((uintptr_t)eytzinger_image_tree.items[idx] & 1) == 0;
295289
return in_image;
296290
}
297291

298-
size_t external_blob_index(jl_value_t *v) JL_NOTSAFEPOINT {
292+
size_t external_blob_index(jl_value_t *v) JL_NOTSAFEPOINT
293+
{
299294
assert((uintptr_t) v % 4 == 0 && "Object not 4-byte aligned!");
300295
int eyt_idx = eyt_obj_idx(v);
301-
if (eyt_idx == eytzinger_image_tree.len) {
302-
return n_linkage_blobs();
303-
}
304296
// We fill the invalid slots with the length, so we can just return that
305297
size_t idx = (size_t) eytzinger_idxs.items[eyt_idx];
306298
return idx;
307299
}
308300

309-
uint8_t jl_object_in_image(jl_value_t *obj) JL_NOTSAFEPOINT {
301+
uint8_t jl_object_in_image(jl_value_t *obj) JL_NOTSAFEPOINT
302+
{
310303
return eyt_obj_in_img(obj);
311304
}
312305

@@ -3373,8 +3366,10 @@ void jl_gc_init(void)
33733366

33743367
arraylist_new(&finalizer_list_marked, 0);
33753368
arraylist_new(&to_finalize, 0);
3376-
arraylist_new(&eytzinger_image_tree, 0);
3377-
arraylist_new(&eytzinger_idxs, 0);
3369+
arraylist_new(&eytzinger_image_tree, 1);
3370+
arraylist_new(&eytzinger_idxs, 1);
3371+
eytzinger_idxs.items[0] = (void*)0;
3372+
eytzinger_image_tree.items[0] = (void*)1; // outside image
33783373

33793374
gc_num.interval = default_collect_interval;
33803375
last_long_collect_interval = default_collect_interval;

0 commit comments

Comments
 (0)