1999-04-07 10:01:30 +02:00
|
|
|
/*
|
|
|
|
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
|
|
|
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
|
|
|
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
|
|
|
*
|
|
|
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
|
|
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted to use or copy this program
|
|
|
|
* for any purpose, provided the above notices are retained on all copies.
|
|
|
|
* Permission to modify the code and to distribute modified code is granted,
|
|
|
|
* provided the above notices are retained, and a notice that the code was
|
|
|
|
* modified is included with the above copyright notice.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These are extra allocation routines which are likely to be less
|
|
|
|
* frequently used than those in malloc.c. They are separate in the
|
|
|
|
* hope that the .o file will be excluded from statically linked
|
|
|
|
* executables. We should probably break this up further.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "gc_priv.h"
|
|
|
|
|
|
|
|
extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
|
|
|
|
void GC_extend_size_map(); /* in misc.c. */
|
|
|
|
GC_bool GC_alloc_reclaim_list(); /* in malloc.c */
|
|
|
|
|
|
|
|
/* Some externally visible but unadvertised variables to allow access to */
|
|
|
|
/* free lists from inlined allocators without including gc_priv.h */
|
|
|
|
/* or introducing dependencies on internal data structure layouts. */
|
|
|
|
ptr_t * CONST GC_objfreelist_ptr = GC_objfreelist;
|
|
|
|
ptr_t * CONST GC_aobjfreelist_ptr = GC_aobjfreelist;
|
|
|
|
ptr_t * CONST GC_uobjfreelist_ptr = GC_uobjfreelist;
|
|
|
|
# ifdef ATOMIC_UNCOLLECTABLE
|
|
|
|
ptr_t * CONST GC_auobjfreelist_ptr = GC_auobjfreelist;
|
|
|
|
# endif
|
|
|
|
|
|
|
|
/* Allocate a composite object of size n bytes. The caller guarantees */
|
|
|
|
/* that pointers past the first page are not relevant. Caller holds */
|
|
|
|
/* allocation lock. */
|
|
|
|
ptr_t GC_generic_malloc_inner_ignore_off_page(lb, k)
|
|
|
|
register size_t lb;
|
|
|
|
register int k;
|
|
|
|
{
|
|
|
|
register struct hblk * h;
|
|
|
|
register word n_blocks;
|
|
|
|
register word lw;
|
|
|
|
register ptr_t op;
|
|
|
|
|
|
|
|
if (lb <= HBLKSIZE)
|
|
|
|
return(GC_generic_malloc_inner((word)lb, k));
|
|
|
|
n_blocks = divHBLKSZ(ADD_SLOP(lb) + HDR_BYTES + HBLKSIZE-1);
|
|
|
|
if (!GC_is_initialized) GC_init_inner();
|
|
|
|
/* Do our share of marking work */
|
|
|
|
if(GC_incremental && !GC_dont_gc)
|
|
|
|
GC_collect_a_little_inner((int)n_blocks);
|
|
|
|
lw = ROUNDED_UP_WORDS(lb);
|
1999-11-02 00:15:51 +01:00
|
|
|
h = GC_allochblk(lw, k, IGNORE_OFF_PAGE);
|
|
|
|
# ifdef USE_MUNMAP
|
|
|
|
if (0 == h) {
|
|
|
|
GC_merge_unmapped();
|
|
|
|
h = GC_allochblk(lw, k, IGNORE_OFF_PAGE);
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
while (0 == h && GC_collect_or_expand(n_blocks, TRUE)) {
|
|
|
|
h = GC_allochblk(lw, k, IGNORE_OFF_PAGE);
|
|
|
|
}
|
1999-04-07 10:01:30 +02:00
|
|
|
if (h == 0) {
|
|
|
|
op = 0;
|
|
|
|
} else {
|
|
|
|
op = (ptr_t) (h -> hb_body);
|
|
|
|
GC_words_wasted += BYTES_TO_WORDS(n_blocks * HBLKSIZE) - lw;
|
|
|
|
}
|
|
|
|
GC_words_allocd += lw;
|
|
|
|
return((ptr_t)op);
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr_t GC_generic_malloc_ignore_off_page(lb, k)
|
|
|
|
register size_t lb;
|
|
|
|
register int k;
|
|
|
|
{
|
|
|
|
register ptr_t result;
|
|
|
|
DCL_LOCK_STATE;
|
|
|
|
|
|
|
|
GC_INVOKE_FINALIZERS();
|
|
|
|
DISABLE_SIGNALS();
|
|
|
|
LOCK();
|
|
|
|
result = GC_generic_malloc_inner_ignore_off_page(lb,k);
|
|
|
|
UNLOCK();
|
|
|
|
ENABLE_SIGNALS();
|
|
|
|
if (0 == result) {
|
|
|
|
return((*GC_oom_fn)(lb));
|
|
|
|
} else {
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Increment GC_words_allocd from code that doesn't have direct access */
|
|
|
|
/* to GC_arrays. */
|
|
|
|
# ifdef __STDC__
|
|
|
|
void GC_incr_words_allocd(size_t n)
|
|
|
|
{
|
|
|
|
GC_words_allocd += n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The same for GC_mem_freed. */
|
|
|
|
void GC_incr_mem_freed(size_t n)
|
|
|
|
{
|
|
|
|
GC_mem_freed += n;
|
|
|
|
}
|
|
|
|
# endif /* __STDC__ */
|
|
|
|
|
|
|
|
/* Analogous to the above, but assumes a small object size, and */
|
|
|
|
/* bypasses MERGE_SIZES mechanism. Used by gc_inline.h. */
|
2000-04-19 12:10:01 +02:00
|
|
|
ptr_t GC_generic_malloc_words_small_inner(lw, k)
|
|
|
|
register word lw;
|
|
|
|
register int k;
|
1999-04-07 10:01:30 +02:00
|
|
|
{
|
|
|
|
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)) {
|
1999-11-02 00:15:51 +01:00
|
|
|
op = GC_clear_stack(GC_allocobj((word)lw, k));
|
1999-04-07 10:01:30 +02:00
|
|
|
}
|
|
|
|
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;
|
2000-04-19 12:10:01 +02:00
|
|
|
return((ptr_t)op);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Analogous to the above, but assumes a small object size, and */
|
|
|
|
/* bypasses MERGE_SIZES mechanism. Used by gc_inline.h. */
|
|
|
|
#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;
|
|
|
|
|
|
|
|
GC_INVOKE_FINALIZERS();
|
|
|
|
DISABLE_SIGNALS();
|
|
|
|
LOCK();
|
|
|
|
op = GC_generic_malloc_words_small_inner(lw, k);
|
1999-04-07 10:01:30 +02:00
|
|
|
UNLOCK();
|
|
|
|
ENABLE_SIGNALS();
|
|
|
|
return((ptr_t)op);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(THREADS) && !defined(SRC_M3)
|
|
|
|
/* Return a list of 1 or more objects of the indicated size, linked */
|
|
|
|
/* through the first word in the object. This has the advantage that */
|
|
|
|
/* it acquires the allocation lock only once, and may greatly reduce */
|
|
|
|
/* time wasted contending for the allocation lock. Typical usage would */
|
|
|
|
/* be in a thread that requires many items of the same size. It would */
|
|
|
|
/* keep its own free list in thread-local storage, and call */
|
|
|
|
/* GC_malloc_many or friends to replenish it. (We do not round up */
|
|
|
|
/* object sizes, since a call indicates the intention to consume many */
|
|
|
|
/* objects of exactly this size.) */
|
|
|
|
/* Note that the client should usually clear the link field. */
|
|
|
|
ptr_t GC_generic_malloc_many(lb, k)
|
|
|
|
register word lb;
|
|
|
|
register int k;
|
|
|
|
{
|
|
|
|
ptr_t op;
|
|
|
|
register ptr_t p;
|
|
|
|
ptr_t *opp;
|
|
|
|
word lw;
|
|
|
|
register word my_words_allocd;
|
|
|
|
DCL_LOCK_STATE;
|
|
|
|
|
|
|
|
if (!SMALL_OBJ(lb)) {
|
|
|
|
op = GC_generic_malloc(lb, k);
|
|
|
|
if(0 != op) obj_link(op) = 0;
|
|
|
|
return(op);
|
|
|
|
}
|
|
|
|
lw = ALIGNED_WORDS(lb);
|
|
|
|
GC_INVOKE_FINALIZERS();
|
|
|
|
DISABLE_SIGNALS();
|
|
|
|
LOCK();
|
|
|
|
opp = &(GC_obj_kinds[k].ok_freelist[lw]);
|
|
|
|
if( (op = *opp) == 0 ) {
|
|
|
|
if (!GC_is_initialized) {
|
|
|
|
GC_init_inner();
|
|
|
|
}
|
|
|
|
op = GC_clear_stack(GC_allocobj(lw, k));
|
|
|
|
if (op == 0) {
|
|
|
|
UNLOCK();
|
|
|
|
ENABLE_SIGNALS();
|
|
|
|
op = (*GC_oom_fn)(lb);
|
|
|
|
if(0 != op) obj_link(op) = 0;
|
|
|
|
return(op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*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;
|
|
|
|
|
|
|
|
out:
|
|
|
|
UNLOCK();
|
|
|
|
ENABLE_SIGNALS();
|
|
|
|
return(op);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void * GC_malloc_many(size_t lb)
|
|
|
|
{
|
|
|
|
return(GC_generic_malloc_many(lb, NORMAL));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note that the "atomic" version of this would be unsafe, since the */
|
|
|
|
/* links would not be seen by the collector. */
|
|
|
|
# endif
|
|
|
|
|
|
|
|
/* Allocate lb bytes of pointerful, traced, but not collectable data */
|
|
|
|
# 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
|
|
|
|
# ifdef ADD_BYTE_AT_END
|
|
|
|
if (lb != 0) lb--;
|
|
|
|
/* We don't need the extra byte, since this won't be */
|
|
|
|
/* collected anyway. */
|
|
|
|
# endif
|
|
|
|
lw = GC_size_map[lb];
|
|
|
|
# else
|
|
|
|
lw = ALIGNED_WORDS(lb);
|
|
|
|
# endif
|
|
|
|
opp = &(GC_uobjfreelist[lw]);
|
|
|
|
FASTLOCK();
|
|
|
|
if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
|
|
|
|
/* See above comment on signals. */
|
|
|
|
*opp = obj_link(op);
|
|
|
|
obj_link(op) = 0;
|
|
|
|
GC_words_allocd += lw;
|
|
|
|
/* Mark bit ws already set on free list. It will be */
|
|
|
|
/* cleared only temporarily during a collection, as a */
|
|
|
|
/* result of the normal free list mark bit clearing. */
|
|
|
|
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);
|
|
|
|
/* We don't need the lock here, since we have an undisguised */
|
|
|
|
/* pointer. We do need to hold the lock while we adjust */
|
|
|
|
/* mark bits. */
|
|
|
|
{
|
|
|
|
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 ATOMIC_UNCOLLECTABLE
|
|
|
|
/* Allocate lb bytes of pointerfree, untraced, uncollectable data */
|
|
|
|
/* This is normally roughly equivalent to the system malloc. */
|
|
|
|
/* But it may be useful if malloc is redefined. */
|
|
|
|
# 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
|
|
|
|
# ifdef ADD_BYTE_AT_END
|
|
|
|
if (lb != 0) lb--;
|
|
|
|
/* We don't need the extra byte, since this won't be */
|
|
|
|
/* collected anyway. */
|
|
|
|
# endif
|
|
|
|
lw = GC_size_map[lb];
|
|
|
|
# else
|
|
|
|
lw = ALIGNED_WORDS(lb);
|
|
|
|
# endif
|
|
|
|
opp = &(GC_auobjfreelist[lw]);
|
|
|
|
FASTLOCK();
|
|
|
|
if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
|
|
|
|
/* See above comment on signals. */
|
|
|
|
*opp = obj_link(op);
|
|
|
|
obj_link(op) = 0;
|
|
|
|
GC_words_allocd += lw;
|
|
|
|
/* Mark bit was already set while object was on free list. */
|
|
|
|
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);
|
|
|
|
/* We don't need the lock here, since we have an undisguised */
|
|
|
|
/* pointer. We do need to hold the lock while we adjust */
|
|
|
|
/* mark bits. */
|
|
|
|
{
|
|
|
|
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 /* ATOMIC_UNCOLLECTABLE */
|