return (hhdr -> hb_n_marks == 0);
}
-STATIC GC_bool GC_block_nearly_full(hdr *hhdr)
+STATIC GC_bool GC_block_nearly_full(hdr *hhdr, word sz)
{
- return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8);
+ return hhdr -> hb_n_marks > HBLK_OBJS(sz) * 7 / 8;
}
/* TODO: This should perhaps again be specialized for USE_MARK_BYTES */
signed_word n_bytes_found = 0;
GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
- GC_ASSERT(sz == hhdr -> hb_sz);
+# ifndef THREADS
+ GC_ASSERT(sz == hhdr -> hb_sz);
+# else
+ /* Skip the assertion because of a potential race with GC_realloc. */
+# endif
GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0);
p = (word *)(hbp->hb_body);
plim = (word *)(hbp->hb_body + HBLKSIZE - sz);
word *p, *plim;
signed_word n_bytes_found = 0;
- GC_ASSERT(sz == hhdr -> hb_sz);
+# ifndef THREADS
+ GC_ASSERT(sz == hhdr -> hb_sz);
+# endif
p = (word *)(hbp->hb_body);
plim = (word *)((ptr_t)hbp + HBLKSIZE - sz);
struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind];
int (GC_CALLBACK *disclaim)(void *) = ok->ok_disclaim_proc;
- GC_ASSERT(sz == hhdr -> hb_sz);
+# ifndef THREADS
+ GC_ASSERT(sz == hhdr -> hb_sz);
+# endif
p = (word *)(hbp -> hb_body);
plim = (word *)((ptr_t)p + HBLKSIZE - sz);
{
word bit_no;
ptr_t p, plim;
- GC_ASSERT(sz == hhdr -> hb_sz);
+# ifndef THREADS
+ GC_ASSERT(sz == hhdr -> hb_sz);
+# endif
/* go through all words in block */
p = hbp->hb_body;
plim = p + HBLKSIZE - sz;
* If entirely empty blocks are to be completely deallocated, then
* caller should perform that check.
*/
-STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp,
+STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, word sz,
GC_bool report_if_found)
{
hdr *hhdr = HDR(hbp);
- word sz = hhdr -> hb_sz;
struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found)
{
hdr * hhdr = HDR(hbp);
- word sz = hhdr -> hb_sz; /* size of objects in current block */
+ word sz; /* size of objects in current block */
struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
+# ifdef AO_HAVE_load
+ /* Atomic access is used to avoid racing with GC_realloc. */
+ sz = (word)AO_load((volatile AO_t *)&hhdr->hb_sz);
+# else
+ /* No race as GC_realloc holds the lock while updating hb_sz. */
+ sz = hhdr -> hb_sz;
+# endif
if( sz > MAXOBJBYTES ) { /* 1 big object */
if( !mark_bit_from_hdr(hhdr, 0) ) {
if (report_if_found) {
GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE);
# endif
if (report_if_found) {
- GC_reclaim_small_nonempty_block(hbp, TRUE /* report_if_found */);
+ GC_reclaim_small_nonempty_block(hbp, sz,
+ TRUE /* report_if_found */);
} else if (empty) {
# ifdef ENABLE_DISCLAIM
if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) {
GC_bytes_found += HBLKSIZE;
GC_freehblk(hbp);
}
- } else if (GC_find_leak || !GC_block_nearly_full(hhdr)) {
+ } else if (GC_find_leak || !GC_block_nearly_full(hhdr, sz)) {
/* group of smaller objects, enqueue the real work */
struct hblk **rlh = ok -> ok_reclaim_list;
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
- GC_reclaim_small_nonempty_block(hbp, FALSE);
- if (*flh != 0) break;
+ GC_reclaim_small_nonempty_block(hbp, hhdr -> hb_sz, FALSE);
+ if (*flh != 0)
+ break;
}
}
/* It's likely we'll need it this time, too */
/* It's been touched recently, so this */
/* shouldn't trigger paging. */
- GC_reclaim_small_nonempty_block(hbp, FALSE);
+ GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE);
}
}
}
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr->hb_next;
- GC_reclaim_small_nonempty_block(hbp, FALSE);
+ GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE);
}
}
}