1 \section[COptWraps]{Wrappers for calls to ``STG C'' routines}
3 % this file is part of the C-as-assembler document
10 %************************************************************************
12 \subsection[COptWraps-portable]{Wrappers for ``portable~C''}
14 %************************************************************************
16 @STGCALL@ macros are used when we really have to be careful about saving
17 any caller-saves STG registers. @SAFESTGCALL@ macros are used
18 when the caller has previously arranged to save/restore volatile user
19 registers (vanilla, float, and double STG registers), and we only have to
20 worry about the ``system'' registers (stack and heap pointers, @STK_STUB@,
21 etc.). @STGCALL_GC@ macros are used whenever the callee is going to
22 need to access (and perhaps modify) some STG registers. @ULTRASAFESTGCALL@
23 is available for our own routines that we are absolutely certain will not
24 damage any STG registers.
28 \item @STGCALL@ saves/restores all caller-saves STG registers.
29 \item @SAFESTGCALL@ saves/restores only caller-saves STG ``system'' registers.
30 \item @ULTRASAFECALL@ is a simple call, without a wrapper.
31 \item @STGCALL_GC@ saves/restores {\em all} STG registers.
34 Several macros are provided to handle outcalls to functions requiring from
35 one to five arguments. (If we could assume GCC, we could use macro varargs,
36 but unfortunately, we have to cater to ANSI C as well.)
40 #define ULTRASAFESTGCALL0(t,p,f) f()
41 #define ULTRASAFESTGCALL1(t,p,f,a) f(a)
42 #define ULTRASAFESTGCALL2(t,p,f,a,b) f(a,b)
43 #define ULTRASAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
44 #define ULTRASAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
45 #define ULTRASAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
47 #if ! (defined(__GNUC__) && defined(__STG_GCC_REGS__))
49 #define STGCALL0(t,p,f) f()
50 #define STGCALL1(t,p,f,a) f(a)
51 #define STGCALL2(t,p,f,a,b) f(a,b)
52 #define STGCALL3(t,p,f,a,b,c) f(a,b,c)
53 #define STGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
54 #define STGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
56 #define SAFESTGCALL0(t,p,f) f()
57 #define SAFESTGCALL1(t,p,f,a) f(a)
58 #define SAFESTGCALL2(t,p,f,a,b) f(a,b)
59 #define SAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
60 #define SAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
61 #define SAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
64 * Generic call_GC wrappers have gone away in favor of these partially
69 do {SaveAllStgRegs(); PerformGC(args); RestoreAllStgRegs();} while(0)
70 #define DO_STACKOVERFLOW(headroom,args) \
71 do {SaveAllStgRegs(); StackOverflow(headroom,args); RestoreAllStgRegs();} while(0)
72 #define DO_YIELD(args) \
73 do {SaveAllStgRegs(); Yield(args); RestoreAllStgRegs();} while(0)
77 %************************************************************************
79 \subsection[COptWraps-optimised]{Wrappers in ``optimised~C''}
81 %************************************************************************
83 We {\em expect} the call-wrappery to be boring---the defaults shown
84 herein will kick in--- but you never know.
86 For example: Don't try an @STGCALL6@ on a SPARC! That's because you
87 cannot pass that many arguments to \tr{f} just by heaving them into
88 \tr{%o*} registers; anything else is too painful to contemplate.
91 #else /* __GNUC__ && __STG_GCC_REGS__ */
93 #if !(defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER))
94 #define STGCALL0(t,p,f) f()
95 #define STGCALL1(t,p,f,a) f(a)
96 #define STGCALL2(t,p,f,a,b) f(a,b)
97 #define STGCALL3(t,p,f,a,b,c) f(a,b,c)
98 #define STGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
99 #define STGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
103 extern void callWrapper(STG_NO_ARGS);
105 #define STGCALL0(t,p,f) \
106 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f);})
108 #define STGCALL1(t,p,f,a) \
109 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a);})
111 #define STGCALL2(t,p,f,a,b) \
112 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b);})
114 #define STGCALL3(t,p,f,a,b,c) \
115 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c);})
117 #define STGCALL4(t,p,f,a,b,c,d) \
118 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d);})
120 #define STGCALL5(t,p,f,a,b,c,d,e) \
121 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d,e);})
125 #if !defined(CALLER_SAVES_SYSTEM)
126 #define SAFESTGCALL0(t,p,f) f()
127 #define SAFESTGCALL1(t,p,f,a) f(a)
128 #define SAFESTGCALL2(t,p,f,a,b) f(a,b)
129 #define SAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
130 #define SAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
131 #define SAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
135 extern void callWrapper_safe(STG_NO_ARGS);
137 #define SAFESTGCALL0(t,p,f) \
138 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f);})
140 #define SAFESTGCALL1(t,p,f,a) \
141 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a);})
143 #define SAFESTGCALL2(t,p,f,a,b) \
144 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b);})
146 #define SAFESTGCALL3(t,p,f,a,b,c) \
147 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c);})
149 #define SAFESTGCALL4(t,p,f,a,b,c,d) \
150 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d);})
152 #define SAFESTGCALL5(t,p,f,a,b,c,d,e) \
153 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d,e);})
158 * Generic call_GC wrappers have gone away in favor of these partially
159 * evaluated versions. These are only here so that we can avoid putting
160 * all of the STG register save/restore code at each call site.
163 #ifndef CALLWRAPPER_C
165 * We may have funny declarations in CallWrapper_C, to avoid sliding the
166 * register windows and other nastiness.
168 void PerformGC_wrapper PROTO((W_));
169 void StackOverflow_wrapper PROTO((W_, W_));
170 void Yield_wrapper PROTO((W_));
173 #define DO_GC(args) PerformGC_wrapper(args)
174 #define DO_STACKOVERFLOW(headroom,args) StackOverflow_wrapper(headroom,args)
175 #define DO_YIELD(args) Yield_wrapper(args)
177 #endif /* __GNUC__ && __STG_GCC_REGS__ */
180 %************************************************************************
182 \subsection[COptWraps-magic]{Magic assembly bits for call wrappers}
184 %************************************************************************
186 Call wrappers need to be able to call arbitrary functions, regardless of
187 their arguments and return types. (Okay, we actually only allow up to
188 five arguments, because on the sparc it gets more complicated to handle
189 any more.) The nasty bit is that the return value can be in either an
190 integer register or a floating point register, and we don't know which.
191 (We {\em don't} handle structure returns, and we don't want to.)
192 Still, we have to stash the result away while we restore caller-saves
193 STG registers, and then we have to pass the result back to our caller
196 Getting this right requires three extremely @MAGIC@ macros, no doubt
197 chock full of assembly gook for the current platform. These are
198 @MAGIC_CALL_SETUP@, which gets ready for one of these magic calls,
199 @MAGIC_CALL@, which performs the call and stashes away all possible
200 results, and @MAGIC_RETURN@, which collects all possible results back
203 For example, in the sparc version, the @SETUP@ guarantees that we
204 have enough space to store all of our argument registers for a wee
205 bit, and it gives a `C' name to the register that we're going to use
206 for the call. (It helps to do the call in actual `C' fashion, so that
207 gcc knows about register death.) It also stashes the incoming arguments
208 in the space provided. The @MAGIC_CALL@ then reloads the argument
209 registers, rotated by one, so that the function to call is in \tr{%o5},
210 calls the function in `C' fashion, and stashes away the possible return
211 values (either \tr{%o0} or \tr{%f0}) on the stack. Finally, @MAGIC_RETURN@
212 ensures that \tr{%o0} and \tr{%f0} are both set to the values we stashed
213 away. Presumably, we then fall into a return instruction and our caller
214 gets whatever it's after.
216 %************************************************************************
218 \subsubsection[alpha-magic]{Call-wrapper MAGIC for DEC Alpha}
220 %************************************************************************
224 #if defined(__GNUC__) && defined(__STG_GCC_REGS__)
226 #if alpha_dec_osf1_TARGET
227 /* Is this too specific */
229 #define MAGIC_CALL_SETUP \
230 long WeNeedThisSpace[7]; \
231 double AndThisSpaceToo[6]; \
232 register void (*f)() __asm__("$21");\
235 "\tstq $17,16($30)\n" \
236 "\tstq $18,24($30)\n" \
237 "\tstq $19,32($30)\n" \
238 "\tstq $20,40($30)\n" \
239 "\tstq $21,48($30)\n" \
240 "\tstt $f16,56($30)\n" \
241 "\tstt $f17,64($30)\n" \
242 "\tstt $f18,72($30)\n" \
243 "\tstt $f19,80($30)\n" \
244 "\tstt $f20,88($30)\n" \
245 "\tstt $f21,96($30)");
250 "\tldq $16,16($30)\n" \
251 "\tldq $17,24($30)\n" \
252 "\tldq $18,32($30)\n" \
253 "\tldq $19,40($30)\n" \
254 "\tldq $20,48($30)\n" \
255 "\tldt $f16,56($30)\n" \
256 "\tldt $f17,64($30)\n" \
257 "\tldt $f18,72($30)\n" \
258 "\tldt $f19,80($30)\n" \
259 "\tldt $f20,88($30)\n" \
260 "\tldt $f21,96($30)");\
264 "\tstt $f0,16($30)");
266 #define MAGIC_RETURN \
269 "\tldt $f0,16($30)");
271 #define WRAPPER_NAME(f) /* nothing */
274 Threaded code needs to be able to grab the return address, in case we have
275 an intervening context switch.
278 #define SET_RETADDR(loc) { register StgFunPtrFunPtr ra __asm__ ("$26"); loc = ra; }
280 #define WRAPPER_SETUP(f) SaveAllStgContext();
282 #define WRAPPER_RETURN(x) \
283 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
285 #define SEPARATE_WRAPPER_RESTORE /* none */
291 %************************************************************************
293 \subsubsection[hppa-magic]{Call-wrapper MAGIC for HP-PA}
295 %************************************************************************
299 #if hppa1_1_hp_hpux_TARGET
300 /* Is this too specific */
302 #define MAGIC_CALL_SETUP \
303 long SavedIntArgRegs[4]; \
304 double SavedFltArgRegs[2]; \
305 register void (*f)() __asm__("%r28");\
308 "\tstw %r25,8(0,%r3)\n" \
309 "\tstw %r24,12(0,%r3)\n" \
310 "\tstw %r23,16(0,%r3)\n" \
311 "\tldo 40(%r3),%r19\n" \
312 "\tfstds %fr5,-16(0,%r19)\n"\
313 "\tfstds %fr7, -8(0,%r19)\n");
318 "ldw 8(0,%r3),%r26\n" \
319 "\tldw 12(0,%r3),%r25\n" \
320 "\tldw 16(0,%r3),%r24\n" \
321 "\tldw -52(0,%r3),%r23\n" \
322 "\tldw -56(0,%r3),%r19\n" \
323 "\tstw %r19,-52(0,%r30)\n" \
324 "\tldo 40(%r3),%r19\n" \
325 "\tfldds -16(0,%r19),%fr5\n"\
326 "\tfldds -8(0,%r19),%fr7\n" \
327 "\tldo -64(%r3),%r19\n" \
328 "\tldo -64(%r30),%r20\n" \
329 "\tfldds -16(0,%r19),%fr4\n"\
330 "\tfstds %fr4,-16(0,%r20)\n"\
331 "\tfldds -8(0,%r19)%fr4\n" \
332 "\tfstds %fr4,-8(0,%r19)\n" \
333 "\tfldds 0(0,%r19),%fr4\n" \
334 "\tfstds %fr4,0(0,%r19)\n" \
335 "\tfldds 8(0,%r19),%fr4\n" \
336 "\tfstds %fr4,8(0,%r19)\n");\
339 "stw %r28,8(0,%r3)\n" \
340 "\tfstds %fr4,16(0,%r3)");
342 #define MAGIC_RETURN \
344 "\tfldds 16(0,%r3),%fr4" \
345 "ldw 8(0,%r3),%r28\n");
347 #define WRAPPER_NAME(f) /* nothing */
350 Threaded code needs to be able to grab the return address, in case we have
351 an intervening context switch.
354 #define SET_RETADDR(loc) __asm__ volatile ("stw %%r2, %0" : "=m" ((void *)(loc)));
356 #define WRAPPER_SETUP(f) SaveAllStgContext();
358 #define WRAPPER_RETURN(x) \
359 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
361 #define SEPARATE_WRAPPER_RESTORE /* none */
367 %************************************************************************
369 \subsubsection[iX86-magic]{Call-wrapper MAGIC for iX86}
371 %************************************************************************
375 #if i386_TARGET_ARCH || i486_TARGET_ARCH
377 /* modelled loosely on SPARC stuff */
379 /* NB: no MAGIC_CALL_SETUP, MAGIC_CALL, or MAGIC_RETURN! */
381 #define WRAPPER_NAME(f) __asm__("L" #f "_wrapper")
383 #define REAL_NAME(f) "_" #f
385 /* when we come into PerformGC_wrapper:
387 - %esp holds Hp (!); get it into 80(%ebx) -- quick!
389 - %esp needs to be bumped by (at least) 4, because
390 C thinks an argument was passed on the stack
391 (use 64 just for fun)
393 - %eax holds the argument for PerformGC
395 - 104(%ebx) hold the return address -- address we want to
398 - 100(%ebx) holds a %esp value that we can re-load with
402 #define WRAPPER_SETUP(f) \
404 ".globl " REAL_NAME(f) "_wrapper\n" \
405 REAL_NAME(f) "_wrapper:\n" \
406 "\tmovl %%esp,80(%%ebx)\n" \
407 "\tmovl 100(%%ebx),%%esp\n" \
408 "\tmovl %%eax,%0" : "=r" (args)); \
412 : "=r" (SP_stack[++SP_stack_ptr])); \
415 #define WRAPPER_RETURN(x) \
417 RestoreAllStgRegs(); \
418 if(x) JMP_(EnterNodeCode); /* never used? */ \
421 "\tmovl %0,_MainRegTable+100" \
422 : "=r" (foo) : "m" (SP_stack[SP_stack_ptr--]) ); \
424 "movl 80(%ebx),%esp\n" \
425 "\tjmp *104(%ebx)" ); \
428 #define SEPARATE_WRAPPER_RESTORE /* none */
434 %************************************************************************
436 \subsubsection[m68k-magic]{Call-wrapper MAGIC for m68k}
438 %************************************************************************
444 #define MAGIC_CALL_SETUP \
445 int WeNeedThisSpace[5]; \
446 register void (*f)() __asm__("a0"); \
448 "movel a6@(8),a0\n" \
449 "\tmovel a6@(12),a6@(-20)\n" \
450 "\tmovel a6@(16),a6@(-16)\n" \
451 "\tmovel a6@(20),a6@(-12)\n" \
452 "\tmovel a6@(24),a6@(-8)\n" \
453 "\tmovel a6@(28),a6@(-4)");
461 #define MAGIC_RETURN \
466 #define WRAPPER_NAME(f) /* nothing */
468 #define WRAPPER_SETUP(f) SaveAllStgContext();
470 #define WRAPPER_RETURN(x) \
471 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
473 #define SEPARATE_WRAPPER_RESTORE /* none */
475 #endif /* __mc680x0__ */
479 %************************************************************************
481 \subsubsection[mips-magic]{Call-wrapper MAGIC for MIPS}
483 %************************************************************************
486 #if mipseb_TARGET_ARCH || mipsel_TARGET_ARCH
488 /* shift 4 arg registers down one */
490 #define MAGIC_CALL_SETUP \
491 register void (*f)() __asm__("$2"); \
497 "\tlw $7,16($sp)\n" \
498 "\taddu $sp,$sp,4\n" \
505 "\ts.d $f0, -8($sp)\n" \
506 "\tsw $2, -12($sp)");
508 #define MAGIC_RETURN \
510 "l.d $f0, -8($sp)\n" \
511 "\tlw $2, -12($sp)");
513 #define WRAPPER_NAME(f) /* nothing */
515 #define WRAPPER_SETUP(f) SaveAllStgContext();
517 #define WRAPPER_RETURN(x) \
518 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
520 #define SEPARATE_WRAPPER_RESTORE /* none */
525 %************************************************************************
527 \subsubsection[sparc-magic]{Call-wrapper MAGIC for SPARC}
529 %************************************************************************
533 #if sparc_TARGET_ARCH
535 #define MAGIC_CALL_SETUP \
536 int WeNeedThisSpace[6]; \
537 register void (*f)() __asm__("%o5");\
539 "std %i0,[%fp-40]\n" \
540 "\tstd %i2,[%fp-32]\n" \
541 "\tstd %i4,[%fp-24]");
545 "ld [%%fp-40],%%o5\n" \
546 "\tld [%%fp-36],%%o0\n" \
547 "\tld [%%fp-32],%%o1\n" \
548 "\tld [%%fp-28],%%o2\n" \
549 "\tld [%%fp-24],%%o3\n" \
550 "\tld [%%fp-20],%%o4" \
551 : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5");\
554 "std %f0,[%fp-40]\n" \
555 "\tstd %o0,[%fp-32]");
557 #define MAGIC_RETURN \
559 "ldd [%fp-40],%f0\n" \
560 "\tldd [%fp-32],%i0");
563 We rename the entry points for wrappers so that we can
564 introduce a new entry point after the prologue. We want to ensure
565 that the register window does not slide! However, we insert a
566 call to abort() to make gcc _believe_ that the window slid.
569 #define WRAPPER_NAME(f) __asm__("L" #f "_wrapper")
571 #ifdef solaris2_TARGET_OS
572 #define REAL_NAME(f) #f
574 #define REAL_NAME(f) "_" #f
577 #define WRAPPER_SETUP(f) \
579 ".global " REAL_NAME(f) "_wrapper\n"\
580 REAL_NAME(f) "_wrapper:\n" \
581 "\tstd %o0,[%sp-24]\n" \
583 SaveAllStgContext(); \
585 "ldd [%sp-24],%i0\n" \
589 * In the above, we want to ensure that the arguments are both in the %i registers
590 * and the %o registers, with the assumption that gcc will expect them now to be in
591 * one or the other. This is a terrible hack.
595 Threaded code needs to be able to grab the return address, in case we have
596 an intervening context switch. Note that we want the address of the next
597 instruction to be executed, so we add 8 to the link address.
600 #define SET_RETADDR(loc) \
602 "add %%i7,8,%%o7\n" \
604 : "=m" (loc) : : "%o7");
607 #define WRAPPER_RETURN(x) \
609 "call Lwrapper_restore" #x "\n" \
614 The sparc is a big nuisance. We use a separate function for
615 restoring STG registers so that gcc won't try to leave anything
616 (like the address of MainRegTable) in the stack frame that we
617 didn't build. We also use a leaf return in a format that allows us
618 to pass %o7 in as an argument known to gcc, in the hope that its
619 value will be preserved during the reloading of STG registers.
620 Note that the current gcc (2.5.6) does not use the delay slot
621 here (%#), but perhaps future versions will.
624 #if defined(CONCURRENT)
625 #define WRAPPER_REENTER \
626 void wrapper_restore_and_reenter_node(STG_NO_ARGS) \
628 __asm__("Lwrapper_restore1:"); \
629 RestoreAllStgRegs(); \
630 JMP_(EnterNodeCode); \
633 #define WRAPPER_REENTER
636 #define SEPARATE_WRAPPER_RESTORE \
637 void wrapper_restore(STG_NO_ARGS) \
639 register void *o7 __asm__("%o7"); \
641 "Lwrapper_restore0:\n" \
642 "\tmov %%i7,%0" : "=r" (o7)); \
643 RestoreAllStgRegs(); \
644 __asm__ volatile ("jmp %0+8%#" : : "r" (o7)); \
648 #endif /* __sparc__ */
650 #endif /* __GNUC__ && __STG_GCC_REGS__ */
656 #endif /* ! COPTWRAPS_H */