/* with GC_gcj_debug_kind. */ GC_PTR GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr, GC_EXTRA_PARAMS) { GC_PTR result; /* We're careful to avoid extra calls, which could */ /* confuse the backtrace. */ LOCK(); maybe_finalize(); result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind); if (result == 0) { UNLOCK(); GC_err_printf2("GC_debug_gcj_malloc(%ld, 0x%lx) returning NIL (", (unsigned long) lb, (unsigned long) ptr_to_struct_containing_descr); GC_err_puts(s); GC_err_printf1(":%ld)\n", (unsigned long)i); return(GC_oom_fn(lb)); } *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr; UNLOCK(); if (!GC_debugging_started) { GC_start_debugging(); } ADD_CALL_CHAIN(result, ra); return (GC_store_debug_info(result, (word)lb, s, (word)i)); }
/* And a debugging version of the above: */ void * GC_debug_gcj_fast_malloc(size_t lw, void * ptr_to_struct_containing_descr, GC_EXTRA_PARAMS) { GC_PTR result; size_t lb = WORDS_TO_BYTES(lw); /* We clone the code from GC_debug_gcj_malloc, so that we */ /* dont end up with extra frames on the stack, which could */ /* confuse the backtrace. */ LOCK(); maybe_finalize(); result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind); if (result == 0) { UNLOCK(); GC_err_printf2("GC_debug_gcj_fast_malloc(%ld, 0x%lx) returning NIL (", (unsigned long) lw, (unsigned long) ptr_to_struct_containing_descr); GC_err_puts(s); GC_err_printf1(":%ld)\n", (unsigned long)i); return GC_oom_fn(WORDS_TO_BYTES(lw)); } *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr; UNLOCK(); if (!GC_debugging_started) { GC_start_debugging(); } ADD_CALL_CHAIN(result, ra); return (GC_store_debug_info(result, (word)lb, s, (word)i)); }
void GC_print_obj(ptr_t p) { register oh * ohdr = (oh *)GC_base(p); GC_ASSERT(I_DONT_HOLD_LOCK()); GC_err_printf("%p (", ((ptr_t)ohdr + sizeof(oh))); GC_err_puts(ohdr -> oh_string); # ifdef SHORT_DBG_HDRS GC_err_printf(":%ld, ", (unsigned long)(ohdr -> oh_int)); # else GC_err_printf(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int), (unsigned long)(ohdr -> oh_sz)); # endif GC_print_type((ptr_t)(ohdr + 1)); GC_err_puts(")\n"); PRINT_CALL_CHAIN(ohdr); }
/* to somewhere inside an object with the debugging info. */ STATIC void GC_print_obj(ptr_t p) { oh * ohdr = (oh *)GC_base(p); GC_ASSERT(I_DONT_HOLD_LOCK()); # ifdef LINT2 if (!ohdr) ABORT("Invalid GC_print_obj argument"); # endif GC_err_printf("%p (", ((ptr_t)ohdr + sizeof(oh))); GC_err_puts(ohdr -> oh_string); # ifdef SHORT_DBG_HDRS GC_err_printf(":%d, ", GET_OH_LINENUM(ohdr)); # else GC_err_printf(":%d, sz=%lu, ", GET_OH_LINENUM(ohdr), (unsigned long)(ohdr -> oh_sz)); # endif GC_print_type((ptr_t)(ohdr + 1)); GC_err_puts(")\n"); PRINT_CALL_CHAIN(ohdr); }
void GC_print_smashed_obj(ptr_t p, ptr_t clobbered_addr) { register oh * ohdr = (oh *)GC_base(p); GC_ASSERT(I_DONT_HOLD_LOCK()); GC_err_printf("%p in object at %p(", clobbered_addr, p); if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz)) || ohdr -> oh_string == 0) { GC_err_printf("<smashed>, appr. sz = %ld)\n", (GC_size((ptr_t)ohdr) - DEBUG_BYTES)); } else { if (ohdr -> oh_string[0] == '\0') { GC_err_puts("EMPTY(smashed?)"); } else { GC_err_puts(ohdr -> oh_string); } GC_err_printf(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), (unsigned long)(ohdr -> oh_sz)); PRINT_CALL_CHAIN(ohdr); } }
GC_API void * GC_CALL GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS) { void * result = GC_malloc_atomic(lb + DEBUG_BYTES); if (result == 0) { GC_err_printf("GC_debug_malloc_atomic(%lu) returning NULL (", (unsigned long) lb); GC_err_puts(s); GC_err_printf(":%lu)\n", (unsigned long)i); return(0); } if (!GC_debugging_started) { GC_start_debugging(); } ADD_CALL_CHAIN(result, ra); return (GC_store_debug_info(result, (word)lb, s, i)); }
void * GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS) { void * result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES); if (result == 0) { GC_err_printf("GC_debug_malloc_uncollectable(%lu) returning NIL (", (unsigned long) lb); GC_err_puts(s); GC_err_printf(":%lu)\n", (unsigned long)i); return(0); } if (!GC_debugging_started) { GC_start_debugging(); } ADD_CALL_CHAIN(result, ra); return (GC_store_debug_info(result, (word)lb, s, (word)i)); }
GC_API void * GC_CALL GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS) { void * result; /* Note that according to malloc() specification, if size is 0 then */ /* malloc() returns either NULL, or a unique pointer value that can */ /* later be successfully passed to free(). We always do the latter. */ result = GC_malloc(lb + DEBUG_BYTES); if (result == 0) { GC_err_printf("GC_debug_malloc(%lu) returning NULL (", (unsigned long) lb); GC_err_puts(s); GC_err_printf(":%ld)\n", (unsigned long)i); return(0); } if (!GC_debugging_started) { GC_start_debugging(); } ADD_CALL_CHAIN(result, ra); return (GC_store_debug_info(result, (word)lb, s, i)); }
/*longPtr = proc->pr_ReturnAddr; size = longPtr[0];*/ return (char *)proc->pr_ReturnAddr + sizeof(ULONG); } else { return (char *)proc->pr_Task.tc_SPUpper; } } #if 0 /* old version */ ptr_t GC_get_stack_base() { extern struct WBStartup *_WBenchMsg; extern long __base; extern long __stack; struct Task *task; struct Process *proc; struct CommandLineInterface *cli; long size; if ((task = FindTask(0)) == 0) { GC_err_puts("Cannot find own task structure\n"); ABORT("task missing"); } proc = (struct Process *)task; cli = BADDR(proc->pr_CLI); if (_WBenchMsg != 0 || cli == 0) { size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower; } else { size = cli->cli_DefaultStack * 4; } return (ptr_t)(__base + GC_max(size, __stack)); }
/* is p. */ STATIC void GC_print_type(ptr_t p) { hdr * hhdr = GC_find_header(p); char buffer[GC_TYPE_DESCR_LEN + 1]; int kind = hhdr -> hb_obj_kind; if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) { /* This should preclude free list objects except with */ /* thread-local allocation. */ buffer[GC_TYPE_DESCR_LEN] = 0; (GC_describe_type_fns[kind])(p, buffer); GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0); GC_err_puts(buffer); } else { switch(kind) { case PTRFREE: GC_err_puts("PTRFREE"); break; case NORMAL: GC_err_puts("NORMAL"); break; case UNCOLLECTABLE: GC_err_puts("UNCOLLECTABLE"); break; # ifdef ATOMIC_UNCOLLECTABLE case AUNCOLLECTABLE: GC_err_puts("ATOMIC UNCOLLECTABLE"); break; # endif case STUBBORN: GC_err_puts("STUBBORN"); break; default: GC_err_printf("kind=%d descr=0x%lx", kind, (unsigned long)(hhdr -> hb_descr)); } } }
/* xoper hunks Shell Process */ num=0; for (data = (ULONG *)BADDR(myseglist); data != NULL; data = (ULONG *)BADDR(data[0])) { if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) || ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) { # ifdef __GNUC__ if (dataSegSize == data[-1]) { found_segment = TRUE; } # endif GC_add_roots_inner((char *)&data[1], ((char *)&data[1]) + data[-1], FALSE); } ++num; } /* for */ # ifdef __GNUC__ if (!found_segment) { ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library"); } # endif } #if 0 /* old version */ void GC_register_data_segments() { extern struct WBStartup *_WBenchMsg; struct Process *proc; struct CommandLineInterface *cli; BPTR myseglist; ULONG *data; if ( _WBenchMsg != 0 ) { if ((myseglist = _WBenchMsg->sm_Segment) == 0) { GC_err_puts("No seglist from workbench\n"); return; } } else { if ((proc = (struct Process *)FindTask(0)) == 0) { GC_err_puts("Cannot find process structure\n"); return; } if ((cli = BADDR(proc->pr_CLI)) == 0) { GC_err_puts("No CLI\n"); return; } if ((myseglist = cli->cli_Module) == 0) { GC_err_puts("No seglist from CLI\n"); return; } } for (data = (ULONG *)BADDR(myseglist); data != 0; data = (ULONG *)BADDR(data[0])) { # ifdef AMIGA_SKIP_SEG if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) || ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) { # else { # endif /* AMIGA_SKIP_SEG */ GC_add_roots_inner((char *)&data[1], ((char *)&data[1]) + data[-1], FALSE); } } } #endif /* old version */ #endif #ifdef GC_AMIGA_AM #ifndef GC_AMIGA_FASTALLOC void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)) { return (*AllocFunction)(size); } void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2)) =GC_amiga_allocwrapper; #else void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)); void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2)) =GC_amiga_allocwrapper_firsttime; /****************************************************************** Amiga-spesific routines to obtain memory, and force GC to give back fast-mem whenever possible. These hacks makes gc-programs go many times faster when the amiga is low on memory, and are therefore strictly necesarry. -Kjetil S. Matheussen, 2000. ******************************************************************/ /* List-header for all allocated memory. */ struct GC_Amiga_AllocedMemoryHeader { ULONG size; struct GC_Amiga_AllocedMemoryHeader *next; }; struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL); /* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */ ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR; /* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */ #ifndef GC_AMIGA_ONLYFAST BOOL GC_amiga_dontalloc=FALSE; #endif #ifdef GC_AMIGA_PRINTSTATS int succ=0,succ2=0; int nsucc=0,nsucc2=0; int nullretries=0; int numcollects=0; int chipa=0; int allochip=0; int allocfast=0; int cur0=0; int cur1=0; int cur10=0; int cur50=0; int cur150=0; int cur151=0; int ncur0=0; int ncur1=0; int ncur10=0; int ncur50=0; int ncur150=0; int ncur151=0; #endif /* Free everything at program-end. */ void GC_amiga_free_all_mem(void) { struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM)); struct GC_Amiga_AllocedMemoryHeader *temp; #ifdef GC_AMIGA_PRINTSTATS printf("\n\n" "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n", allochip,allocfast ); printf( "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n", chipa ); printf("\n"); printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects); printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries); printf("\n"); printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2); printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2); printf("\n"); printf( "Number of retries before succeding a chip->fast force:\n" "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n", cur0,cur1,cur10,cur50,cur150,cur151 ); printf( "Number of retries before giving up a chip->fast force:\n" "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n", ncur0,ncur1,ncur10,ncur50,ncur150,ncur151 ); #endif while(gc_am!=NULL) { temp=gc_am->next; FreeMem(gc_am,gc_am->size); gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp)); } } #ifndef GC_AMIGA_ONLYFAST /* All memory with address lower than this one is chip-mem. */ char *chipmax; /* * Allways set to the last size of memory tried to be allocated. * Needed to ensure allocation when the size is bigger than 100000. * */ size_t latestsize; #endif /* * The actual function that is called with the GET_MEM macro. * */ void *GC_amiga_get_mem(size_t size) { struct GC_Amiga_AllocedMemoryHeader *gc_am; #ifndef GC_AMIGA_ONLYFAST if(GC_amiga_dontalloc==TRUE) { // printf("rejected, size: %d, latestsize: %d\n",size,latestsize); return NULL; } // We really don't want to use chip-mem, but if we must, then as little as possible. if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL; #endif gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF); if(gc_am==NULL) return NULL; gc_am->next=GC_AMIGAMEM; gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader); GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am)); // printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize); #ifdef GC_AMIGA_PRINTSTATS if((char *)gc_am<chipmax) { allochip+=size; } else { allocfast+=size; } #endif return gc_am+1; } #ifndef GC_AMIGA_ONLYFAST /* Tries very hard to force GC to find fast-mem to return. Done recursively * to hold the rejected memory-pointers reachable from the collector in an * easy way. * */ #ifdef GC_AMIGA_RETRY void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec) { void *ret; ret=(*AllocFunction)(size); #ifdef GC_AMIGA_PRINTSTATS if((char *)ret>chipmax || ret==NULL) { if(ret==NULL) { nsucc++; nsucc2+=size; if(rec==0) ncur0++; if(rec==1) ncur1++; if(rec>1 && rec<10) ncur10++; if(rec>=10 && rec<50) ncur50++; if(rec>=50 && rec<150) ncur150++; if(rec>=150) ncur151++; } else { succ++; succ2+=size; if(rec==0) cur0++; if(rec==1) cur1++; if(rec>1 && rec<10) cur10++; if(rec>=10 && rec<50) cur50++; if(rec>=50 && rec<150) cur150++; if(rec>=150) cur151++; } } #endif if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))) { ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1); // GC_free(ret2); } return ret; }