#include <stdio.h>
#include "private/gc_priv.h"
extern ptr_t GC_clear_stack();
void GC_extend_size_map();
GC_bool GC_alloc_reclaim_list();
ptr_t * GC_CONST GC_objfreelist_ptr = GC_objfreelist;
ptr_t * GC_CONST GC_aobjfreelist_ptr = GC_aobjfreelist;
ptr_t * GC_CONST GC_uobjfreelist_ptr = GC_uobjfreelist;
# ifdef ATOMIC_UNCOLLECTABLE
ptr_t * GC_CONST GC_auobjfreelist_ptr = GC_auobjfreelist;
# endif
GC_PTR GC_generic_or_special_malloc(lb,knd)
word lb;
int knd;
{
switch(knd) {
# ifdef STUBBORN_ALLOC
case STUBBORN:
return(GC_malloc_stubborn((size_t)lb));
# endif
case PTRFREE:
return(GC_malloc_atomic((size_t)lb));
case NORMAL:
return(GC_malloc((size_t)lb));
case UNCOLLECTABLE:
return(GC_malloc_uncollectable((size_t)lb));
# ifdef ATOMIC_UNCOLLECTABLE
case AUNCOLLECTABLE:
return(GC_malloc_atomic_uncollectable((size_t)lb));
# endif
default:
return(GC_generic_malloc(lb,knd));
}
}
# ifdef __STDC__
GC_PTR GC_realloc(GC_PTR p, size_t lb)
# else
GC_PTR GC_realloc(p,lb)
GC_PTR p;
size_t lb;
# endif
{
register struct hblk * h;
register hdr * hhdr;
register word sz;
register word orig_sz;
int obj_kind;
if (p == 0) return(GC_malloc(lb));
h = HBLKPTR(p);
hhdr = HDR(h);
sz = hhdr -> hb_sz;
obj_kind = hhdr -> hb_obj_kind;
sz = WORDS_TO_BYTES(sz);
orig_sz = sz;
if (sz > MAXOBJBYTES) {
register word descr;
sz = (sz+HBLKSIZE-1) & (~HBLKMASK);
hhdr -> hb_sz = BYTES_TO_WORDS(sz);
descr = GC_obj_kinds[obj_kind].ok_descriptor;
if (GC_obj_kinds[obj_kind].ok_relocate_descr) descr += sz;
hhdr -> hb_descr = descr;
if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
}
if (ADD_SLOP(lb) <= sz) {
if (lb >= (sz >> 1)) {
# ifdef STUBBORN_ALLOC
if (obj_kind == STUBBORN) GC_change_stubborn(p);
# endif
if (orig_sz > lb) {
BZERO(((ptr_t)p) + lb, orig_sz - lb);
}
return(p);
} else {
GC_PTR result =
GC_generic_or_special_malloc((word)lb, obj_kind);
if (result == 0) return(0);
BCOPY(p, result, lb);
# ifndef IGNORE_FREE
GC_free(p);
# endif
return(result);
}
} else {
GC_PTR result =
GC_generic_or_special_malloc((word)lb, obj_kind);
if (result == 0) return(0);
BCOPY(p, result, sz);
# ifndef IGNORE_FREE
GC_free(p);
# endif
return(result);
}
}
# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_REALLOC)
# define REDIRECT_REALLOC GC_realloc
# endif
# ifdef REDIRECT_REALLOC
# ifdef GC_ADD_CALLER
# define RA GC_RETURN_ADDR,
# else
# define RA
# endif
# define GC_debug_realloc_replacement(p, lb) \
GC_debug_realloc(p, lb, RA "unknown", 0)
# ifdef __STDC__
GC_PTR realloc(GC_PTR p, size_t lb)
# else
GC_PTR realloc(p,lb)
GC_PTR p;
size_t lb;
# endif
{
return(REDIRECT_REALLOC(p, lb));
}
# undef GC_debug_realloc_replacement
# endif
ptr_t GC_generic_malloc_ignore_off_page(lb, k)
register size_t lb;
register int k;
{
register ptr_t result;
word lw;
word n_blocks;
GC_bool init;
DCL_LOCK_STATE;
if (SMALL_OBJ(lb))
return(GC_generic_malloc((word)lb, k));
lw = ROUNDED_UP_WORDS(lb);
n_blocks = OBJ_SZ_TO_BLOCKS(lw);
init = GC_obj_kinds[k].ok_init;
if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
result = (ptr_t)GC_alloc_large(lw, k, IGNORE_OFF_PAGE);
if (0 != result) {
if (GC_debugging_started) {
BZERO(result, n_blocks * HBLKSIZE);
} else {
# ifdef THREADS
((word *)result)[0] = 0;
((word *)result)[1] = 0;
((word *)result)[lw-1] = 0;
((word *)result)[lw-2] = 0;
# endif
}
}
GC_words_allocd += lw;
UNLOCK();
ENABLE_SIGNALS();
if (0 == result) {
return((*GC_oom_fn)(lb));
} else {
if (init && !GC_debugging_started) {
BZERO(result, n_blocks * HBLKSIZE);
}
return(result);
}
}
# if defined(__STDC__) || defined(__cplusplus)
void * GC_malloc_ignore_off_page(size_t lb)
# else
char * GC_malloc_ignore_off_page(lb)
register size_t lb;
# endif
{
return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, NORMAL));
}
# if defined(__STDC__) || defined(__cplusplus)
void * GC_malloc_atomic_ignore_off_page(size_t lb)
# else
char * GC_malloc_atomic_ignore_off_page(lb)
register size_t lb;
# endif
{
return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
}
# ifdef __STDC__
void GC_incr_words_allocd(size_t n)
{
GC_words_allocd += n;
}
void GC_incr_mem_freed(size_t n)
{
GC_mem_freed += n;
}
# endif
ptr_t GC_generic_malloc_words_small_inner(lw, k)
register word lw;
register int k;
{
register ptr_t op;
register ptr_t *opp;
register struct obj_kind * kind = GC_obj_kinds + k;
opp = &(kind -> ok_freelist[lw]);
if( (op = *opp) == 0 ) {
if (!GC_is_initialized) {
GC_init_inner();
}
if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) {
op = GC_clear_stack(GC_allocobj((word)lw, k));
}
if (op == 0) {
UNLOCK();
ENABLE_SIGNALS();
return ((*GC_oom_fn)(WORDS_TO_BYTES(lw)));
}
}
*opp = obj_link(op);
obj_link(op) = 0;
GC_words_allocd += lw;
return((ptr_t)op);
}
#ifdef __STDC__
ptr_t GC_generic_malloc_words_small(size_t lw, int k)
#else
ptr_t GC_generic_malloc_words_small(lw, k)
register word lw;
register int k;
#endif
{
register ptr_t op;
DCL_LOCK_STATE;
if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
op = GC_generic_malloc_words_small_inner(lw, k);
UNLOCK();
ENABLE_SIGNALS();
return((ptr_t)op);
}
#if defined(THREADS) && !defined(SRC_M3)
extern signed_word GC_mem_found;
#ifdef PARALLEL_MARK
volatile signed_word GC_words_allocd_tmp = 0;
#endif
extern ptr_t GC_reclaim_generic();
void GC_generic_malloc_many(lb, k, result)
register word lb;
register int k;
ptr_t *result;
{
ptr_t op;
ptr_t p;
ptr_t *opp;
word lw;
word my_words_allocd = 0;
struct obj_kind * ok = &(GC_obj_kinds[k]);
DCL_LOCK_STATE;
# if defined(GATHERSTATS) || defined(PARALLEL_MARK)
# define COUNT_ARG , &my_words_allocd
# else
# define COUNT_ARG
# define NEED_TO_COUNT
# endif
if (!SMALL_OBJ(lb)) {
op = GC_generic_malloc(lb, k);
if(0 != op) obj_link(op) = 0;
*result = op;
return;
}
lw = ALIGNED_WORDS(lb);
if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
if (!GC_is_initialized) GC_init_inner();
if (GC_incremental && !GC_dont_gc) {
ENTER_GC();
GC_collect_a_little_inner(1);
EXIT_GC();
}
{
struct hblk ** rlh = ok -> ok_reclaim_list;
struct hblk * hbp;
hdr * hhdr;
rlh += lw;
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
# ifdef PARALLEL_MARK
{
signed_word my_words_allocd_tmp = GC_words_allocd_tmp;
GC_ASSERT(my_words_allocd_tmp >= 0);
if (my_words_allocd_tmp != 0) {
(void)GC_atomic_add(
(volatile GC_word *)(&GC_words_allocd_tmp),
(GC_word)(-my_words_allocd_tmp));
GC_words_allocd += my_words_allocd_tmp;
}
}
GC_acquire_mark_lock();
++ GC_fl_builder_count;
UNLOCK();
ENABLE_SIGNALS();
GC_release_mark_lock();
# endif
op = GC_reclaim_generic(hbp, hhdr, lw,
ok -> ok_init, 0 COUNT_ARG);
if (op != 0) {
# ifdef NEED_TO_COUNT
for (p = op; p != 0; p = obj_link(p)) {
my_words_allocd += lw;
}
# endif
# if defined(GATHERSTATS)
GC_mem_found += my_words_allocd;
# endif
# ifdef PARALLEL_MARK
*result = op;
(void)GC_atomic_add(
(volatile GC_word *)(&GC_words_allocd_tmp),
(GC_word)(my_words_allocd));
GC_acquire_mark_lock();
-- GC_fl_builder_count;
if (GC_fl_builder_count == 0) GC_notify_all_builder();
GC_release_mark_lock();
(void) GC_clear_stack(0);
return;
# else
GC_words_allocd += my_words_allocd;
goto out;
# endif
}
# ifdef PARALLEL_MARK
GC_acquire_mark_lock();
-- GC_fl_builder_count;
if (GC_fl_builder_count == 0) GC_notify_all_builder();
GC_release_mark_lock();
DISABLE_SIGNALS();
LOCK();
# endif
}
}
opp = &(GC_obj_kinds[k].ok_freelist[lw]);
if ( (op = *opp) != 0 ) {
*opp = 0;
my_words_allocd = 0;
for (p = op; p != 0; p = obj_link(p)) {
my_words_allocd += lw;
if (my_words_allocd >= BODY_SZ) {
*opp = obj_link(p);
obj_link(p) = 0;
break;
}
}
GC_words_allocd += my_words_allocd;
goto out;
}
{
struct hblk *h = GC_allochblk(lw, k, 0);
if (h != 0) {
if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
GC_words_allocd += BYTES_TO_WORDS(HBLKSIZE)
- BYTES_TO_WORDS(HBLKSIZE) % lw;
# ifdef PARALLEL_MARK
GC_acquire_mark_lock();
++ GC_fl_builder_count;
UNLOCK();
ENABLE_SIGNALS();
GC_release_mark_lock();
# endif
op = GC_build_fl(h, lw, ok -> ok_init, 0);
# ifdef PARALLEL_MARK
*result = op;
GC_acquire_mark_lock();
-- GC_fl_builder_count;
if (GC_fl_builder_count == 0) GC_notify_all_builder();
GC_release_mark_lock();
(void) GC_clear_stack(0);
return;
# else
goto out;
# endif
}
}
op = GC_generic_malloc_inner(lb, k);
if (0 != op) obj_link(op) = 0;
out:
*result = op;
UNLOCK();
ENABLE_SIGNALS();
(void) GC_clear_stack(0);
}
GC_PTR GC_malloc_many(size_t lb)
{
ptr_t result;
GC_generic_malloc_many(lb, NORMAL, &result);
return result;
}
# endif
# ifdef __STDC__
GC_PTR GC_malloc_uncollectable(size_t lb)
# else
GC_PTR GC_malloc_uncollectable(lb)
size_t lb;
# endif
{
register ptr_t op;
register ptr_t *opp;
register word lw;
DCL_LOCK_STATE;
if( SMALL_OBJ(lb) ) {
# ifdef MERGE_SIZES
if (EXTRA_BYTES != 0 && lb != 0) lb--;
lw = GC_size_map[lb];
# else
lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_uobjfreelist[lw]);
FASTLOCK();
if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
*opp = obj_link(op);
obj_link(op) = 0;
GC_words_allocd += lw;
GC_non_gc_bytes += WORDS_TO_BYTES(lw);
FASTUNLOCK();
return((GC_PTR) op);
}
FASTUNLOCK();
op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
} else {
op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
}
if (0 == op) return(0);
{
register struct hblk * h;
h = HBLKPTR(op);
lw = HDR(h) -> hb_sz;
DISABLE_SIGNALS();
LOCK();
GC_set_mark_bit(op);
GC_non_gc_bytes += WORDS_TO_BYTES(lw);
UNLOCK();
ENABLE_SIGNALS();
return((GC_PTR) op);
}
}
#ifdef __STDC__
#include <limits.h>
GC_PTR GC_memalign(size_t align, size_t lb)
{
size_t new_lb;
size_t offset;
ptr_t result;
# ifdef ALIGN_DOUBLE
if (align <= WORDS_TO_BYTES(2) && lb > align) return GC_malloc(lb);
# endif
if (align <= WORDS_TO_BYTES(1)) return GC_malloc(lb);
if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
if (align > HBLKSIZE) return GC_oom_fn(LONG_MAX-1024) ;
return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
}
new_lb = lb + align - 1;
result = GC_malloc(new_lb);
offset = (word)result % align;
if (offset != 0) {
offset = align - offset;
if (!GC_all_interior_pointers) {
if (offset >= VALID_OFFSET_SZ) return GC_malloc(HBLKSIZE);
GC_register_displacement(offset);
}
}
result = (GC_PTR) ((ptr_t)result + offset);
GC_ASSERT((word)result % align == 0);
return result;
}
#endif
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef __STDC__
GC_PTR GC_malloc_atomic_uncollectable(size_t lb)
# else
GC_PTR GC_malloc_atomic_uncollectable(lb)
size_t lb;
# endif
{
register ptr_t op;
register ptr_t *opp;
register word lw;
DCL_LOCK_STATE;
if( SMALL_OBJ(lb) ) {
# ifdef MERGE_SIZES
if (EXTRA_BYTES != 0 && lb != 0) lb--;
lw = GC_size_map[lb];
# else
lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_auobjfreelist[lw]);
FASTLOCK();
if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
*opp = obj_link(op);
obj_link(op) = 0;
GC_words_allocd += lw;
GC_non_gc_bytes += WORDS_TO_BYTES(lw);
FASTUNLOCK();
return((GC_PTR) op);
}
FASTUNLOCK();
op = (ptr_t)GC_generic_malloc((word)lb, AUNCOLLECTABLE);
} else {
op = (ptr_t)GC_generic_malloc((word)lb, AUNCOLLECTABLE);
}
if (0 == op) return(0);
{
register struct hblk * h;
h = HBLKPTR(op);
lw = HDR(h) -> hb_sz;
DISABLE_SIGNALS();
LOCK();
GC_set_mark_bit(op);
GC_non_gc_bytes += WORDS_TO_BYTES(lw);
UNLOCK();
ENABLE_SIGNALS();
return((GC_PTR) op);
}
}
#endif