version 1.1, 1999/12/03 07:39:09 |
version 1.3, 2000/12/01 09:26:10 |
|
|
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. |
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. |
* Copyright (c) 1997 by Silicon Graphics. All rights reserved. |
* Copyright (c) 1997 by Silicon Graphics. All rights reserved. |
|
* Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. |
* |
* |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
|
|
* provided the above notices are retained, and a notice that the code was |
* provided the above notices are retained, and a notice that the code was |
* modified is included with the above copyright notice. |
* modified is included with the above copyright notice. |
*/ |
*/ |
# define I_HIDE_POINTERS |
|
# include "gc_priv.h" |
|
# ifdef KEEP_BACK_PTRS |
|
# include "backptr.h" |
|
# endif |
|
|
|
|
#include "dbg_mlc.h" |
|
|
void GC_default_print_heap_obj_proc(); |
void GC_default_print_heap_obj_proc(); |
GC_API void GC_register_finalizer_no_order |
GC_API void GC_register_finalizer_no_order |
GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, |
GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, |
GC_finalization_proc *ofn, GC_PTR *ocd)); |
GC_finalization_proc *ofn, GC_PTR *ocd)); |
|
|
/* Do we want to and know how to save the call stack at the time of */ |
|
/* an allocation? How much space do we want to use in each object? */ |
|
|
|
# define START_FLAG ((word)0xfedcedcb) |
|
# define END_FLAG ((word)0xbcdecdef) |
|
/* Stored both one past the end of user object, and one before */ |
|
/* the end of the object as seen by the allocator. */ |
|
|
|
|
|
/* Object header */ |
|
typedef struct { |
|
# ifdef KEEP_BACK_PTRS |
|
ptr_t oh_back_ptr; |
|
# define MARKED_FOR_FINALIZATION (ptr_t)(-1) |
|
/* Object was marked because it is finalizable. */ |
|
# ifdef ALIGN_DOUBLE |
|
word oh_dummy; |
|
# endif |
|
# endif |
|
char * oh_string; /* object descriptor string */ |
|
word oh_int; /* object descriptor integers */ |
|
# ifdef NEED_CALLINFO |
|
struct callinfo oh_ci[NFRAMES]; |
|
# endif |
|
word oh_sz; /* Original malloc arg. */ |
|
word oh_sf; /* start flag */ |
|
} oh; |
|
/* The size of the above structure is assumed not to dealign things, */ |
|
/* and to be a multiple of the word length. */ |
|
|
|
#define DEBUG_BYTES (sizeof (oh) + sizeof (word)) |
|
#undef ROUNDED_UP_WORDS |
|
#define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1) |
|
|
|
|
|
#ifdef SAVE_CALL_CHAIN |
|
# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci) |
|
# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) |
|
#else |
|
# ifdef GC_ADD_CALLER |
|
# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra) |
|
# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) |
|
# else |
|
# define ADD_CALL_CHAIN(base, ra) |
|
# define PRINT_CALL_CHAIN(base) |
|
# endif |
|
#endif |
|
|
|
/* Check whether object with base pointer p has debugging info */ |
/* Check whether object with base pointer p has debugging info */ |
/* p is assumed to point to a legitimate object in our part */ |
/* p is assumed to point to a legitimate object in our part */ |
/* of the heap. */ |
/* of the heap. */ |
|
|
|
|
/* Store information about the object referencing dest in *base_p */ |
/* Store information about the object referencing dest in *base_p */ |
/* and *offset_p. */ |
/* and *offset_p. */ |
/* source is root ==> *base_p = 0, *offset_p = address */ |
/* source is root ==> *base_p = address, *offset_p = 0 */ |
/* source is heap object ==> *base_p != 0, *offset_p = offset */ |
/* source is heap object ==> *base_p != 0, *offset_p = offset */ |
/* Returns 1 on success, 0 if source couldn't be determined. */ |
/* Returns 1 on success, 0 if source couldn't be determined. */ |
/* Dest can be any address within a heap object. */ |
/* Dest can be any address within a heap object. */ |
|
|
if (!GC_has_debug_info((ptr_t) hdr)) return GC_NO_SPACE; |
if (!GC_has_debug_info((ptr_t) hdr)) return GC_NO_SPACE; |
bp = hdr -> oh_back_ptr; |
bp = hdr -> oh_back_ptr; |
if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD; |
if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD; |
|
if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG; |
if (0 == bp) return GC_UNREFERENCED; |
if (0 == bp) return GC_UNREFERENCED; |
bp = REVEAL_POINTER(bp); |
bp = REVEAL_POINTER(bp); |
bp_base = GC_base(bp); |
bp_base = GC_base(bp); |
|
|
} |
} |
} |
} |
|
|
/* Force a garbage collection and generate a backtrace from a */ |
/* Print back trace for p */ |
/* random heap address. */ |
void GC_print_backtrace(void *p) |
void GC_generate_random_backtrace(void) |
|
{ |
{ |
void * current; |
void *current = p; |
int i; |
int i; |
void * base; |
|
size_t offset; |
|
GC_ref_kind source; |
GC_ref_kind source; |
GC_gcollect(); |
size_t offset; |
current = GC_generate_random_valid_address(); |
void *base; |
GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current); |
|
GC_print_heap_obj(GC_base(current)); |
GC_print_heap_obj(GC_base(current)); |
GC_err_printf0("\n"); |
GC_err_printf0("\n"); |
for (i = 0; ; ++i) { |
for (i = 0; ; ++i) { |
|
|
case GC_REFD_FROM_ROOT: |
case GC_REFD_FROM_ROOT: |
GC_err_printf1("root at 0x%lx\n", (unsigned long)base); |
GC_err_printf1("root at 0x%lx\n", (unsigned long)base); |
goto out; |
goto out; |
|
case GC_REFD_FROM_REG: |
|
GC_err_printf0("root in register\n"); |
|
goto out; |
case GC_FINALIZER_REFD: |
case GC_FINALIZER_REFD: |
GC_err_printf0("list of finalizable objects\n"); |
GC_err_printf0("list of finalizable objects\n"); |
goto out; |
goto out; |
|
|
} |
} |
out:; |
out:; |
} |
} |
|
|
|
/* Force a garbage collection and generate a backtrace from a */ |
|
/* random heap address. */ |
|
void GC_generate_random_backtrace(void) |
|
{ |
|
void * current; |
|
GC_gcollect(); |
|
current = GC_generate_random_valid_address(); |
|
GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current); |
|
GC_print_backtrace(current); |
|
} |
|
|
#endif /* KEEP_BACK_PTRS */ |
#endif /* KEEP_BACK_PTRS */ |
|
|
Line 342 void GC_start_debugging() |
|
Line 305 void GC_start_debugging() |
|
GC_register_displacement((word)sizeof(oh) + offset); |
GC_register_displacement((word)sizeof(oh) + offset); |
} |
} |
|
|
# ifdef GC_ADD_CALLER |
|
# define EXTRA_ARGS word ra, char * s, int i |
|
# define OPT_RA ra, |
|
# else |
|
# define EXTRA_ARGS char * s, int i |
|
# define OPT_RA |
|
# endif |
|
|
|
# ifdef __STDC__ |
# ifdef __STDC__ |
GC_PTR GC_debug_malloc(size_t lb, EXTRA_ARGS) |
GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS) |
# else |
# else |
GC_PTR GC_debug_malloc(lb, s, i) |
GC_PTR GC_debug_malloc(lb, s, i) |
size_t lb; |
size_t lb; |
Line 380 void GC_start_debugging() |
|
Line 335 void GC_start_debugging() |
|
|
|
#ifdef STUBBORN_ALLOC |
#ifdef STUBBORN_ALLOC |
# ifdef __STDC__ |
# ifdef __STDC__ |
GC_PTR GC_debug_malloc_stubborn(size_t lb, EXTRA_ARGS) |
GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS) |
# else |
# else |
GC_PTR GC_debug_malloc_stubborn(lb, s, i) |
GC_PTR GC_debug_malloc_stubborn(lb, s, i) |
size_t lb; |
size_t lb; |
|
|
GC_end_stubborn_change(q); |
GC_end_stubborn_change(q); |
} |
} |
|
|
#endif /* STUBBORN_ALLOC */ |
#else /* !STUBBORN_ALLOC */ |
|
|
# ifdef __STDC__ |
# ifdef __STDC__ |
GC_PTR GC_debug_malloc_atomic(size_t lb, EXTRA_ARGS) |
GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS) |
# else |
# else |
|
GC_PTR GC_debug_malloc_stubborn(lb, s, i) |
|
size_t lb; |
|
char * s; |
|
int i; |
|
# endif |
|
{ |
|
return GC_debug_malloc(lb, OPT_RA s, i); |
|
} |
|
|
|
void GC_debug_change_stubborn(p) |
|
GC_PTR p; |
|
{ |
|
} |
|
|
|
void GC_debug_end_stubborn_change(p) |
|
GC_PTR p; |
|
{ |
|
} |
|
|
|
#endif /* !STUBBORN_ALLOC */ |
|
|
|
# ifdef __STDC__ |
|
GC_PTR GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS) |
|
# else |
GC_PTR GC_debug_malloc_atomic(lb, s, i) |
GC_PTR GC_debug_malloc_atomic(lb, s, i) |
size_t lb; |
size_t lb; |
char * s; |
char * s; |
|
|
} |
} |
|
|
# ifdef __STDC__ |
# ifdef __STDC__ |
GC_PTR GC_debug_malloc_uncollectable(size_t lb, EXTRA_ARGS) |
GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS) |
# else |
# else |
GC_PTR GC_debug_malloc_uncollectable(lb, s, i) |
GC_PTR GC_debug_malloc_uncollectable(lb, s, i) |
size_t lb; |
size_t lb; |
|
|
|
|
#ifdef ATOMIC_UNCOLLECTABLE |
#ifdef ATOMIC_UNCOLLECTABLE |
# ifdef __STDC__ |
# ifdef __STDC__ |
GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, EXTRA_ARGS) |
GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS) |
# else |
# else |
GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i) |
GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i) |
size_t lb; |
size_t lb; |
|
|
GC_PTR p; |
GC_PTR p; |
# endif |
# endif |
{ |
{ |
register GC_PTR base = GC_base(p); |
register GC_PTR base; |
register ptr_t clobbered; |
register ptr_t clobbered; |
|
|
|
if (0 == p) return; |
|
base = GC_base(p); |
if (base == 0) { |
if (base == 0) { |
GC_err_printf1("Attempt to free invalid pointer %lx\n", |
GC_err_printf1("Attempt to free invalid pointer %lx\n", |
(unsigned long)p); |
(unsigned long)p); |
if (p != 0) ABORT("free(invalid pointer)"); |
ABORT("free(invalid pointer)"); |
} |
} |
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { |
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { |
GC_err_printf1( |
GC_err_printf1( |
|
|
/* Invalidate size */ |
/* Invalidate size */ |
((oh *)base) -> oh_sz = GC_size(base); |
((oh *)base) -> oh_sz = GC_size(base); |
} |
} |
# ifdef FIND_LEAK |
if (GC_find_leak) { |
GC_free(base); |
GC_free(base); |
# else |
} else { |
{ |
register hdr * hhdr = HDR(p); |
register hdr * hhdr = HDR(p); |
GC_bool uncollectable = FALSE; |
GC_bool uncollectable = FALSE; |
|
|
|
if (hhdr -> hb_obj_kind == UNCOLLECTABLE) { |
if (hhdr -> hb_obj_kind == UNCOLLECTABLE) { |
uncollectable = TRUE; |
uncollectable = TRUE; |
} |
|
# ifdef ATOMIC_UNCOLLECTABLE |
|
if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) { |
|
uncollectable = TRUE; |
|
} |
|
# endif |
|
if (uncollectable) GC_free(base); |
|
} |
} |
# endif |
# ifdef ATOMIC_UNCOLLECTABLE |
|
if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) { |
|
uncollectable = TRUE; |
|
} |
|
# endif |
|
if (uncollectable) GC_free(base); |
|
} /* !GC_find_leak */ |
} |
} |
|
|
# ifdef __STDC__ |
# ifdef __STDC__ |
GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, EXTRA_ARGS) |
GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, GC_EXTRA_PARAMS) |
# else |
# else |
GC_PTR GC_debug_realloc(p, lb, s, i) |
GC_PTR GC_debug_realloc(p, lb, s, i) |
GC_PTR p; |
GC_PTR p; |