| 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; |