%************************************************************************ %* * \section[CallWrap_C.lc]{``callWrapper'' stuff that can be written in C} %* * %************************************************************************ \begin{code} #define MAIN_REG_MAP /* These routines are all a bit special */ #define CALLWRAPPER_C /* Don't give standard declarations for wrappers */ #include "rtsdefs.h" \end{code} %************************************************************************ %* * \subsection[call-wrapping]{Routines to ``wrap'' special calls to C} %* * %************************************************************************ In most cases, this requires some assembly-language hacking (see the discussion in @COptWraps.lh@.) \begin{code} #if defined(__STG_GCC_REGS__) # if defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER) void callWrapper(STG_NO_ARGS) { MAGIC_CALL_SETUP CALLER_SAVE_Base CALLER_SAVE_StkO CALLER_SAVE_R1 CALLER_SAVE_R2 CALLER_SAVE_R3 CALLER_SAVE_R4 CALLER_SAVE_R5 CALLER_SAVE_R6 CALLER_SAVE_R7 CALLER_SAVE_R8 CALLER_SAVE_FltReg1 CALLER_SAVE_FltReg2 CALLER_SAVE_FltReg3 CALLER_SAVE_FltReg4 CALLER_SAVE_DblReg1 CALLER_SAVE_DblReg2 CALLER_SAVE_Tag CALLER_SAVE_SpA CALLER_SAVE_SuA CALLER_SAVE_SpB CALLER_SAVE_SuB CALLER_SAVE_Hp CALLER_SAVE_HpLim CALLER_SAVE_Liveness CALLER_SAVE_Ret MAGIC_CALL CALLER_RESTORE_Base /* has to be first! */ CALLER_RESTORE_StkO CALLER_RESTORE_R1 CALLER_RESTORE_R2 CALLER_RESTORE_R3 CALLER_RESTORE_R4 CALLER_RESTORE_R5 CALLER_RESTORE_R6 CALLER_RESTORE_R7 CALLER_RESTORE_R8 CALLER_RESTORE_FltReg1 CALLER_RESTORE_FltReg2 CALLER_RESTORE_FltReg3 CALLER_RESTORE_FltReg4 CALLER_RESTORE_DblReg1 CALLER_RESTORE_DblReg2 CALLER_RESTORE_Tag CALLER_RESTORE_SpA CALLER_RESTORE_SuA CALLER_RESTORE_SpB CALLER_RESTORE_SuB CALLER_RESTORE_Hp CALLER_RESTORE_HpLim CALLER_RESTORE_Liveness CALLER_RESTORE_Ret /* These next two are restore-only */ CALLER_RESTORE_StdUpdRetVec CALLER_RESTORE_StkStub MAGIC_RETURN } # endif /* defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER) */ # if defined(CALLER_SAVES_SYSTEM) void callWrapper_safe(STG_NO_ARGS) { MAGIC_CALL_SETUP CALLER_SAVE_Base CALLER_SAVE_StkO CALLER_SAVE_SpA CALLER_SAVE_SuA CALLER_SAVE_SpB CALLER_SAVE_SuB CALLER_SAVE_Hp CALLER_SAVE_HpLim CALLER_SAVE_Liveness CALLER_SAVE_Ret MAGIC_CALL CALLER_RESTORE_Base /* has to be first! */ CALLER_RESTORE_StkO CALLER_RESTORE_SpA CALLER_RESTORE_SuA CALLER_RESTORE_SpB CALLER_RESTORE_SuB CALLER_RESTORE_Hp CALLER_RESTORE_HpLim CALLER_RESTORE_Liveness CALLER_RESTORE_Ret /* These next two are restore-only */ CALLER_RESTORE_StdUpdRetVec CALLER_RESTORE_StkStub MAGIC_RETURN } # endif /* defined(CALLER_SAVES_SYSTEM) */ /* Nota Bene: Anyone changing the definition of @callWrapper_GC@ should make appropriate changes in the compiler (absCSyn/PprAbsC.lhs :: pprCCall). The reason is that \tr{_ccall_GC_} and \tr{_casm_GC_} generate code like this: \begin{verbatim} { R _ccall_result; SaveAllStgRegs(); inCCallGC+=1; _ccall_result = << do the call/asm>>; inCCallGC-=1; RestoreAllStgRegs(); } \end{verbatim} This avoids limiting _ccall_GC_ to 6 arguments and makes it possible to implement _ccall_GC_. (The local variable avoids the need for some of the deeper magic hidden inside @GC_SETUP@, @GC_CCALL@ and @GC_RETURN@.) ADR */ EXTFUN(EnterNodeCode); void *__temp_esp, *__temp_eax; void PerformGC_wrapper PROTO((W_)) WRAPPER_NAME(PerformGC); void PerformGC_wrapper(args) W_ args; { #if i386_TARGET_ARCH void *ret_addr; WRAPPER_SETUP(PerformGC,ret_addr,args) #else WRAPPER_SETUP(PerformGC, ignore_me, ignore_me) #endif PerformGC(args); WRAPPER_RETURN(0) } # ifdef CONCURRENT void __DISCARD__ (STG_NO_ARGS) { /*nothing*/ } void StackOverflow_wrapper PROTO((W_,W_)) WRAPPER_NAME(StackOverflow); void StackOverflow_wrapper(args1,args2) W_ args1, args2; { #if i386_TARGET_ARCH void *ret_addr, *ignore_me; WRAPPER_SETUP(StackOverflow,ret_addr,ignore_me) #else WRAPPER_SETUP(StackOverflow, ignore_me, ignore_me) #endif if(StackOverflow(args1,args2)) { WRAPPER_RETURN(1) } WRAPPER_RETURN(0) } void Yield_wrapper PROTO((W_)) WRAPPER_NAME(Yield); void Yield_wrapper(args) W_ args; { #if i386_TARGET_ARCH void *ret_addr, *ignore_me; WRAPPER_SETUP(Yield, ret_addr, ignore_me) #else WRAPPER_SETUP(Yield, ignore_me, ignore_me) #endif Yield(args); WRAPPER_RETURN(0) } # endif # ifdef GRAN void PerformReschedule_wrapper PROTO((W_, W_)) WRAPPER_NAME(PerformReschedule); void PerformReschedule_wrapper(liveness, always_reenter_node) W_ liveness; W_ always_reenter_node; { #if i386_TARGET_ARCH void *ret_addr, *ignore_me; WRAPPER_SETUP(PerformReschedule, ret_addr, ignore_me) #else WRAPPER_SETUP(PerformReschedule, ignore_me, ignore_me) #endif PerformReschedule(liveness, always_reenter_node); WRAPPER_RETURN(0) } # endif /* GRAN */ /* * In the threaded world, context switches may occur during one of these * wrapped calls, and when we come back, our stack will have been trashed. * If gcc, in all of its cleverness, tries to store any temporary values on * the stack, we need to separate the restoration function. See the sparc * code for an example. */ SEPARATE_WRAPPER_RESTORE #endif /* defined(__STG_GCC_REGS__) */ /* We can perform a runtime check that we have used @_ccall_GC_@ when appropriate using this flag. */ StgInt inCCallGC = 0; void checkInCCallGC() { if (inCCallGC == 0) { fprintf(stderr, "Error: entering a closure from C without using _ccall_GC_\n"); EXIT(EXIT_FAILURE); } } \end{code} Hack for -UGRAN setup. % HWL \begin{code} #ifndef GRAN void PerformReschedule_wrapper PROTO((W_, W_)); void PerformReschedule_wrapper(liveness, always_reenter_node) W_ liveness; W_ always_reenter_node; { } #endif \end{code}