diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2023-01-20 21:16:51 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2023-01-24 12:28:20 +0300 |
commit | ba137368d1add5a24ff2fafe2ae2587c765cad34 (patch) | |
tree | a949b2ab5b8d0e5da33ea02b4b65d28f53d00149 | |
parent | 94eda0c39eea3f6fce7990c0984542ab2c58c79d (diff) | |
download | bdwgc-ba137368d1add5a24ff2fafe2ae2587c765cad34.tar.gz |
Support GC_memalign with alignments greater than HBLKSIZE
Issue #510 (bdwgc).
* allchblk.c (GC_allochblk_nth, GC_allochblk, next_hblk_fits_better,
find_nonbl_hblk): Add align_m1 argument.
* include/private/gc_priv.h (GC_allochblk, GC_alloc_large): Likewise.
* malloc.c (GC_alloc_large): Likewise.
* allchblk.c (GC_allochblk): Check that there is no overflow in
blocks*HBLKSIZE+align_m1; pass align_m1 to GC_allochblk_nth; try
start_list again (with may_split) if non-zero align_m1.
* allchblk.c (ALIGN_PAD_SZ): New macro.
* allchblk.c (next_hblk_fits_better): Define and use next_ofs local
variable; adjust next_hbp passed to GC_is_black_listed().
* allchblk.c (find_nonbl_hblk): Adjust search_end and last_hbp based
on align_m1 value.
* allchblk.c (GC_allochblk_nth): Add assertion that align_m1+1 is
a power of two and that align_m1+1 is 1 or a multiple of HBLKSIZE;
define and use align_ofs local variable; add assertion that last_hbp
(before GC_install_header() call) is multiple of align_m1+1.
* include/gc/gc.h (GC_memalign): Update comment to mention the
restriction on align value (should be a power of two and not less than
size of a pointer).
* include/private/gc_priv.h (GC_allochblk, GC_alloc_large): Update
comment (to mention align_m1 argument).
* include/private/gc_priv.h (GC_generic_malloc_aligned): Declare
function.
* include/private/gcconfig.h [(NACL || I386 && (EMSCRIPTEN || WASI))
&& !HBLKSIZE && !GC_NO_VALLOC] (HBLKSIZE): Do not define (to 65536 or
GETPAGESIZE()); remove TODO item.
* malloc.c (GC_alloc_large): Add alignment to n_blocks value (but not
to GC_large_allocd_bytes); pass align_m1 to GC_allochblk(); add
assertion that result is aligned to align_m1+1.
* malloc.c (GC_alloc_large_and_clear): Pass zero align_m1 to
GC_alloc_large().
* mallocx.c (GC_generic_malloc_ignore_off_page): Likewise.
* malloc.c (GC_generic_malloc_aligned): Move code from
GC_generic_malloc; adjust align_m1 to be either zero or not less than
HBLKSIZE-1, and pass it to GC_alloc_large(); add comment that the
result of GC_oom_fn(lb) might be unaligned.
* malloc.c (GC_generic_malloc): Call GC_generic_malloc_aligned() with
zero align_m1.
* mallocx.c (GC_generic_malloc_ignore_off_page): Expect result of
GC_alloc_large() is unlikely to be NULL.
* mallocx.c (GC_generic_malloc_many): Pass zero align_m1 to
GC_allochblk().
* new_hblk.c (GC_new_hblk): Likewise.
* mallocx.c: Do not include limits.h.
* mallocx.c (GC_memalign): Remove new_lb local variable; define and
use align_m1 local variable; if align is smaller than sizeof(void*) or
is not a power of two than return NULL; call GC_generic_malloc_aligned
and GC_clear_stack (instead of GC_oom_fn() or GC_malloc()) if align or
lb is at least HBLKSIZE/2; replace result%align to result&align_m1;
do not result+=offset if offset is zero.
* new_hblk.c (GC_new_hblk): Expect result of GC_allochblk() is unlikely
to be NULL.
* tests/gctest.c (run_one_test): Call GC_memalign() also for bigger
alignment values (up to HBLKSIZE*4).
-rw-r--r-- | allchblk.c | 55 | ||||
-rw-r--r-- | include/gc/gc.h | 5 | ||||
-rw-r--r-- | include/private/gc_priv.h | 12 | ||||
-rw-r--r-- | include/private/gcconfig.h | 9 | ||||
-rw-r--r-- | malloc.c | 39 | ||||
-rw-r--r-- | mallocx.c | 31 | ||||
-rw-r--r-- | new_hblk.c | 4 | ||||
-rw-r--r-- | tests/gctest.c | 2 |
8 files changed, 90 insertions, 67 deletions
@@ -674,14 +674,16 @@ STATIC void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n, } STATIC struct hblk *GC_allochblk_nth(size_t sz /* bytes */, int kind, - unsigned flags, int n, int may_split); + unsigned flags, int n, int may_split, + size_t align_m1); #ifdef USE_MUNMAP # define AVOID_SPLIT_REMAPPED 2 #endif GC_INNER struct hblk *GC_allochblk(size_t sz, int kind, - unsigned flags /* IGNORE_OFF_PAGE or 0 */) + unsigned flags /* IGNORE_OFF_PAGE or 0 */, + size_t align_m1) { size_t blocks; int start_list; @@ -692,12 +694,13 @@ GC_INNER struct hblk *GC_allochblk(size_t sz, int kind, GC_ASSERT(I_HOLD_LOCK()); GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0); blocks = OBJ_SZ_TO_BLOCKS_CHECKED(sz); - if (EXPECT(blocks >= (GC_SIZE_MAX >> 1) / HBLKSIZE, FALSE)) + if (EXPECT(SIZET_SAT_ADD(blocks * HBLKSIZE, align_m1) + >= (GC_SIZE_MAX >> 1), FALSE)) return NULL; /* overflow */ start_list = GC_hblk_fl_from_blocks(blocks); /* Try for an exact match first. */ - result = GC_allochblk_nth(sz, kind, flags, start_list, FALSE); + result = GC_allochblk_nth(sz, kind, flags, start_list, FALSE, align_m1); if (result != NULL) return result; may_split = TRUE; @@ -723,13 +726,14 @@ GC_INNER struct hblk *GC_allochblk(size_t sz, int kind, may_split = AVOID_SPLIT_REMAPPED; # endif } - if (start_list < UNIQUE_THRESHOLD) { + if (start_list < UNIQUE_THRESHOLD && 0 == align_m1) { /* No reason to try start_list again, since all blocks are exact */ /* matches. */ ++start_list; } for (; start_list <= split_limit; ++start_list) { - result = GC_allochblk_nth(sz, kind, flags, start_list, may_split); + result = GC_allochblk_nth(sz, kind, flags, start_list, may_split, + align_m1); if (result != NULL) break; } return result; @@ -742,11 +746,15 @@ STATIC unsigned GC_drop_blacklisted_count = 0; /* Counter of the cases when found block by */ /* GC_allochblk_nth is blacklisted completely. */ +#define ALIGN_PAD_SZ(p, align_m1) \ + (((align_m1) + 1 - (size_t)(word)(p)) & (align_m1)) + static GC_bool next_hblk_fits_better(hdr *hhdr, word size_avail, - word size_needed) + word size_needed, size_t align_m1) { hdr *next_hdr; word next_size; + size_t next_ofs; struct hblk *next_hbp = hhdr -> hb_next; if (NULL == next_hbp) return FALSE; /* no next block */ @@ -754,18 +762,20 @@ static GC_bool next_hblk_fits_better(hdr *hhdr, word size_avail, next_size = next_hdr -> hb_sz; if (size_avail <= next_size) return FALSE; /* not enough size */ - return next_size >= size_needed - && !GC_is_black_listed(next_hbp, size_needed); + next_ofs = ALIGN_PAD_SZ(next_hbp, align_m1); + return next_size >= size_needed + next_ofs + && !GC_is_black_listed(next_hbp + divHBLKSZ(next_ofs), size_needed); } static struct hblk *find_nonbl_hblk(struct hblk *last_hbp, word size_remain, - word eff_size_needed) + word eff_size_needed, size_t align_m1) { - word search_end = (word)last_hbp + size_remain; + word search_end = ((word)last_hbp + size_remain) & ~(word)align_m1; do { struct hblk *next_hbp; + last_hbp += divHBLKSZ(ALIGN_PAD_SZ(last_hbp, align_m1)); next_hbp = GC_is_black_listed(last_hbp, eff_size_needed); if (NULL == next_hbp) return last_hbp; /* not black-listed */ last_hbp = next_hbp; @@ -801,7 +811,7 @@ static void drop_hblk_in_chunks(int n, struct hblk *hbp, hdr *hhdr) /* followed by splitting should be generally avoided. Rounded-up sz */ /* plus align_m1 value should be less than GC_SIZE_MAX/2. */ STATIC struct hblk *GC_allochblk_nth(size_t sz, int kind, unsigned flags, - int n, int may_split) + int n, int may_split, size_t align_m1) { struct hblk *hbp, *last_hbp; hdr *hhdr; /* header corresponding to hbp */ @@ -809,11 +819,13 @@ STATIC struct hblk *GC_allochblk_nth(size_t sz, int kind, unsigned flags, /* number of bytes in requested objects */ GC_ASSERT(I_HOLD_LOCK()); - GC_ASSERT(sz > 0); + GC_ASSERT(((align_m1 + 1) & align_m1) == 0 && sz > 0); + GC_ASSERT(0 == align_m1 || modHBLKSZ(align_m1 + 1) == 0); retry: /* Search for a big enough block in free list. */ for (hbp = GC_hblkfreelist[n];; hbp = hhdr -> hb_next) { word size_avail; /* bytes available in this block */ + size_t align_ofs; if (hbp /* != NULL */) { /* CPPCHECK */ @@ -822,27 +834,29 @@ STATIC struct hblk *GC_allochblk_nth(size_t sz, int kind, unsigned flags, } GET_HDR(hbp, hhdr); /* set hhdr value */ size_avail = hhdr -> hb_sz; + if (!may_split && size_avail != size_needed) continue; - if (size_avail < size_needed) + align_ofs = ALIGN_PAD_SZ(hbp, align_m1); + if (size_avail < size_needed + align_ofs) continue; /* the block is too small */ if (size_avail != size_needed) { - if (!may_split) continue; /* If the next heap block is obviously better, go on. */ /* This prevents us from disassembling a single large */ /* block to get tiny blocks. */ - if (next_hblk_fits_better(hhdr, size_avail, size_needed)) + if (next_hblk_fits_better(hhdr, size_avail, size_needed, align_m1)) continue; } if (IS_UNCOLLECTABLE(kind) || (kind == PTRFREE && size_needed <= MAX_BLACK_LIST_ALLOC)) { - last_hbp = hbp; + last_hbp = hbp + divHBLKSZ(align_ofs); break; } last_hbp = find_nonbl_hblk(hbp, size_avail - size_needed, - (flags & IGNORE_OFF_PAGE) != 0 ? HBLKSIZE : size_needed); + (flags & IGNORE_OFF_PAGE) != 0 ? HBLKSIZE : size_needed, + align_m1); /* Is non-blacklisted part of enough size? */ if (last_hbp != NULL) { # ifdef USE_MUNMAP @@ -858,7 +872,7 @@ STATIC struct hblk *GC_allochblk_nth(size_t sz, int kind, unsigned flags, /* drop some such blocks, since otherwise we spend all our */ /* time traversing them if pointer-free blocks are unpopular. */ /* A dropped block will be reconsidered at next GC. */ - if (size_needed == HBLKSIZE + if (size_needed == HBLKSIZE && 0 == align_m1 && !GC_find_leak && IS_MAPPED(hhdr) && (++GC_drop_blacklisted_count & 3) == 0) { struct hblk *prev = hhdr -> hb_prev; @@ -880,11 +894,12 @@ STATIC struct hblk *GC_allochblk_nth(size_t sz, int kind, unsigned flags, size_needed >> 10); GC_large_alloc_warn_suppressed = 0; } - last_hbp = hbp; + last_hbp = hbp + divHBLKSZ(align_ofs); break; } } + GC_ASSERT(((word)last_hbp & align_m1) == 0); if (last_hbp != hbp) { hdr *last_hdr = GC_install_header(last_hbp); diff --git a/include/gc/gc.h b/include/gc/gc.h index a6f4ab70..fe957a91 100644 --- a/include/gc/gc.h +++ b/include/gc/gc.h @@ -552,8 +552,9 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL GC_API GC_ATTR_DEPRECATED void * GC_CALL GC_malloc_stubborn(size_t); /* The routines that guarantee the requested alignment of the allocated */ -/* memory object. Note that GC_base() and GC_size() might return the */ -/* value which is not the expected one (due to the alignment). */ +/* memory object. The align argument should be a power of two and not */ +/* less than size of a pointer. Note: GC_base() and GC_size() might */ +/* return the value which is not the expected one due to the alignment. */ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2) void * GC_CALL GC_memalign(size_t /* align */, size_t /* lb */); GC_API int GC_CALL GC_posix_memalign(void ** /* memptr */, size_t /* align */, diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 08d74914..62fd71a8 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -2254,10 +2254,10 @@ GC_INNER ptr_t GC_build_fl(struct hblk *h, size_t words, GC_bool clear, /* called explicitly without GC lock. */ GC_INNER struct hblk * GC_allochblk(size_t size_in_bytes, int kind, - unsigned flags); + unsigned flags, size_t align_m1); /* Allocate (and return pointer to) */ /* a heap block for objects of the */ - /* given size (in bytes), */ + /* given size and alignment (in bytes), */ /* searching over the appropriate free */ /* block lists; inform the marker */ /* that the found block is valid for */ @@ -2269,8 +2269,10 @@ GC_INNER struct hblk * GC_allochblk(size_t size_in_bytes, int kind, /* responsible for building an object */ /* freelist in the block. */ -GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags); - /* Allocate a large block of size lb bytes. */ +GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags, + size_t align_m1); + /* Allocate a large block of size lb bytes with */ + /* the requested alignment (align_m1 plus one). */ /* The block is not cleared. Assumes that */ /* EXTRA_BYTES value is already added to lb. */ /* The flags argument should be IGNORE_OFF_PAGE */ @@ -2336,6 +2338,8 @@ GC_INNER void GC_collect_a_little_inner(int n); /* A unit is an amount appropriate for */ /* HBLKSIZE bytes of allocation. */ +GC_INNER void * GC_generic_malloc_aligned(size_t lb, int k, size_t align_m1); + GC_INNER void * GC_generic_malloc_inner(size_t lb, int k); /* Allocate an object of the given */ /* kind but assuming lock already held. */ diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index bce2a8f8..b9a55b85 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -1195,9 +1195,6 @@ EXTERN_C_BEGIN # define NO_PTHREAD_GETATTR_NP # define USE_MMAP_ANON # define GETPAGESIZE() 65536 /* FIXME: Not real page size */ -# if !defined(HBLKSIZE) && !defined(GC_NO_VALLOC) -# define HBLKSIZE GETPAGESIZE() /* TODO: workaround for GC_valloc */ -# endif # define MAX_NACL_GC_THREADS 1024 # endif @@ -1309,9 +1306,6 @@ EXTERN_C_BEGIN # undef USE_MMAP # undef USE_MUNMAP /* The real page size in WebAssembly is 64 KB. */ -# if !defined(HBLKSIZE) && !defined(GC_NO_VALLOC) -# define HBLKSIZE 65536 /* TODO: workaround for GC_valloc */ -# endif # if defined(GC_THREADS) && !defined(CPPCHECK) # error No threads support yet # endif @@ -1332,9 +1326,6 @@ EXTERN_C_BEGIN # undef USE_MUNMAP /* The real page size in WebAssembly is 64 KB. */ # define GETPAGESIZE() 65536 -# if !defined(HBLKSIZE) && !defined(GC_NO_VALLOC) -# define HBLKSIZE GETPAGESIZE() /* TODO: workaround for GC_valloc */ -# endif # if defined(GC_THREADS) && !defined(CPPCHECK) # error No threads support yet # endif @@ -33,16 +33,17 @@ STATIC GC_bool GC_alloc_reclaim_list(struct obj_kind *kind) return TRUE; } -GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags) +GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags, + size_t align_m1) { struct hblk * h; - size_t n_blocks; + size_t n_blocks; /* includes alignment */ ptr_t result = NULL; GC_bool retry = FALSE; GC_ASSERT(I_HOLD_LOCK()); lb = ROUNDUP_GRANULE_SIZE(lb); - n_blocks = OBJ_SZ_TO_BLOCKS_CHECKED(lb); + n_blocks = OBJ_SZ_TO_BLOCKS_CHECKED(SIZET_SAT_ADD(lb, align_m1)); if (!EXPECT(GC_is_initialized, TRUE)) { DCL_LOCK_STATE; UNLOCK(); /* just to unset GC_lock_holder */ @@ -56,25 +57,26 @@ GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags) EXIT_GC(); } - h = GC_allochblk(lb, k, flags); + h = GC_allochblk(lb, k, flags, align_m1); # ifdef USE_MUNMAP if (NULL == h) { GC_merge_unmapped(); - h = GC_allochblk(lb, k, flags); + h = GC_allochblk(lb, k, flags, align_m1); } # endif while (0 == h && GC_collect_or_expand(n_blocks, flags != 0, retry)) { - h = GC_allochblk(lb, k, flags); + h = GC_allochblk(lb, k, flags, align_m1); retry = TRUE; } if (EXPECT(h != NULL, TRUE)) { - if (n_blocks > 1) { - GC_large_allocd_bytes += HBLKSIZE * n_blocks; + if (lb > HBLKSIZE) { + GC_large_allocd_bytes += HBLKSIZE * OBJ_SZ_TO_BLOCKS(lb); if (GC_large_allocd_bytes > GC_max_large_allocd_bytes) GC_max_large_allocd_bytes = GC_large_allocd_bytes; } /* FIXME: Do we need some way to reset GC_max_large_allocd_bytes? */ result = h -> hb_body; + GC_ASSERT(((word)result & align_m1) == 0); } return result; } @@ -86,7 +88,7 @@ STATIC ptr_t GC_alloc_large_and_clear(size_t lb, int k, unsigned flags) ptr_t result; GC_ASSERT(I_HOLD_LOCK()); - result = GC_alloc_large(lb, k, flags); + result = GC_alloc_large(lb, k, flags, 0 /* align_m1 */); if (EXPECT(result != NULL, TRUE) && (GC_debugging_started || GC_obj_kinds[k].ok_init)) { /* Clear the whole block, in case of GC_realloc call. */ @@ -234,7 +236,7 @@ GC_INNER void * GC_generic_malloc_inner(size_t lb, int k) # endif #endif -GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc(size_t lb, int k) +GC_INNER void * GC_generic_malloc_aligned(size_t lb, int k, size_t align_m1) { void * result; DCL_LOCK_STATE; @@ -244,7 +246,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc(size_t lb, int k) GC_print_all_errors(); GC_INVOKE_FINALIZERS(); GC_DBG_COLLECT_AT_MALLOC(lb); - if (SMALL_OBJ(lb)) { + if (SMALL_OBJ(lb) && EXPECT(align_m1 < GRANULE_BYTES, TRUE)) { LOCK(); result = GC_generic_malloc_inner(lb, k); UNLOCK(); @@ -256,8 +258,13 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc(size_t lb, int k) lg = ROUNDED_UP_GRANULES(lb); lb_rounded = GRANULES_TO_BYTES(lg); init = GC_obj_kinds[k].ok_init; + if (EXPECT(align_m1 < GRANULE_BYTES, TRUE)) { + align_m1 = 0; + } else if (align_m1 < HBLKSIZE) { + align_m1 = HBLKSIZE - 1; + } LOCK(); - result = (ptr_t)GC_alloc_large(lb_rounded, k, 0); + result = (ptr_t)GC_alloc_large(lb_rounded, k, 0 /* flags */, align_m1); if (EXPECT(result != NULL, TRUE)) { if (GC_debugging_started) { BZERO(result, HBLKSIZE * OBJ_SZ_TO_BLOCKS(lb_rounded)); @@ -278,10 +285,16 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc(size_t lb, int k) BZERO(result, HBLKSIZE * OBJ_SZ_TO_BLOCKS(lb_rounded)); } } - if (EXPECT(NULL == result, FALSE)) return (*GC_get_oom_fn())(lb); + if (EXPECT(NULL == result, FALSE)) + result = (*GC_get_oom_fn())(lb); /* might be misaligned */ return result; } +GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc(size_t lb, int k) +{ + return GC_generic_malloc_aligned(lb, k, 0 /* align_m1 */); +} + GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_kind_global(size_t lb, int k) { GC_ASSERT(k < MAXOBJKINDS); @@ -214,8 +214,8 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_INVOKE_FINALIZERS(); GC_DBG_COLLECT_AT_MALLOC(lb); LOCK(); - result = (ptr_t)GC_alloc_large(ADD_SLOP(lb), k, IGNORE_OFF_PAGE); - if (NULL == result) { + result = (ptr_t)GC_alloc_large(ADD_SLOP(lb), k, IGNORE_OFF_PAGE, 0); + if (EXPECT(NULL == result, FALSE)) { GC_oom_func oom_fn = GC_oom_fn; UNLOCK(); return (*oom_fn)(lb); @@ -441,7 +441,8 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) } /* Next try to allocate a new block worth of objects of this size. */ { - struct hblk *h = GC_allochblk(lb, k, 0); + struct hblk *h = GC_allochblk(lb, k, 0 /* flags */, 0 /* align_m1 */); + if (h /* != NULL */) { /* CPPCHECK */ if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h)); GC_bytes_allocd += HBLKSIZE - HBLKSIZE % lb; @@ -494,31 +495,29 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_many(size_t lb) return result; } -#include <limits.h> - /* Debug version is tricky and currently missing. */ GC_API GC_ATTR_MALLOC void * GC_CALL GC_memalign(size_t align, size_t lb) { - size_t new_lb; size_t offset; ptr_t result; + size_t align_m1 = align - 1; + + /* Check the alignment argument. */ + if (align < sizeof(void *) || (align & align_m1) != 0) return NULL; if (align <= GRANULE_BYTES) return GC_malloc(lb); + if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) { - if (EXPECT(align > HBLKSIZE, FALSE)) { - return (*GC_get_oom_fn())(LONG_MAX-1024); /* Fail */ - } - return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb); - /* Will be HBLKSIZE aligned. */ + return GC_clear_stack(GC_generic_malloc_aligned(lb, NORMAL, align_m1)); } + /* We could also try to make sure that the real rounded-up object size */ /* is a multiple of align. That would be correct up to HBLKSIZE. */ /* TODO: Not space efficient for big align values. */ - new_lb = SIZET_SAT_ADD(lb, align - 1); - result = (ptr_t)GC_malloc(new_lb); + result = (ptr_t)GC_malloc(SIZET_SAT_ADD(lb, align_m1)); /* It is OK not to check result for NULL as in that case */ /* GC_memalign returns NULL too since (0 + 0 % align) is 0. */ - offset = (word)result % align; + offset = (size_t)(word)result & align_m1; if (offset != 0) { offset = align - offset; if (!GC_all_interior_pointers) { @@ -526,9 +525,9 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_memalign(size_t align, size_t lb) GC_ASSERT(offset < VALID_OFFSET_SZ); GC_register_displacement(offset); } + result += offset; } - result += offset; - GC_ASSERT((word)result % align == 0); + GC_ASSERT(((word)result & align_m1) == 0); return result; } @@ -177,8 +177,8 @@ GC_INNER void GC_new_hblk(size_t gran, int kind) if (GC_debugging_started) clear = TRUE; /* Allocate a new heap block */ - h = GC_allochblk(GRANULES_TO_BYTES(gran), kind, 0); - if (h == 0) return; + h = GC_allochblk(GRANULES_TO_BYTES(gran), kind, 0 /* flags */, 0); + if (EXPECT(NULL == h, FALSE)) return; /* Mark all objects if appropriate. */ if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(HDR(h)); diff --git a/tests/gctest.c b/tests/gctest.c index ba60f108..16959648 100644 --- a/tests/gctest.c +++ b/tests/gctest.c @@ -1558,7 +1558,7 @@ void run_one_test(void) AO_fetch_and_add1(&collectable_count); /* TODO: GC_memalign and friends are not tested well. */ - for (i = sizeof(GC_word); i < 512; i *= 2) { + for (i = sizeof(GC_word); i <= HBLKSIZE * 4; i *= 2) { p = GC_memalign(i, 17); CHECK_OUT_OF_MEMORY(p); AO_fetch_and_add1(&collectable_count); |