3 /******************************************************************
5 AmigaOS-spesific routines for GC.
6 This file is normally included from os_dep.c
8 ******************************************************************/
11 #if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
25 # include <exec/exec.h>
27 # include <proto/exec.h>
28 # include <proto/dos.h>
29 # include <dos/dosextens.h>
30 # include <workbench/startup.h>
39 /******************************************************************
40 Find the base of the stack.
41 ******************************************************************/
43 ptr_t
GC_get_stack_base()
45 struct Process
*proc
= (struct Process
*)SysBase
->ThisTask
;
47 /* Reference: Amiga Guru Book Pages: 42,567,574 */
48 if (proc
->pr_Task
.tc_Node
.ln_Type
==NT_PROCESS
49 && proc
->pr_CLI
!= NULL
) {
50 /* first ULONG is StackSize */
51 /*longPtr = proc->pr_ReturnAddr;
54 return (char *)proc
->pr_ReturnAddr
+ sizeof(ULONG
);
56 return (char *)proc
->pr_Task
.tc_SPUpper
;
60 #if 0 /* old version */
61 ptr_t
GC_get_stack_base()
63 extern struct WBStartup
*_WBenchMsg
;
68 struct CommandLineInterface
*cli
;
71 if ((task
= FindTask(0)) == 0) {
72 GC_err_puts("Cannot find own task structure\n");
73 ABORT("task missing");
75 proc
= (struct Process
*)task
;
76 cli
= BADDR(proc
->pr_CLI
);
78 if (_WBenchMsg
!= 0 || cli
== 0) {
79 size
= (char *)task
->tc_SPUpper
- (char *)task
->tc_SPLower
;
81 size
= cli
->cli_DefaultStack
* 4;
83 return (ptr_t
)(__base
+ GC_max(size
, __stack
));
92 /******************************************************************
93 Register data segments.
94 ******************************************************************/
96 void GC_register_data_segments()
99 struct CommandLineInterface
*cli
;
108 GC_bool found_segment
= FALSE
;
109 extern char __data_size
[];
111 dataSegSize
=__data_size
+8;
112 /* Can`t find the Location of __data_size, because
113 it`s possible that is it, inside the segment. */
117 proc
= (struct Process
*)SysBase
->ThisTask
;
119 /* Reference: Amiga Guru Book Pages: 538ff,565,573
121 if (proc
->pr_Task
.tc_Node
.ln_Type
==NT_PROCESS
) {
122 if (proc
->pr_CLI
== NULL
) {
123 myseglist
= proc
->pr_SegList
;
125 /* ProcLoaded 'Loaded as a command: '*/
126 cli
= BADDR(proc
->pr_CLI
);
127 myseglist
= cli
->cli_Module
;
130 ABORT("Not a Process.");
133 if (myseglist
== NULL
) {
134 ABORT("Arrrgh.. can't find segments, aborting");
137 /* xoper hunks Shell Process */
140 for (data
= (ULONG
*)BADDR(myseglist
); data
!= NULL
;
141 data
= (ULONG
*)BADDR(data
[0])) {
142 if (((ULONG
) GC_register_data_segments
< (ULONG
) &data
[1]) ||
143 ((ULONG
) GC_register_data_segments
> (ULONG
) &data
[1] + data
[-1])) {
145 if (dataSegSize
== data
[-1]) {
146 found_segment
= TRUE
;
149 GC_add_roots_inner((char *)&data
[1],
150 ((char *)&data
[1]) + data
[-1], FALSE
);
155 if (!found_segment
) {
156 ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");
161 #if 0 /* old version */
162 void GC_register_data_segments()
164 extern struct WBStartup
*_WBenchMsg
;
165 struct Process
*proc
;
166 struct CommandLineInterface
*cli
;
170 if ( _WBenchMsg
!= 0 ) {
171 if ((myseglist
= _WBenchMsg
->sm_Segment
) == 0) {
172 GC_err_puts("No seglist from workbench\n");
176 if ((proc
= (struct Process
*)FindTask(0)) == 0) {
177 GC_err_puts("Cannot find process structure\n");
180 if ((cli
= BADDR(proc
->pr_CLI
)) == 0) {
181 GC_err_puts("No CLI\n");
184 if ((myseglist
= cli
->cli_Module
) == 0) {
185 GC_err_puts("No seglist from CLI\n");
190 for (data
= (ULONG
*)BADDR(myseglist
); data
!= 0;
191 data
= (ULONG
*)BADDR(data
[0])) {
192 # ifdef AMIGA_SKIP_SEG
193 if (((ULONG
) GC_register_data_segments
< (ULONG
) &data
[1]) ||
194 ((ULONG
) GC_register_data_segments
> (ULONG
) &data
[1] + data
[-1])) {
197 # endif /* AMIGA_SKIP_SEG */
198 GC_add_roots_inner((char *)&data
[1],
199 ((char *)&data
[1]) + data
[-1], FALSE
);
203 #endif /* old version */
212 #ifndef GC_AMIGA_FASTALLOC
214 void *GC_amiga_allocwrapper(size_t size
,void *(*AllocFunction
)(size_t size2
)){
215 return (*AllocFunction
)(size
);
218 void *(*GC_amiga_allocwrapper_do
)(size_t size
,void *(*AllocFunction
)(size_t size2
))
219 =GC_amiga_allocwrapper
;
226 void *GC_amiga_allocwrapper_firsttime(size_t size
,void *(*AllocFunction
)(size_t size2
));
228 void *(*GC_amiga_allocwrapper_do
)(size_t size
,void *(*AllocFunction
)(size_t size2
))
229 =GC_amiga_allocwrapper_firsttime
;
232 /******************************************************************
233 Amiga-spesific routines to obtain memory, and force GC to give
234 back fast-mem whenever possible.
235 These hacks makes gc-programs go many times faster when
236 the amiga is low on memory, and are therefore strictly necesarry.
238 -Kjetil S. Matheussen, 2000.
239 ******************************************************************/
243 /* List-header for all allocated memory. */
245 struct GC_Amiga_AllocedMemoryHeader
{
247 struct GC_Amiga_AllocedMemoryHeader
*next
;
249 struct GC_Amiga_AllocedMemoryHeader
*GC_AMIGAMEM
=(struct GC_Amiga_AllocedMemoryHeader
*)(int)~(NULL
);
253 /* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */
255 ULONG GC_AMIGA_MEMF
= MEMF_FAST
| MEMF_CLEAR
;
258 /* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */
259 #ifndef GC_AMIGA_ONLYFAST
260 BOOL GC_amiga_dontalloc
=FALSE
;
263 #ifdef GC_AMIGA_PRINTSTATS
265 int nsucc
=0,nsucc2
=0;
285 /* Free everything at program-end. */
287 void GC_amiga_free_all_mem(void){
288 struct GC_Amiga_AllocedMemoryHeader
*gc_am
=(struct GC_Amiga_AllocedMemoryHeader
*)(~(int)(GC_AMIGAMEM
));
289 struct GC_Amiga_AllocedMemoryHeader
*temp
;
291 #ifdef GC_AMIGA_PRINTSTATS
293 "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n",
297 "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
301 printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects
);
302 printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries
);
304 printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ
,succ2
);
305 printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc
,nsucc2
);
308 "Number of retries before succeding a chip->fast force:\n"
309 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
310 cur0
,cur1
,cur10
,cur50
,cur150
,cur151
313 "Number of retries before giving up a chip->fast force:\n"
314 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
315 ncur0
,ncur1
,ncur10
,ncur50
,ncur150
,ncur151
321 FreeMem(gc_am
,gc_am
->size
);
322 gc_am
=(struct GC_Amiga_AllocedMemoryHeader
*)(~(int)(temp
));
326 #ifndef GC_AMIGA_ONLYFAST
328 /* All memory with address lower than this one is chip-mem. */
334 * Allways set to the last size of memory tried to be allocated.
335 * Needed to ensure allocation when the size is bigger than 100000.
344 * The actual function that is called with the GET_MEM macro.
348 void *GC_amiga_get_mem(size_t size
){
349 struct GC_Amiga_AllocedMemoryHeader
*gc_am
;
351 #ifndef GC_AMIGA_ONLYFAST
352 if(GC_amiga_dontalloc
==TRUE
){
353 // printf("rejected, size: %d, latestsize: %d\n",size,latestsize);
357 // We really don't want to use chip-mem, but if we must, then as little as possible.
358 if(GC_AMIGA_MEMF
==(MEMF_ANY
|MEMF_CLEAR
) && size
>100000 && latestsize
<50000) return NULL
;
361 gc_am
=AllocMem((ULONG
)(size
+ sizeof(struct GC_Amiga_AllocedMemoryHeader
)),GC_AMIGA_MEMF
);
362 if(gc_am
==NULL
) return NULL
;
364 gc_am
->next
=GC_AMIGAMEM
;
365 gc_am
->size
=size
+ sizeof(struct GC_Amiga_AllocedMemoryHeader
);
366 GC_AMIGAMEM
=(struct GC_Amiga_AllocedMemoryHeader
*)(~(int)(gc_am
));
368 // printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize);
370 #ifdef GC_AMIGA_PRINTSTATS
371 if((char *)gc_am
<chipmax
){
385 #ifndef GC_AMIGA_ONLYFAST
387 /* Tries very hard to force GC to find fast-mem to return. Done recursively
388 * to hold the rejected memory-pointers reachable from the collector in an
392 #ifdef GC_AMIGA_RETRY
393 void *GC_amiga_rec_alloc(size_t size
,void *(*AllocFunction
)(size_t size2
),const int rec
){
396 ret
=(*AllocFunction
)(size
);
398 #ifdef GC_AMIGA_PRINTSTATS
399 if((char *)ret
>chipmax
|| ret
==NULL
){
405 if(rec
>1 && rec
<10) ncur10
++;
406 if(rec
>=10 && rec
<50) ncur50
++;
407 if(rec
>=50 && rec
<150) ncur150
++;
408 if(rec
>=150) ncur151
++;
414 if(rec
>1 && rec
<10) cur10
++;
415 if(rec
>=10 && rec
<50) cur50
++;
416 if(rec
>=50 && rec
<150) cur150
++;
417 if(rec
>=150) cur151
++;
422 if (((char *)ret
)<=chipmax
&& ret
!=NULL
&& (rec
<(size
>500000?9:size
/5000))){
423 ret
=GC_amiga_rec_alloc(size
,AllocFunction
,rec
+1);
432 /* The allocating-functions defined inside the amiga-blocks in gc.h is called
433 * via these functions.
437 void *GC_amiga_allocwrapper_any(size_t size
,void *(*AllocFunction
)(size_t size2
)){
440 GC_amiga_dontalloc
=TRUE
; // Pretty tough thing to do, but its indeed necesarry.
443 ret
=(*AllocFunction
)(size
);
445 if(((char *)ret
) <= chipmax
){
447 //Give GC access to allocate memory.
451 #ifdef GC_AMIGA_PRINTSTATS
454 ret
=(*AllocFunction
)(size
);
458 GC_amiga_dontalloc
=FALSE
;
459 ret
=(*AllocFunction
)(size
);
461 WARN("Out of Memory! Returning NIL!\n", 0);
464 #ifdef GC_AMIGA_PRINTSTATS
468 if(ret
!=NULL
&& (char *)ret
<=chipmax
) chipa
+=size
;
471 #ifdef GC_AMIGA_RETRY
473 /* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
474 /* Using gctest to check the effectiviness of doing this, does seldom give a very good result. */
475 /* However, real programs doesn't normally rapidly allocate and deallocate. */
476 // printf("trying to force... %d bytes... ",size);
478 AllocFunction
!=GC_malloc_uncollectable
479 #ifdef ATOMIC_UNCOLLECTABLE
480 && AllocFunction
!=GC_malloc_atomic_uncollectable
483 ret2
=GC_amiga_rec_alloc(size
,AllocFunction
,0);
485 ret2
=(*AllocFunction
)(size
);
486 #ifdef GC_AMIGA_PRINTSTATS
487 if((char *)ret2
<chipmax
|| ret2
==NULL
){
498 if(((char *)ret2
)>chipmax
){
499 // printf("Succeeded.\n");
504 // printf("But did not succeed.\n");
510 GC_amiga_dontalloc
=FALSE
;
517 void (*GC_amiga_toany
)(void)=NULL
;
519 void GC_amiga_set_toany(void (*func
)(void)){
523 #endif // !GC_AMIGA_ONLYFAST
526 void *GC_amiga_allocwrapper_fast(size_t size
,void *(*AllocFunction
)(size_t size2
)){
529 ret
=(*AllocFunction
)(size
);
532 // Enable chip-mem allocation.
533 // printf("ret==NULL\n");
537 #ifdef GC_AMIGA_PRINTSTATS
540 ret
=(*AllocFunction
)(size
);
544 #ifndef GC_AMIGA_ONLYFAST
545 GC_AMIGA_MEMF
=MEMF_ANY
| MEMF_CLEAR
;
546 if(GC_amiga_toany
!=NULL
) (*GC_amiga_toany
)();
547 GC_amiga_allocwrapper_do
=GC_amiga_allocwrapper_any
;
548 return GC_amiga_allocwrapper_any(size
,AllocFunction
);
551 #ifdef GC_AMIGA_PRINTSTATS
561 void *GC_amiga_allocwrapper_firsttime(size_t size
,void *(*AllocFunction
)(size_t size2
)){
562 atexit(&GC_amiga_free_all_mem
);
563 chipmax
=(char *)SysBase
->MaxLocMem
; // For people still having SysBase in chip-mem, this might speed up a bit.
564 GC_amiga_allocwrapper_do
=GC_amiga_allocwrapper_fast
;
565 return GC_amiga_allocwrapper_fast(size
,AllocFunction
);
569 #endif //GC_AMIGA_FASTALLOC
574 * The wrapped realloc function.
577 void *GC_amiga_realloc(void *old_object
,size_t new_size_in_bytes
){
578 #ifndef GC_AMIGA_FASTALLOC
579 return GC_realloc(old_object
,new_size_in_bytes
);
582 latestsize
=new_size_in_bytes
;
583 ret
=GC_realloc(old_object
,new_size_in_bytes
);
584 if(ret
==NULL
&& GC_AMIGA_MEMF
==(MEMF_FAST
| MEMF_CLEAR
)){
585 /* Out of fast-mem. */
589 #ifdef GC_AMIGA_PRINTSTATS
592 ret
=GC_realloc(old_object
,new_size_in_bytes
);
596 #ifndef GC_AMIGA_ONLYFAST
597 GC_AMIGA_MEMF
=MEMF_ANY
| MEMF_CLEAR
;
598 if(GC_amiga_toany
!=NULL
) (*GC_amiga_toany
)();
599 GC_amiga_allocwrapper_do
=GC_amiga_allocwrapper_any
;
600 ret
=GC_realloc(old_object
,new_size_in_bytes
);
603 #ifdef GC_AMIGA_PRINTSTATS
610 WARN("Out of Memory! Returning NIL!\n", 0);
612 #ifdef GC_AMIGA_PRINTSTATS
613 if(((char *)ret
)<chipmax
&& ret
!=NULL
){
614 chipa
+=new_size_in_bytes
;