1
2
3 /******************************************************************
4
5 AmigaOS-specific routines for GC.
6 This file is normally included from os_dep.c
7
8 ******************************************************************/
9
10
11 #if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
12 # include "private/gc_priv.h"
13 # include <stdio.h>
14 # include <signal.h>
15 # define GC_AMIGA_DEF
16 # define GC_AMIGA_SB
17 # define GC_AMIGA_DS
18 # define GC_AMIGA_AM
19 #endif
20
21
22 #ifdef GC_AMIGA_DEF
23
24 # ifndef __GNUC__
25 # include <exec/exec.h>
26 # endif
27 # include <proto/exec.h>
28 # include <proto/dos.h>
29 # include <dos/dosextens.h>
30 # include <workbench/startup.h>
31
32 #endif
33
34
35
36
37 #ifdef GC_AMIGA_SB
38
39 /******************************************************************
40 Find the base of the stack.
41 ******************************************************************/
42
GC_get_main_stack_base(void)43 ptr_t GC_get_main_stack_base(void)
44 {
45 struct Process *proc = (struct Process*)SysBase->ThisTask;
46
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;
52 size = longPtr[0];*/
53
54 return (char *)proc->pr_ReturnAddr + sizeof(ULONG);
55 } else {
56 return (char *)proc->pr_Task.tc_SPUpper;
57 }
58 }
59
60 #endif
61
62
63 #ifdef GC_AMIGA_DS
64 /******************************************************************
65 Register data segments.
66 ******************************************************************/
67
GC_register_data_segments(void)68 void GC_register_data_segments(void)
69 {
70 struct Process *proc;
71 struct CommandLineInterface *cli;
72 BPTR myseglist;
73 ULONG *data;
74
75 # ifdef __GNUC__
76 ULONG dataSegSize;
77 GC_bool found_segment = FALSE;
78 extern char __data_size[];
79
80 dataSegSize=__data_size+8;
81 /* Can`t find the Location of __data_size, because
82 it`s possible that is it, inside the segment. */
83
84 # endif
85
86 proc= (struct Process*)SysBase->ThisTask;
87
88 /* Reference: Amiga Guru Book Pages: 538ff,565,573
89 and XOper.asm */
90 myseglist = proc->pr_SegList;
91 if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
92 if (proc->pr_CLI != NULL) {
93 /* ProcLoaded 'Loaded as a command: '*/
94 cli = BADDR(proc->pr_CLI);
95 myseglist = cli->cli_Module;
96 }
97 } else {
98 ABORT("Not a Process.");
99 }
100
101 if (myseglist == NULL) {
102 ABORT("Arrrgh.. can't find segments, aborting");
103 }
104
105 /* xoper hunks Shell Process */
106
107 for (data = (ULONG *)BADDR(myseglist); data != NULL;
108 data = (ULONG *)BADDR(data[0])) {
109 if ((ULONG)GC_register_data_segments < (ULONG)(&data[1])
110 || (ULONG)GC_register_data_segments > (ULONG)(&data[1])
111 + data[-1]) {
112 # ifdef __GNUC__
113 if (dataSegSize == data[-1]) {
114 found_segment = TRUE;
115 }
116 # endif
117 GC_add_roots_inner((char *)&data[1],
118 ((char *)&data[1]) + data[-1], FALSE);
119 }
120 } /* for */
121 # ifdef __GNUC__
122 if (!found_segment) {
123 ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");
124 }
125 # endif
126 }
127
128 #endif
129
130
131
132 #ifdef GC_AMIGA_AM
133
134 #ifndef GC_AMIGA_FASTALLOC
135
GC_amiga_allocwrapper(size_t size,void * (* AllocFunction)(size_t size2))136 void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){
137 return (*AllocFunction)(size);
138 }
139
140 void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
141 =GC_amiga_allocwrapper;
142
143 #else
144
145
146
147
148 void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2));
149
150 void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
151 =GC_amiga_allocwrapper_firsttime;
152
153
154 /******************************************************************
155 Amiga-specific routines to obtain memory, and force GC to give
156 back fast-mem whenever possible.
157 These hacks makes gc-programs go many times faster when
158 the Amiga is low on memory, and are therefore strictly necessary.
159
160 -Kjetil S. Matheussen, 2000.
161 ******************************************************************/
162
163
164
165 /* List-header for all allocated memory. */
166
167 struct GC_Amiga_AllocedMemoryHeader{
168 ULONG size;
169 struct GC_Amiga_AllocedMemoryHeader *next;
170 };
171 struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL);
172
173
174
175 /* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */
176
177 ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR;
178
179
180 /* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */
181 #ifndef GC_AMIGA_ONLYFAST
182 BOOL GC_amiga_dontalloc=FALSE;
183 #endif
184
185 #ifdef GC_AMIGA_PRINTSTATS
186 int succ=0,succ2=0;
187 int nsucc=0,nsucc2=0;
188 int nullretries=0;
189 int numcollects=0;
190 int chipa=0;
191 int allochip=0;
192 int allocfast=0;
193 int cur0=0;
194 int cur1=0;
195 int cur10=0;
196 int cur50=0;
197 int cur150=0;
198 int cur151=0;
199 int ncur0=0;
200 int ncur1=0;
201 int ncur10=0;
202 int ncur50=0;
203 int ncur150=0;
204 int ncur151=0;
205 #endif
206
207 /* Free everything at program-end. */
208
GC_amiga_free_all_mem(void)209 void GC_amiga_free_all_mem(void){
210 struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
211
212 #ifdef GC_AMIGA_PRINTSTATS
213 printf("\n\n"
214 "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n",
215 allochip,allocfast
216 );
217 printf(
218 "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
219 chipa
220 );
221 printf("\n");
222 printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
223 printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
224 printf("\n");
225 printf("Succeeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
226 printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
227 printf("\n");
228 printf(
229 "Number of retries before succeeding a chip->fast force:\n"
230 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
231 cur0,cur1,cur10,cur50,cur150,cur151
232 );
233 printf(
234 "Number of retries before giving up a chip->fast force:\n"
235 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
236 ncur0,ncur1,ncur10,ncur50,ncur150,ncur151
237 );
238 #endif
239
240 while(gc_am!=NULL){
241 struct GC_Amiga_AllocedMemoryHeader *temp = gc_am->next;
242 FreeMem(gc_am,gc_am->size);
243 gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
244 }
245 }
246
247 #ifndef GC_AMIGA_ONLYFAST
248
249 /* All memory with address lower than this one is chip-mem. */
250
251 char *chipmax;
252
253
254 /*
255 * Always set to the last size of memory tried to be allocated.
256 * Needed to ensure allocation when the size is bigger than 100000.
257 *
258 */
259 size_t latestsize;
260
261 #endif
262
263
264 #ifdef GC_AMIGA_FASTALLOC
265
266 /*
267 * The actual function that is called with the GET_MEM macro.
268 *
269 */
270
GC_amiga_get_mem(size_t size)271 void *GC_amiga_get_mem(size_t size){
272 struct GC_Amiga_AllocedMemoryHeader *gc_am;
273
274 #ifndef GC_AMIGA_ONLYFAST
275 if(GC_amiga_dontalloc==TRUE){
276 return NULL;
277 }
278
279 /* We really don't want to use chip-mem, but if we must, then as little as possible. */
280 if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
281 #endif
282
283 gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF);
284 if(gc_am==NULL) return NULL;
285
286 gc_am->next=GC_AMIGAMEM;
287 gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
288 GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
289
290 #ifdef GC_AMIGA_PRINTSTATS
291 if((char *)gc_am<chipmax){
292 allochip+=size;
293 }else{
294 allocfast+=size;
295 }
296 #endif
297
298 return gc_am+1;
299
300 }
301
302 #endif
303
304
305 #ifndef GC_AMIGA_ONLYFAST
306
307 /* Tries very hard to force GC to find fast-mem to return. Done recursively
308 * to hold the rejected memory-pointers reachable from the collector in an
309 * easy way.
310 *
311 */
312 #ifdef GC_AMIGA_RETRY
GC_amiga_rec_alloc(size_t size,void * (* AllocFunction)(size_t size2),const int rec)313 void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec){
314 void *ret;
315
316 ret=(*AllocFunction)(size);
317
318 #ifdef GC_AMIGA_PRINTSTATS
319 if((char *)ret>chipmax || ret==NULL){
320 if(ret==NULL){
321 nsucc++;
322 nsucc2+=size;
323 if(rec==0) ncur0++;
324 if(rec==1) ncur1++;
325 if(rec>1 && rec<10) ncur10++;
326 if(rec>=10 && rec<50) ncur50++;
327 if(rec>=50 && rec<150) ncur150++;
328 if(rec>=150) ncur151++;
329 }else{
330 succ++;
331 succ2+=size;
332 if(rec==0) cur0++;
333 if(rec==1) cur1++;
334 if(rec>1 && rec<10) cur10++;
335 if(rec>=10 && rec<50) cur50++;
336 if(rec>=50 && rec<150) cur150++;
337 if(rec>=150) cur151++;
338 }
339 }
340 #endif
341
342 if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
343 ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
344 }
345
346 return ret;
347 }
348 #endif
349
350
351 /* The allocating-functions defined inside the Amiga-blocks in gc.h is called
352 * via these functions.
353 */
354
355
GC_amiga_allocwrapper_any(size_t size,void * (* AllocFunction)(size_t size2))356 void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
357 void *ret;
358
359 GC_amiga_dontalloc=TRUE; /* Pretty tough thing to do, but its indeed necessary. */
360 latestsize=size;
361
362 ret=(*AllocFunction)(size);
363
364 if(((char *)ret) <= chipmax){
365 if(ret==NULL){
366 /* Give GC access to allocate memory. */
367 #ifdef GC_AMIGA_GC
368 if(!GC_dont_gc){
369 GC_gcollect();
370 #ifdef GC_AMIGA_PRINTSTATS
371 numcollects++;
372 #endif
373 ret=(*AllocFunction)(size);
374 }
375 if(ret==NULL)
376 #endif
377 {
378 GC_amiga_dontalloc=FALSE;
379 ret=(*AllocFunction)(size);
380 if(ret==NULL){
381 WARN("Out of Memory! Returning NIL!\n", 0);
382 }
383 }
384 #ifdef GC_AMIGA_PRINTSTATS
385 else{
386 nullretries++;
387 }
388 if(ret!=NULL && (char *)ret<=chipmax) chipa+=size;
389 #endif
390 }
391 #ifdef GC_AMIGA_RETRY
392 else{
393 void *ret2;
394 /* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
395 /* Using gctest to check the effectiveness of doing this, does seldom give a very good result. */
396 /* However, real programs doesn't normally rapidly allocate and deallocate. */
397 if(
398 AllocFunction!=GC_malloc_uncollectable
399 #ifdef GC_ATOMIC_UNCOLLECTABLE
400 && AllocFunction!=GC_malloc_atomic_uncollectable
401 #endif
402 ){
403 ret2=GC_amiga_rec_alloc(size,AllocFunction,0);
404 }else{
405 ret2=(*AllocFunction)(size);
406 #ifdef GC_AMIGA_PRINTSTATS
407 if((char *)ret2<chipmax || ret2==NULL){
408 nsucc++;
409 nsucc2+=size;
410 ncur0++;
411 }else{
412 succ++;
413 succ2+=size;
414 cur0++;
415 }
416 #endif
417 }
418 if(((char *)ret2)>chipmax){
419 GC_free(ret);
420 ret=ret2;
421 }else{
422 GC_free(ret2);
423 }
424 }
425 #endif
426 }
427
428 GC_amiga_dontalloc=FALSE;
429
430 return ret;
431 }
432
433
434
435 void (*GC_amiga_toany)(void)=NULL;
436
GC_amiga_set_toany(void (* func)(void))437 void GC_amiga_set_toany(void (*func)(void)){
438 GC_amiga_toany=func;
439 }
440
441 #endif /* !GC_AMIGA_ONLYFAST */
442
443
GC_amiga_allocwrapper_fast(size_t size,void * (* AllocFunction)(size_t size2))444 void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
445 void *ret;
446
447 ret=(*AllocFunction)(size);
448
449 if(ret==NULL){
450 /* Enable chip-mem allocation. */
451 #ifdef GC_AMIGA_GC
452 if(!GC_dont_gc){
453 GC_gcollect();
454 #ifdef GC_AMIGA_PRINTSTATS
455 numcollects++;
456 #endif
457 ret=(*AllocFunction)(size);
458 }
459 if(ret==NULL)
460 #endif
461 {
462 #ifndef GC_AMIGA_ONLYFAST
463 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
464 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
465 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
466 return GC_amiga_allocwrapper_any(size,AllocFunction);
467 #endif
468 }
469 #ifdef GC_AMIGA_PRINTSTATS
470 else{
471 nullretries++;
472 }
473 #endif
474 }
475
476 return ret;
477 }
478
GC_amiga_allocwrapper_firsttime(size_t size,void * (* AllocFunction)(size_t size2))479 void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
480 atexit(&GC_amiga_free_all_mem);
481 chipmax=(char *)SysBase->MaxLocMem; /* For people still having SysBase in chip-mem, this might speed up a bit. */
482 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
483 return GC_amiga_allocwrapper_fast(size,AllocFunction);
484 }
485
486
487 #endif /* GC_AMIGA_FASTALLOC */
488
489
490
491 /*
492 * The wrapped realloc function.
493 *
494 */
GC_amiga_realloc(void * old_object,size_t new_size_in_bytes)495 void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
496 #ifndef GC_AMIGA_FASTALLOC
497 return GC_realloc(old_object,new_size_in_bytes);
498 #else
499 void *ret;
500 latestsize=new_size_in_bytes;
501 ret=GC_realloc(old_object,new_size_in_bytes);
502 if(ret==NULL && new_size_in_bytes != 0
503 && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
504 /* Out of fast-mem. */
505 #ifdef GC_AMIGA_GC
506 if(!GC_dont_gc){
507 GC_gcollect();
508 #ifdef GC_AMIGA_PRINTSTATS
509 numcollects++;
510 #endif
511 ret=GC_realloc(old_object,new_size_in_bytes);
512 }
513 if(ret==NULL)
514 #endif
515 {
516 #ifndef GC_AMIGA_ONLYFAST
517 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
518 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
519 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
520 ret=GC_realloc(old_object,new_size_in_bytes);
521 #endif
522 }
523 #ifdef GC_AMIGA_PRINTSTATS
524 else{
525 nullretries++;
526 }
527 #endif
528 }
529 if(ret==NULL && new_size_in_bytes != 0){
530 WARN("Out of Memory! Returning NIL!\n", 0);
531 }
532 #ifdef GC_AMIGA_PRINTSTATS
533 if(((char *)ret)<chipmax && ret!=NULL){
534 chipa+=new_size_in_bytes;
535 }
536 #endif
537 return ret;
538 #endif
539 }
540
541 #endif /* GC_AMIGA_AM */
542