3 /******************************************************************
5 AmigaOS-spesific routines for GC.
6 This file is normally included from os_dep.c
8 ******************************************************************/
12 #if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
26 # include <exec/exec.h>
28 # include <proto/exec.h>
29 # include <proto/dos.h>
30 # include <dos/dosextens.h>
31 # include <workbench/startup.h>
40 /******************************************************************
41 Find the base of the stack.
42 ******************************************************************/
44 ptr_t GC_get_main_stack_base()
46 struct Process *proc = (struct Process*)SysBase->ThisTask;
48 /* Reference: Amiga Guru Book Pages: 42,567,574 */
49 if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
50 && proc->pr_CLI != NULL) {
51 /* first ULONG is StackSize */
52 /*longPtr = proc->pr_ReturnAddr;
55 return (char *)proc->pr_ReturnAddr + sizeof(ULONG);
57 return (char *)proc->pr_Task.tc_SPUpper;
61 #if 0 /* old version */
62 ptr_t GC_get_stack_base()
64 extern struct WBStartup *_WBenchMsg;
69 struct CommandLineInterface *cli;
72 if ((task = FindTask(0)) == 0) {
73 GC_err_puts("Cannot find own task structure\n");
74 ABORT("task missing");
76 proc = (struct Process *)task;
77 cli = BADDR(proc->pr_CLI);
79 if (_WBenchMsg != 0 || cli == 0) {
80 size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower;
82 size = cli->cli_DefaultStack * 4;
84 return (ptr_t)(__base + GC_max(size, __stack));
93 /******************************************************************
94 Register data segments.
95 ******************************************************************/
97 void GC_register_data_segments()
100 struct CommandLineInterface *cli;
109 GC_bool found_segment = FALSE;
110 extern char __data_size[];
112 dataSegSize=__data_size+8;
113 /* Can`t find the Location of __data_size, because
114 it`s possible that is it, inside the segment. */
118 proc= (struct Process*)SysBase->ThisTask;
120 /* Reference: Amiga Guru Book Pages: 538ff,565,573
122 if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
123 if (proc->pr_CLI == NULL) {
124 myseglist = proc->pr_SegList;
126 /* ProcLoaded 'Loaded as a command: '*/
127 cli = BADDR(proc->pr_CLI);
128 myseglist = cli->cli_Module;
131 ABORT("Not a Process.");
134 if (myseglist == NULL) {
135 ABORT("Arrrgh.. can't find segments, aborting");
138 /* xoper hunks Shell Process */
141 for (data = (ULONG *)BADDR(myseglist); data != NULL;
142 data = (ULONG *)BADDR(data[0])) {
143 if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
144 ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
146 if (dataSegSize == data[-1]) {
147 found_segment = TRUE;
150 GC_add_roots_inner((char *)&data[1],
151 ((char *)&data[1]) + data[-1], FALSE);
156 if (!found_segment) {
157 ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");
162 #if 0 /* old version */
163 void GC_register_data_segments()
165 extern struct WBStartup *_WBenchMsg;
166 struct Process *proc;
167 struct CommandLineInterface *cli;
171 if ( _WBenchMsg != 0 ) {
172 if ((myseglist = _WBenchMsg->sm_Segment) == 0) {
173 GC_err_puts("No seglist from workbench\n");
177 if ((proc = (struct Process *)FindTask(0)) == 0) {
178 GC_err_puts("Cannot find process structure\n");
181 if ((cli = BADDR(proc->pr_CLI)) == 0) {
182 GC_err_puts("No CLI\n");
185 if ((myseglist = cli->cli_Module) == 0) {
186 GC_err_puts("No seglist from CLI\n");
191 for (data = (ULONG *)BADDR(myseglist); data != 0;
192 data = (ULONG *)BADDR(data[0])) {
193 # ifdef AMIGA_SKIP_SEG
194 if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
195 ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
198 # endif /* AMIGA_SKIP_SEG */
199 GC_add_roots_inner((char *)&data[1],
200 ((char *)&data[1]) + data[-1], FALSE);
204 #endif /* old version */
213 #ifndef GC_AMIGA_FASTALLOC
215 void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){
216 return (*AllocFunction)(size);
219 void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
220 =GC_amiga_allocwrapper;
227 void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2));
229 void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
230 =GC_amiga_allocwrapper_firsttime;
233 /******************************************************************
234 Amiga-spesific routines to obtain memory, and force GC to give
235 back fast-mem whenever possible.
236 These hacks makes gc-programs go many times faster when
237 the amiga is low on memory, and are therefore strictly necesarry.
239 -Kjetil S. Matheussen, 2000.
240 ******************************************************************/
244 /* List-header for all allocated memory. */
246 struct GC_Amiga_AllocedMemoryHeader{
248 struct GC_Amiga_AllocedMemoryHeader *next;
250 struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL);
254 /* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */
256 ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR;
259 /* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */
260 #ifndef GC_AMIGA_ONLYFAST
261 BOOL GC_amiga_dontalloc=FALSE;
264 #ifdef GC_AMIGA_PRINTSTATS
266 int nsucc=0,nsucc2=0;
286 /* Free everything at program-end. */
288 void GC_amiga_free_all_mem(void){
289 struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
290 struct GC_Amiga_AllocedMemoryHeader *temp;
292 #ifdef GC_AMIGA_PRINTSTATS
294 "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n",
298 "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
302 printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
303 printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
305 printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
306 printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
309 "Number of retries before succeding a chip->fast force:\n"
310 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
311 cur0,cur1,cur10,cur50,cur150,cur151
314 "Number of retries before giving up a chip->fast force:\n"
315 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
316 ncur0,ncur1,ncur10,ncur50,ncur150,ncur151
322 FreeMem(gc_am,gc_am->size);
323 gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
327 #ifndef GC_AMIGA_ONLYFAST
329 /* All memory with address lower than this one is chip-mem. */
335 * Allways set to the last size of memory tried to be allocated.
336 * Needed to ensure allocation when the size is bigger than 100000.
345 * The actual function that is called with the GET_MEM macro.
349 void *GC_amiga_get_mem(size_t size){
350 struct GC_Amiga_AllocedMemoryHeader *gc_am;
352 #ifndef GC_AMIGA_ONLYFAST
353 if(GC_amiga_dontalloc==TRUE){
354 // printf("rejected, size: %d, latestsize: %d\n",size,latestsize);
358 // We really don't want to use chip-mem, but if we must, then as little as possible.
359 if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
362 gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF);
363 if(gc_am==NULL) return NULL;
365 gc_am->next=GC_AMIGAMEM;
366 gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
367 GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
369 // printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize);
371 #ifdef GC_AMIGA_PRINTSTATS
372 if((char *)gc_am<chipmax){
386 #ifndef GC_AMIGA_ONLYFAST
388 /* Tries very hard to force GC to find fast-mem to return. Done recursively
389 * to hold the rejected memory-pointers reachable from the collector in an
393 #ifdef GC_AMIGA_RETRY
394 void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec){
397 ret=(*AllocFunction)(size);
399 #ifdef GC_AMIGA_PRINTSTATS
400 if((char *)ret>chipmax || ret==NULL){
406 if(rec>1 && rec<10) ncur10++;
407 if(rec>=10 && rec<50) ncur50++;
408 if(rec>=50 && rec<150) ncur150++;
409 if(rec>=150) ncur151++;
415 if(rec>1 && rec<10) cur10++;
416 if(rec>=10 && rec<50) cur50++;
417 if(rec>=50 && rec<150) cur150++;
418 if(rec>=150) cur151++;
423 if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
424 ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
433 /* The allocating-functions defined inside the amiga-blocks in gc.h is called
434 * via these functions.
438 void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
441 GC_amiga_dontalloc=TRUE; // Pretty tough thing to do, but its indeed necesarry.
444 ret=(*AllocFunction)(size);
446 if(((char *)ret) <= chipmax){
448 //Give GC access to allocate memory.
452 #ifdef GC_AMIGA_PRINTSTATS
455 ret=(*AllocFunction)(size);
459 GC_amiga_dontalloc=FALSE;
460 ret=(*AllocFunction)(size);
462 WARN("Out of Memory! Returning NIL!\n", 0);
465 #ifdef GC_AMIGA_PRINTSTATS
469 if(ret!=NULL && (char *)ret<=chipmax) chipa+=size;
472 #ifdef GC_AMIGA_RETRY
474 /* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
475 /* Using gctest to check the effectiviness of doing this, does seldom give a very good result. */
476 /* However, real programs doesn't normally rapidly allocate and deallocate. */
477 // printf("trying to force... %d bytes... ",size);
479 AllocFunction!=GC_malloc_uncollectable
480 #ifdef ATOMIC_UNCOLLECTABLE
481 && AllocFunction!=GC_malloc_atomic_uncollectable
484 ret2=GC_amiga_rec_alloc(size,AllocFunction,0);
486 ret2=(*AllocFunction)(size);
487 #ifdef GC_AMIGA_PRINTSTATS
488 if((char *)ret2<chipmax || ret2==NULL){
499 if(((char *)ret2)>chipmax){
500 // printf("Succeeded.\n");
505 // printf("But did not succeed.\n");
511 GC_amiga_dontalloc=FALSE;
518 void (*GC_amiga_toany)(void)=NULL;
520 void GC_amiga_set_toany(void (*func)(void)){
524 #endif // !GC_AMIGA_ONLYFAST
527 void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
530 ret=(*AllocFunction)(size);
533 // Enable chip-mem allocation.
534 // printf("ret==NULL\n");
538 #ifdef GC_AMIGA_PRINTSTATS
541 ret=(*AllocFunction)(size);
545 #ifndef GC_AMIGA_ONLYFAST
546 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
547 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
548 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
549 return GC_amiga_allocwrapper_any(size,AllocFunction);
552 #ifdef GC_AMIGA_PRINTSTATS
562 void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
563 atexit(&GC_amiga_free_all_mem);
564 chipmax=(char *)SysBase->MaxLocMem; // For people still having SysBase in chip-mem, this might speed up a bit.
565 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
566 return GC_amiga_allocwrapper_fast(size,AllocFunction);
570 #endif //GC_AMIGA_FASTALLOC
575 * The wrapped realloc function.
578 void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
579 #ifndef GC_AMIGA_FASTALLOC
580 return GC_realloc(old_object,new_size_in_bytes);
583 latestsize=new_size_in_bytes;
584 ret=GC_realloc(old_object,new_size_in_bytes);
585 if(ret==NULL && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
586 /* Out of fast-mem. */
590 #ifdef GC_AMIGA_PRINTSTATS
593 ret=GC_realloc(old_object,new_size_in_bytes);
597 #ifndef GC_AMIGA_ONLYFAST
598 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
599 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
600 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
601 ret=GC_realloc(old_object,new_size_in_bytes);
604 #ifdef GC_AMIGA_PRINTSTATS
611 WARN("Out of Memory! Returning NIL!\n", 0);
613 #ifdef GC_AMIGA_PRINTSTATS
614 if(((char *)ret)<chipmax && ret!=NULL){
615 chipa+=new_size_in_bytes;