|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM) |
|
# include "gc_priv.h" |
|
# include <stdio.h> |
|
# include <signal.h> |
|
# define GC_AMIGA_DEF |
|
# define GC_AMIGA_SB |
|
# define GC_AMIGA_DS |
|
# define GC_AMIGA_AM |
|
#endif |
|
|
|
|
|
#ifdef GC_AMIGA_DEF |
|
|
|
# ifndef __GNUC__ |
|
# include <exec/exec.h> |
|
# endif |
|
# include <proto/exec.h> |
|
# include <proto/dos.h> |
|
# include <dos/dosextens.h> |
|
# include <workbench/startup.h> |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#ifdef GC_AMIGA_SB |
|
|
|
|
|
|
|
|
|
|
|
ptr_t GC_get_main_stack_base() |
|
{ |
|
struct Process *proc = (struct Process*)SysBase->ThisTask; |
|
|
|
|
|
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS |
|
&& proc->pr_CLI != NULL) { |
|
|
|
|
|
|
|
|
|
return (char *)proc->pr_ReturnAddr + sizeof(ULONG); |
|
} else { |
|
return (char *)proc->pr_Task.tc_SPUpper; |
|
} |
|
} |
|
|
|
#if 0 |
|
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)); |
|
} |
|
#endif |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef GC_AMIGA_DS |
|
|
|
|
|
|
|
|
|
void GC_register_data_segments() |
|
{ |
|
struct Process *proc; |
|
struct CommandLineInterface *cli; |
|
BPTR myseglist; |
|
ULONG *data; |
|
|
|
int num; |
|
|
|
|
|
# ifdef __GNUC__ |
|
ULONG dataSegSize; |
|
GC_bool found_segment = FALSE; |
|
extern char __data_size[]; |
|
|
|
dataSegSize=__data_size+8; |
|
|
|
|
|
|
|
# endif |
|
|
|
proc= (struct Process*)SysBase->ThisTask; |
|
|
|
|
|
|
|
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) { |
|
if (proc->pr_CLI == NULL) { |
|
myseglist = proc->pr_SegList; |
|
} else { |
|
|
|
cli = BADDR(proc->pr_CLI); |
|
myseglist = cli->cli_Module; |
|
} |
|
} else { |
|
ABORT("Not a Process."); |
|
} |
|
|
|
if (myseglist == NULL) { |
|
ABORT("Arrrgh.. can't find segments, aborting"); |
|
} |
|
|
|
|
|
|
|
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; |
|
} |
|
# ifdef __GNUC__ |
|
if (!found_segment) { |
|
ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library"); |
|
} |
|
# endif |
|
} |
|
|
|
#if 0 |
|
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 |
|
GC_add_roots_inner((char *)&data[1], |
|
((char *)&data[1]) + data[-1], FALSE); |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
|
|
#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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct GC_Amiga_AllocedMemoryHeader{ |
|
ULONG size; |
|
struct GC_Amiga_AllocedMemoryHeader *next; |
|
}; |
|
struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL); |
|
|
|
|
|
|
|
|
|
|
|
ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR; |
|
|
|
|
|
|
|
#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 |
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
char *chipmax; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t latestsize; |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void *GC_amiga_get_mem(size_t size){ |
|
struct GC_Amiga_AllocedMemoryHeader *gc_am; |
|
|
|
#ifndef GC_AMIGA_ONLYFAST |
|
if(GC_amiga_dontalloc==TRUE){ |
|
|
|
return NULL; |
|
} |
|
|
|
|
|
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)); |
|
|
|
|
|
|
|
#ifdef GC_AMIGA_PRINTSTATS |
|
if((char *)gc_am<chipmax){ |
|
allochip+=size; |
|
}else{ |
|
allocfast+=size; |
|
} |
|
#endif |
|
|
|
return gc_am+1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifndef GC_AMIGA_ONLYFAST |
|
|
|
|
|
|
|
|
|
|
|
|
|
#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); |
|
|
|
} |
|
|
|
return ret; |
|
} |
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){ |
|
void *ret,*ret2; |
|
|
|
GC_amiga_dontalloc=TRUE; |
|
latestsize=size; |
|
|
|
ret=(*AllocFunction)(size); |
|
|
|
if(((char *)ret) <= chipmax){ |
|
if(ret==NULL){ |
|
|
|
#ifdef GC_AMIGA_GC |
|
if(!GC_dont_gc){ |
|
GC_gcollect(); |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
numcollects++; |
|
#endif |
|
ret=(*AllocFunction)(size); |
|
} |
|
#endif |
|
if(ret==NULL){ |
|
GC_amiga_dontalloc=FALSE; |
|
ret=(*AllocFunction)(size); |
|
if(ret==NULL){ |
|
WARN("Out of Memory! Returning NIL!\n", 0); |
|
} |
|
} |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
else{ |
|
nullretries++; |
|
} |
|
if(ret!=NULL && (char *)ret<=chipmax) chipa+=size; |
|
#endif |
|
} |
|
#ifdef GC_AMIGA_RETRY |
|
else{ |
|
|
|
|
|
|
|
|
|
if( |
|
AllocFunction!=GC_malloc_uncollectable |
|
#ifdef ATOMIC_UNCOLLECTABLE |
|
&& AllocFunction!=GC_malloc_atomic_uncollectable |
|
#endif |
|
){ |
|
ret2=GC_amiga_rec_alloc(size,AllocFunction,0); |
|
}else{ |
|
ret2=(*AllocFunction)(size); |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
if((char *)ret2<chipmax || ret2==NULL){ |
|
nsucc++; |
|
nsucc2+=size; |
|
ncur0++; |
|
}else{ |
|
succ++; |
|
succ2+=size; |
|
cur0++; |
|
} |
|
#endif |
|
} |
|
if(((char *)ret2)>chipmax){ |
|
|
|
GC_free(ret); |
|
ret=ret2; |
|
}else{ |
|
GC_free(ret2); |
|
|
|
} |
|
} |
|
#endif |
|
} |
|
|
|
GC_amiga_dontalloc=FALSE; |
|
|
|
return ret; |
|
} |
|
|
|
|
|
|
|
void (*GC_amiga_toany)(void)=NULL; |
|
|
|
void GC_amiga_set_toany(void (*func)(void)){ |
|
GC_amiga_toany=func; |
|
} |
|
|
|
#endif |
|
|
|
|
|
void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){ |
|
void *ret; |
|
|
|
ret=(*AllocFunction)(size); |
|
|
|
if(ret==NULL){ |
|
|
|
|
|
#ifdef GC_AMIGA_GC |
|
if(!GC_dont_gc){ |
|
GC_gcollect(); |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
numcollects++; |
|
#endif |
|
ret=(*AllocFunction)(size); |
|
} |
|
#endif |
|
if(ret==NULL){ |
|
#ifndef GC_AMIGA_ONLYFAST |
|
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR; |
|
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)(); |
|
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any; |
|
return GC_amiga_allocwrapper_any(size,AllocFunction); |
|
#endif |
|
} |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
else{ |
|
nullretries++; |
|
} |
|
#endif |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){ |
|
atexit(&GC_amiga_free_all_mem); |
|
chipmax=(char *)SysBase->MaxLocMem; |
|
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast; |
|
return GC_amiga_allocwrapper_fast(size,AllocFunction); |
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){ |
|
#ifndef GC_AMIGA_FASTALLOC |
|
return GC_realloc(old_object,new_size_in_bytes); |
|
#else |
|
void *ret; |
|
latestsize=new_size_in_bytes; |
|
ret=GC_realloc(old_object,new_size_in_bytes); |
|
if(ret==NULL && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){ |
|
|
|
#ifdef GC_AMIGA_GC |
|
if(!GC_dont_gc){ |
|
GC_gcollect(); |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
numcollects++; |
|
#endif |
|
ret=GC_realloc(old_object,new_size_in_bytes); |
|
} |
|
#endif |
|
if(ret==NULL){ |
|
#ifndef GC_AMIGA_ONLYFAST |
|
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR; |
|
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)(); |
|
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any; |
|
ret=GC_realloc(old_object,new_size_in_bytes); |
|
#endif |
|
} |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
else{ |
|
nullretries++; |
|
} |
|
#endif |
|
} |
|
if(ret==NULL){ |
|
WARN("Out of Memory! Returning NIL!\n", 0); |
|
} |
|
#ifdef GC_AMIGA_PRINTSTATS |
|
if(((char *)ret)<chipmax && ret!=NULL){ |
|
chipa+=new_size_in_bytes; |
|
} |
|
#endif |
|
return ret; |
|
#endif |
|
} |
|
|
|
#endif |
|
|
|
|
|
|