[project @ 1999-03-02 19:50:12 by sof]
[ghc-hetmet.git] / ghc / rts / ForeignCall.c
1
2 /* -----------------------------------------------------------------------------
3  * $Id: ForeignCall.c,v 1.4 1999/03/01 14:47:06 sewardj Exp $
4  *
5  * (c) The GHC Team 1994-1999.
6  *
7  * Foreign Function calls
8  *
9  * ---------------------------------------------------------------------------*/
10
11 #include "Rts.h"
12
13 #ifdef INTERPRETER
14
15 #include "Assembler.h" /* for CFun stuff */
16 #include "Evaluator.h"
17 #include "ForeignCall.h"
18
19 /* the assymetry here seem to come from the caller-allocates 
20  * calling convention.  But does the caller really allocate 
21  * result??
22  */
23
24 void hcall( HFunDescriptor* d, StablePtr fun, void* as, void* rs)
25 {
26 #if 0
27     /* out of date - ADR */
28     marshall(d->arg_tys,as);
29     prim_hcall(fun);
30     unmarshall(d->result_tys,rs);
31 #else
32     assert(0);
33 #endif
34 }
35
36 #if 0
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]
40  *   as[1] = arg1
41  *   as[2] = arg2
42  *   ...
43  *
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
46  * 8 bytes.
47  *
48  * On a sparc:
49  *   as[0] = &first arg = &as[2]
50  *   as[1] = where structures should be returned
51  *   as[2] = arg1
52  *   as[3] = arg2
53  *   ...
54  *
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
57  */
58 void ccall( CFunDescriptor* d, void (*fun)(void) )
59 {
60     void *rs;
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
66      * better job.
67      */
68 #if i386_TARGET_ARCH
69     void *as=alloca(4 + d->arg_size);
70     StgWord* args = (StgWord*) as;
71     *(void**)(args++) = 4 + (char*)as; /* incoming args ptr */
72     for(; *tys; ++tys) {
73       args += unmarshall(*tys,args);
74     }
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;
79     int argcount;
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*/
82     for(; *tys; ++tys) {
83       args += unmarshall(*tys,args);
84     }
85     argcount = ((void*)args - as);
86     ASSERT(8 + d->arg_size == argcount);
87     if (argcount <= 8) {
88       argcount = 0;
89     } else {
90       argcount -= 4;
91     }
92     rs = __builtin_apply(fun,as,argcount);
93 #else
94 #error Cant do ccall for this architecture
95 #endif
96
97     /* ToDo: can't handle multiple return values at the moment
98      * - it's hard enough to get single return values working
99      */
100     if (*(d->result_tys)) {
101         char ty = *(d->result_tys);
102         ASSERT(d->result_tys[1] == '\0');
103         switch (ty) {
104         case 'F':
105         case 'D': 
106                 /* ToDo: is this right? */
107                 marshall(ty,(char*)rs+8);
108                 return;
109         default:
110                 marshall(ty,rs);
111                 return;
112         }
113     }
114 }
115 #endif
116
117
118
119
120 #if 1
121 /* HACK alert (red alert) */
122 extern StgInt          PopTaggedInt       ( void ) ;
123 extern void PushTaggedInt ( StgInt );
124 extern StgPtr PopPtr ( void );
125
126 int seqNr = 0;
127 #define IF(sss) if (strcmp(sss,cdesc)==0)
128 void ccall( CFunDescriptor* d, void (*fun)(void) )
129 {
130    int i;
131    char cdesc[100];
132    strcpy(cdesc, d->result_tys);
133    strcat(cdesc, ":");
134    strcat(cdesc, d->arg_tys);
135    for (i = 0; cdesc[i] != 0; i++) {
136       switch (cdesc[i]) {
137          case 'x': cdesc[i] = 'A'; break;
138          default:  break;
139       }
140    }
141
142    //fprintf(stderr, "ccall: %d cdesc = `%s'\n", seqNr++, cdesc);
143
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; };
155
156    //IF("I:AI") { void* a1=(void*)PopPtr(); int a2=PopTaggedInt();
157    //           int r=((int(*)(void*,int))(fun))(a1,a2); PushTaggedInt(r); return; };
158
159 fprintf(stderr,"panic: ccall cdesc `%s' not implemented\n", cdesc );
160    exit(1);
161
162
163 fprintf(stderr, 
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 );
166 }
167 #undef IF
168 #endif
169
170
171
172
173
174
175 CFunDescriptor* mkDescriptor( char* as, char* rs ) 
176
177     /* ToDo: don't use malloc */
178     CFunDescriptor *d = malloc(sizeof(CFunDescriptor));
179     assert(d);
180     d->arg_tys = as;
181     d->arg_size = argSize(as);
182     d->result_tys = rs;
183     d->result_size = argSize(rs);
184     return d;
185 }
186
187 #endif /* INTERPRETER */