summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2023-01-20 21:16:51 +0300
committerIvan Maidanski <ivmai@mail.ru>2023-01-24 12:28:20 +0300
commitba137368d1add5a24ff2fafe2ae2587c765cad34 (patch)
treea949b2ab5b8d0e5da33ea02b4b65d28f53d00149
parent94eda0c39eea3f6fce7990c0984542ab2c58c79d (diff)
downloadbdwgc-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.c55
-rw-r--r--include/gc/gc.h5
-rw-r--r--include/private/gc_priv.h12
-rw-r--r--include/private/gcconfig.h9
-rw-r--r--malloc.c39
-rw-r--r--mallocx.c31
-rw-r--r--new_hblk.c4
-rw-r--r--tests/gctest.c2
8 files changed, 90 insertions, 67 deletions
diff --git a/allchblk.c b/allchblk.c
index 977bf53d..d6e7bf6d 100644
--- a/allchblk.c
+++ b/allchblk.c
@@ -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
diff --git a/malloc.c b/malloc.c
index e0643790..5101df64 100644
--- a/malloc.c
+++ b/malloc.c
@@ -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);
diff --git a/mallocx.c b/mallocx.c
index aa441d2b..77ba5675 100644
--- a/mallocx.c
+++ b/mallocx.c
@@ -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;
}
diff --git a/new_hblk.c b/new_hblk.c
index 30a9a9ef..b8b06682 100644
--- a/new_hblk.c
+++ b/new_hblk.c
@@ -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);