2 /* -----------------------------------------------------------------------------
3 * $Id: ForeignCall.c,v 1.4 1999/03/01 14:47:06 sewardj Exp $
5 * (c) The GHC Team 1994-1999.
7 * Foreign Function calls
9 * ---------------------------------------------------------------------------*/
15 #include "Assembler.h" /* for CFun stuff */
16 #include "Evaluator.h"
17 #include "ForeignCall.h"
19 /* the assymetry here seem to come from the caller-allocates
20 * calling convention. But does the caller really allocate
24 void hcall( HFunDescriptor* d, StablePtr fun, void* as, void* rs)
27 /* out of date - ADR */
28 marshall(d->arg_tys,as);
30 unmarshall(d->result_tys,rs);
37 /* By experiment on an x86 box, we found that gcc's
38 * __builtin_apply(fun,as,size) expects *as to look like this:
39 * as[0] = &first arg = &as[1]
44 * on an x86, it returns a pointer to a struct containing an
45 * int/int64/ptr in its first 4-8 bytes and a float/double in the next
49 * as[0] = &first arg = &as[2]
50 * as[1] = where structures should be returned
55 * This is something of a hack - but seems to be more portable than
56 * hacking it up in assembly language which is how I did it before - ADR
58 void ccall( CFunDescriptor* d, void (*fun)(void) )
61 char* tys = d->arg_tys;
62 /* ToDo: the use of ARG_SIZE is based on the assumption that Hugs
63 * obeys the same alignment restrictions as C.
64 * But this is almost certainly wrong!
65 * We could use gcc's __va_rounded_size macro (see varargs.h) to do a
69 void *as=alloca(4 + d->arg_size);
70 StgWord* args = (StgWord*) as;
71 *(void**)(args++) = 4 + (char*)as; /* incoming args ptr */
73 args += unmarshall(*tys,args);
75 rs = __builtin_apply(fun,as,(char*)args-(char*)as-4);
76 #elif sparc_TARGET_ARCH
77 void *as=alloca(8 + d->arg_size);
78 StgWord* args = (StgWord*) as;
80 *(void**)(args++) = (char*)as; /* incoming args ptr */
81 *(void**)(args++) = 0; /* structure value address - I think this is the address of a block of memory where structures are returned - in which case we should initialise with rs or something like that*/
83 args += unmarshall(*tys,args);
85 argcount = ((void*)args - as);
86 ASSERT(8 + d->arg_size == argcount);
92 rs = __builtin_apply(fun,as,argcount);
94 #error Cant do ccall for this architecture
97 /* ToDo: can't handle multiple return values at the moment
98 * - it's hard enough to get single return values working
100 if (*(d->result_tys)) {
101 char ty = *(d->result_tys);
102 ASSERT(d->result_tys[1] == '\0');
106 /* ToDo: is this right? */
107 marshall(ty,(char*)rs+8);
121 /* HACK alert (red alert) */
122 extern StgInt PopTaggedInt ( void ) ;
123 extern void PushTaggedInt ( StgInt );
124 extern StgPtr PopPtr ( void );
127 #define IF(sss) if (strcmp(sss,cdesc)==0)
128 void ccall( CFunDescriptor* d, void (*fun)(void) )
132 strcpy(cdesc, d->result_tys);
134 strcat(cdesc, d->arg_tys);
135 for (i = 0; cdesc[i] != 0; i++) {
137 case 'x': cdesc[i] = 'A'; break;
142 //fprintf(stderr, "ccall: %d cdesc = `%s'\n", seqNr++, cdesc);
144 IF(":") { ((void(*)(void))(fun))(); return; };
145 IF(":I") { int a1=PopTaggedInt(); ((void(*)(int))(fun))(a1); return;};
146 IF("I:") { int r= ((int(*)(void))(fun))(); PushTaggedInt(r); return;};
147 IF(":II") { int a1=PopTaggedInt(); int a2=PopTaggedInt();
148 ((void(*)(int,int))(fun))(a1,a2); return; };
149 IF("I:I") { int a1=PopTaggedInt();
150 int r=((int(*)(int))(fun))(a1); PushTaggedInt(r); return; };
151 IF("I:II") { int a1=PopTaggedInt(); int a2=PopTaggedInt();
152 int r=((int(*)(int,int))(fun))(a1,a2); PushTaggedInt(r); return; };
153 IF("I:III") { int a1=PopTaggedInt(); int a2=PopTaggedInt(); int a3=PopTaggedInt();
154 int r=((int(*)(int,int,int))(fun))(a1,a2,a3); PushTaggedInt(r); return; };
156 //IF("I:AI") { void* a1=(void*)PopPtr(); int a2=PopTaggedInt();
157 // int r=((int(*)(void*,int))(fun))(a1,a2); PushTaggedInt(r); return; };
159 fprintf(stderr,"panic: ccall cdesc `%s' not implemented\n", cdesc );
164 "ccall: arg_tys %s arg_size %d result_tys %s result_size %d\n",
165 d->arg_tys, d->arg_size, d->result_tys, d->result_size );
175 CFunDescriptor* mkDescriptor( char* as, char* rs )
177 /* ToDo: don't use malloc */
178 CFunDescriptor *d = malloc(sizeof(CFunDescriptor));
181 d->arg_size = argSize(as);
183 d->result_size = argSize(rs);
187 #endif /* INTERPRETER */