1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (c) 2011, 2013 Anthony Green
3*1fd5a2e1SPrashanth Swaminathan Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
4*1fd5a2e1SPrashanth Swaminathan
5*1fd5a2e1SPrashanth Swaminathan SPARC Foreign Function Interface
6*1fd5a2e1SPrashanth Swaminathan
7*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
8*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
9*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
10*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
11*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
12*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
13*1fd5a2e1SPrashanth Swaminathan the following conditions:
14*1fd5a2e1SPrashanth Swaminathan
15*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
16*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
17*1fd5a2e1SPrashanth Swaminathan
18*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
26*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
27*1fd5a2e1SPrashanth Swaminathan
28*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
29*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
30*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
31*1fd5a2e1SPrashanth Swaminathan #include "internal.h"
32*1fd5a2e1SPrashanth Swaminathan
33*1fd5a2e1SPrashanth Swaminathan #ifndef SPARC64
34*1fd5a2e1SPrashanth Swaminathan
35*1fd5a2e1SPrashanth Swaminathan /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
36*1fd5a2e1SPrashanth Swaminathan all further uses in this file will refer to the 128-bit type. */
37*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
38*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != 4
39*1fd5a2e1SPrashanth Swaminathan # error FFI_TYPE_LONGDOUBLE out of date
40*1fd5a2e1SPrashanth Swaminathan # endif
41*1fd5a2e1SPrashanth Swaminathan #else
42*1fd5a2e1SPrashanth Swaminathan # undef FFI_TYPE_LONGDOUBLE
43*1fd5a2e1SPrashanth Swaminathan # define FFI_TYPE_LONGDOUBLE 4
44*1fd5a2e1SPrashanth Swaminathan #endif
45*1fd5a2e1SPrashanth Swaminathan
46*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
47*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)48*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep(ffi_cif *cif)
49*1fd5a2e1SPrashanth Swaminathan {
50*1fd5a2e1SPrashanth Swaminathan ffi_type *rtype = cif->rtype;
51*1fd5a2e1SPrashanth Swaminathan int rtt = rtype->type;
52*1fd5a2e1SPrashanth Swaminathan size_t bytes;
53*1fd5a2e1SPrashanth Swaminathan int i, n, flags;
54*1fd5a2e1SPrashanth Swaminathan
55*1fd5a2e1SPrashanth Swaminathan /* Set the return type flag */
56*1fd5a2e1SPrashanth Swaminathan switch (rtt)
57*1fd5a2e1SPrashanth Swaminathan {
58*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
59*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_VOID;
60*1fd5a2e1SPrashanth Swaminathan break;
61*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
62*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_F_1;
63*1fd5a2e1SPrashanth Swaminathan break;
64*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
65*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_F_2;
66*1fd5a2e1SPrashanth Swaminathan break;
67*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
68*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
69*1fd5a2e1SPrashanth Swaminathan flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
70*1fd5a2e1SPrashanth Swaminathan flags |= SPARC_RET_STRUCT;
71*1fd5a2e1SPrashanth Swaminathan break;
72*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
73*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_SINT8;
74*1fd5a2e1SPrashanth Swaminathan break;
75*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
76*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_UINT8;
77*1fd5a2e1SPrashanth Swaminathan break;
78*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
79*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_SINT16;
80*1fd5a2e1SPrashanth Swaminathan break;
81*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
82*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_UINT16;
83*1fd5a2e1SPrashanth Swaminathan break;
84*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
85*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
86*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
87*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
88*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_UINT32;
89*1fd5a2e1SPrashanth Swaminathan break;
90*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
91*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
92*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_INT64;
93*1fd5a2e1SPrashanth Swaminathan break;
94*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
95*1fd5a2e1SPrashanth Swaminathan rtt = rtype->elements[0]->type;
96*1fd5a2e1SPrashanth Swaminathan switch (rtt)
97*1fd5a2e1SPrashanth Swaminathan {
98*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
99*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_F_2;
100*1fd5a2e1SPrashanth Swaminathan break;
101*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
102*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_F_4;
103*1fd5a2e1SPrashanth Swaminathan break;
104*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
105*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_F_8;
106*1fd5a2e1SPrashanth Swaminathan break;
107*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
108*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
109*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_INT128;
110*1fd5a2e1SPrashanth Swaminathan break;
111*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
112*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
113*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
114*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_INT64;
115*1fd5a2e1SPrashanth Swaminathan break;
116*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
117*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
118*1fd5a2e1SPrashanth Swaminathan flags = SP_V8_RET_CPLX16;
119*1fd5a2e1SPrashanth Swaminathan break;
120*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
121*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
122*1fd5a2e1SPrashanth Swaminathan flags = SP_V8_RET_CPLX8;
123*1fd5a2e1SPrashanth Swaminathan break;
124*1fd5a2e1SPrashanth Swaminathan default:
125*1fd5a2e1SPrashanth Swaminathan abort();
126*1fd5a2e1SPrashanth Swaminathan }
127*1fd5a2e1SPrashanth Swaminathan break;
128*1fd5a2e1SPrashanth Swaminathan default:
129*1fd5a2e1SPrashanth Swaminathan abort();
130*1fd5a2e1SPrashanth Swaminathan }
131*1fd5a2e1SPrashanth Swaminathan cif->flags = flags;
132*1fd5a2e1SPrashanth Swaminathan
133*1fd5a2e1SPrashanth Swaminathan bytes = 0;
134*1fd5a2e1SPrashanth Swaminathan for (i = 0, n = cif->nargs; i < n; ++i)
135*1fd5a2e1SPrashanth Swaminathan {
136*1fd5a2e1SPrashanth Swaminathan ffi_type *ty = cif->arg_types[i];
137*1fd5a2e1SPrashanth Swaminathan size_t z = ty->size;
138*1fd5a2e1SPrashanth Swaminathan int tt = ty->type;
139*1fd5a2e1SPrashanth Swaminathan
140*1fd5a2e1SPrashanth Swaminathan switch (tt)
141*1fd5a2e1SPrashanth Swaminathan {
142*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
143*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
144*1fd5a2e1SPrashanth Swaminathan by_reference:
145*1fd5a2e1SPrashanth Swaminathan /* Passed by reference. */
146*1fd5a2e1SPrashanth Swaminathan z = 4;
147*1fd5a2e1SPrashanth Swaminathan break;
148*1fd5a2e1SPrashanth Swaminathan
149*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
150*1fd5a2e1SPrashanth Swaminathan tt = ty->elements[0]->type;
151*1fd5a2e1SPrashanth Swaminathan if (tt == FFI_TYPE_FLOAT || z > 8)
152*1fd5a2e1SPrashanth Swaminathan goto by_reference;
153*1fd5a2e1SPrashanth Swaminathan /* FALLTHRU */
154*1fd5a2e1SPrashanth Swaminathan
155*1fd5a2e1SPrashanth Swaminathan default:
156*1fd5a2e1SPrashanth Swaminathan z = FFI_ALIGN(z, 4);
157*1fd5a2e1SPrashanth Swaminathan }
158*1fd5a2e1SPrashanth Swaminathan bytes += z;
159*1fd5a2e1SPrashanth Swaminathan }
160*1fd5a2e1SPrashanth Swaminathan
161*1fd5a2e1SPrashanth Swaminathan /* Sparc call frames require that space is allocated for 6 args,
162*1fd5a2e1SPrashanth Swaminathan even if they aren't used. Make that space if necessary. */
163*1fd5a2e1SPrashanth Swaminathan if (bytes < 6 * 4)
164*1fd5a2e1SPrashanth Swaminathan bytes = 6 * 4;
165*1fd5a2e1SPrashanth Swaminathan
166*1fd5a2e1SPrashanth Swaminathan /* The ABI always requires space for the struct return pointer. */
167*1fd5a2e1SPrashanth Swaminathan bytes += 4;
168*1fd5a2e1SPrashanth Swaminathan
169*1fd5a2e1SPrashanth Swaminathan /* The stack must be 2 word aligned, so round bytes up appropriately. */
170*1fd5a2e1SPrashanth Swaminathan bytes = FFI_ALIGN(bytes, 2 * 4);
171*1fd5a2e1SPrashanth Swaminathan
172*1fd5a2e1SPrashanth Swaminathan /* Include the call frame to prep_args. */
173*1fd5a2e1SPrashanth Swaminathan bytes += 4*16 + 4*8;
174*1fd5a2e1SPrashanth Swaminathan cif->bytes = bytes;
175*1fd5a2e1SPrashanth Swaminathan
176*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
177*1fd5a2e1SPrashanth Swaminathan }
178*1fd5a2e1SPrashanth Swaminathan
179*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue,
180*1fd5a2e1SPrashanth Swaminathan void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
181*1fd5a2e1SPrashanth Swaminathan
182*1fd5a2e1SPrashanth Swaminathan int FFI_HIDDEN
ffi_prep_args_v8(ffi_cif * cif,unsigned long * argp,void * rvalue,void ** avalue)183*1fd5a2e1SPrashanth Swaminathan ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
184*1fd5a2e1SPrashanth Swaminathan {
185*1fd5a2e1SPrashanth Swaminathan ffi_type **p_arg;
186*1fd5a2e1SPrashanth Swaminathan int flags = cif->flags;
187*1fd5a2e1SPrashanth Swaminathan int i, nargs;
188*1fd5a2e1SPrashanth Swaminathan
189*1fd5a2e1SPrashanth Swaminathan if (rvalue == NULL)
190*1fd5a2e1SPrashanth Swaminathan {
191*1fd5a2e1SPrashanth Swaminathan if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
192*1fd5a2e1SPrashanth Swaminathan {
193*1fd5a2e1SPrashanth Swaminathan /* Since we pass the pointer to the callee, we need a value.
194*1fd5a2e1SPrashanth Swaminathan We allowed for this space in ffi_call, before ffi_call_v8
195*1fd5a2e1SPrashanth Swaminathan alloca'd the space. */
196*1fd5a2e1SPrashanth Swaminathan rvalue = (char *)argp + cif->bytes;
197*1fd5a2e1SPrashanth Swaminathan }
198*1fd5a2e1SPrashanth Swaminathan else
199*1fd5a2e1SPrashanth Swaminathan {
200*1fd5a2e1SPrashanth Swaminathan /* Otherwise, we can ignore the return value. */
201*1fd5a2e1SPrashanth Swaminathan flags = SPARC_RET_VOID;
202*1fd5a2e1SPrashanth Swaminathan }
203*1fd5a2e1SPrashanth Swaminathan }
204*1fd5a2e1SPrashanth Swaminathan
205*1fd5a2e1SPrashanth Swaminathan /* This could only really be done when we are returning a structure.
206*1fd5a2e1SPrashanth Swaminathan However, the space is reserved so we can do it unconditionally. */
207*1fd5a2e1SPrashanth Swaminathan *argp++ = (unsigned long)rvalue;
208*1fd5a2e1SPrashanth Swaminathan
209*1fd5a2e1SPrashanth Swaminathan #ifdef USING_PURIFY
210*1fd5a2e1SPrashanth Swaminathan /* Purify will probably complain in our assembly routine,
211*1fd5a2e1SPrashanth Swaminathan unless we zero out this memory. */
212*1fd5a2e1SPrashanth Swaminathan memset(argp, 0, 6*4);
213*1fd5a2e1SPrashanth Swaminathan #endif
214*1fd5a2e1SPrashanth Swaminathan
215*1fd5a2e1SPrashanth Swaminathan p_arg = cif->arg_types;
216*1fd5a2e1SPrashanth Swaminathan for (i = 0, nargs = cif->nargs; i < nargs; i++)
217*1fd5a2e1SPrashanth Swaminathan {
218*1fd5a2e1SPrashanth Swaminathan ffi_type *ty = p_arg[i];
219*1fd5a2e1SPrashanth Swaminathan void *a = avalue[i];
220*1fd5a2e1SPrashanth Swaminathan int tt = ty->type;
221*1fd5a2e1SPrashanth Swaminathan size_t z;
222*1fd5a2e1SPrashanth Swaminathan
223*1fd5a2e1SPrashanth Swaminathan switch (tt)
224*1fd5a2e1SPrashanth Swaminathan {
225*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
226*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
227*1fd5a2e1SPrashanth Swaminathan by_reference:
228*1fd5a2e1SPrashanth Swaminathan *argp++ = (unsigned long)a;
229*1fd5a2e1SPrashanth Swaminathan break;
230*1fd5a2e1SPrashanth Swaminathan
231*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
232*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
233*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
234*1fd5a2e1SPrashanth Swaminathan memcpy(argp, a, 8);
235*1fd5a2e1SPrashanth Swaminathan argp += 2;
236*1fd5a2e1SPrashanth Swaminathan break;
237*1fd5a2e1SPrashanth Swaminathan
238*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
239*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
240*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
241*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
242*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
243*1fd5a2e1SPrashanth Swaminathan *argp++ = *(unsigned *)a;
244*1fd5a2e1SPrashanth Swaminathan break;
245*1fd5a2e1SPrashanth Swaminathan
246*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
247*1fd5a2e1SPrashanth Swaminathan *argp++ = *(UINT8 *)a;
248*1fd5a2e1SPrashanth Swaminathan break;
249*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
250*1fd5a2e1SPrashanth Swaminathan *argp++ = *(SINT8 *)a;
251*1fd5a2e1SPrashanth Swaminathan break;
252*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
253*1fd5a2e1SPrashanth Swaminathan *argp++ = *(UINT16 *)a;
254*1fd5a2e1SPrashanth Swaminathan break;
255*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
256*1fd5a2e1SPrashanth Swaminathan *argp++ = *(SINT16 *)a;
257*1fd5a2e1SPrashanth Swaminathan break;
258*1fd5a2e1SPrashanth Swaminathan
259*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
260*1fd5a2e1SPrashanth Swaminathan tt = ty->elements[0]->type;
261*1fd5a2e1SPrashanth Swaminathan z = ty->size;
262*1fd5a2e1SPrashanth Swaminathan if (tt == FFI_TYPE_FLOAT || z > 8)
263*1fd5a2e1SPrashanth Swaminathan goto by_reference;
264*1fd5a2e1SPrashanth Swaminathan if (z < 4)
265*1fd5a2e1SPrashanth Swaminathan {
266*1fd5a2e1SPrashanth Swaminathan memcpy((char *)argp + 4 - z, a, z);
267*1fd5a2e1SPrashanth Swaminathan argp++;
268*1fd5a2e1SPrashanth Swaminathan }
269*1fd5a2e1SPrashanth Swaminathan else
270*1fd5a2e1SPrashanth Swaminathan {
271*1fd5a2e1SPrashanth Swaminathan memcpy(argp, a, z);
272*1fd5a2e1SPrashanth Swaminathan argp += z / 4;
273*1fd5a2e1SPrashanth Swaminathan }
274*1fd5a2e1SPrashanth Swaminathan break;
275*1fd5a2e1SPrashanth Swaminathan
276*1fd5a2e1SPrashanth Swaminathan default:
277*1fd5a2e1SPrashanth Swaminathan abort();
278*1fd5a2e1SPrashanth Swaminathan }
279*1fd5a2e1SPrashanth Swaminathan }
280*1fd5a2e1SPrashanth Swaminathan
281*1fd5a2e1SPrashanth Swaminathan return flags;
282*1fd5a2e1SPrashanth Swaminathan }
283*1fd5a2e1SPrashanth Swaminathan
284*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)285*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
286*1fd5a2e1SPrashanth Swaminathan void **avalue, void *closure)
287*1fd5a2e1SPrashanth Swaminathan {
288*1fd5a2e1SPrashanth Swaminathan size_t bytes = cif->bytes;
289*1fd5a2e1SPrashanth Swaminathan
290*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (cif->abi == FFI_V8);
291*1fd5a2e1SPrashanth Swaminathan
292*1fd5a2e1SPrashanth Swaminathan /* If we've not got a return value, we need to create one if we've
293*1fd5a2e1SPrashanth Swaminathan got to pass the return value to the callee. Otherwise ignore it. */
294*1fd5a2e1SPrashanth Swaminathan if (rvalue == NULL
295*1fd5a2e1SPrashanth Swaminathan && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
296*1fd5a2e1SPrashanth Swaminathan bytes += FFI_ALIGN (cif->rtype->size, 8);
297*1fd5a2e1SPrashanth Swaminathan
298*1fd5a2e1SPrashanth Swaminathan ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
299*1fd5a2e1SPrashanth Swaminathan }
300*1fd5a2e1SPrashanth Swaminathan
301*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)302*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
303*1fd5a2e1SPrashanth Swaminathan {
304*1fd5a2e1SPrashanth Swaminathan ffi_call_int (cif, fn, rvalue, avalue, NULL);
305*1fd5a2e1SPrashanth Swaminathan }
306*1fd5a2e1SPrashanth Swaminathan
307*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)308*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
309*1fd5a2e1SPrashanth Swaminathan void **avalue, void *closure)
310*1fd5a2e1SPrashanth Swaminathan {
311*1fd5a2e1SPrashanth Swaminathan ffi_call_int (cif, fn, rvalue, avalue, closure);
312*1fd5a2e1SPrashanth Swaminathan }
313*1fd5a2e1SPrashanth Swaminathan
314*1fd5a2e1SPrashanth Swaminathan #ifdef __GNUC__
315*1fd5a2e1SPrashanth Swaminathan static inline void
ffi_flush_icache(void * p)316*1fd5a2e1SPrashanth Swaminathan ffi_flush_icache (void *p)
317*1fd5a2e1SPrashanth Swaminathan {
318*1fd5a2e1SPrashanth Swaminathan /* SPARC v8 requires 5 instructions for flush to be visible */
319*1fd5a2e1SPrashanth Swaminathan asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop"
320*1fd5a2e1SPrashanth Swaminathan : : "r" (p) : "memory");
321*1fd5a2e1SPrashanth Swaminathan }
322*1fd5a2e1SPrashanth Swaminathan #else
323*1fd5a2e1SPrashanth Swaminathan extern void ffi_flush_icache (void *) FFI_HIDDEN;
324*1fd5a2e1SPrashanth Swaminathan #endif
325*1fd5a2e1SPrashanth Swaminathan
326*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_v8(void) FFI_HIDDEN;
327*1fd5a2e1SPrashanth Swaminathan extern void ffi_go_closure_v8(void) FFI_HIDDEN;
328*1fd5a2e1SPrashanth Swaminathan
329*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)330*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure *closure,
331*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif,
332*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
333*1fd5a2e1SPrashanth Swaminathan void *user_data,
334*1fd5a2e1SPrashanth Swaminathan void *codeloc)
335*1fd5a2e1SPrashanth Swaminathan {
336*1fd5a2e1SPrashanth Swaminathan unsigned int *tramp = (unsigned int *) &closure->tramp[0];
337*1fd5a2e1SPrashanth Swaminathan unsigned long ctx = (unsigned long) closure;
338*1fd5a2e1SPrashanth Swaminathan unsigned long fn = (unsigned long) ffi_closure_v8;
339*1fd5a2e1SPrashanth Swaminathan
340*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_V8)
341*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
342*1fd5a2e1SPrashanth Swaminathan
343*1fd5a2e1SPrashanth Swaminathan tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
344*1fd5a2e1SPrashanth Swaminathan tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
345*1fd5a2e1SPrashanth Swaminathan tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
346*1fd5a2e1SPrashanth Swaminathan tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
347*1fd5a2e1SPrashanth Swaminathan
348*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
349*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
350*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
351*1fd5a2e1SPrashanth Swaminathan
352*1fd5a2e1SPrashanth Swaminathan ffi_flush_icache (closure);
353*1fd5a2e1SPrashanth Swaminathan
354*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
355*1fd5a2e1SPrashanth Swaminathan }
356*1fd5a2e1SPrashanth Swaminathan
357*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))358*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
359*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*))
360*1fd5a2e1SPrashanth Swaminathan {
361*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_V8)
362*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
363*1fd5a2e1SPrashanth Swaminathan
364*1fd5a2e1SPrashanth Swaminathan closure->tramp = ffi_go_closure_v8;
365*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
366*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
367*1fd5a2e1SPrashanth Swaminathan
368*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
369*1fd5a2e1SPrashanth Swaminathan }
370*1fd5a2e1SPrashanth Swaminathan
371*1fd5a2e1SPrashanth Swaminathan int FFI_HIDDEN
ffi_closure_sparc_inner_v8(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * rvalue,unsigned long * argp)372*1fd5a2e1SPrashanth Swaminathan ffi_closure_sparc_inner_v8(ffi_cif *cif,
373*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
374*1fd5a2e1SPrashanth Swaminathan void *user_data, void *rvalue,
375*1fd5a2e1SPrashanth Swaminathan unsigned long *argp)
376*1fd5a2e1SPrashanth Swaminathan {
377*1fd5a2e1SPrashanth Swaminathan ffi_type **arg_types;
378*1fd5a2e1SPrashanth Swaminathan void **avalue;
379*1fd5a2e1SPrashanth Swaminathan int i, nargs, flags;
380*1fd5a2e1SPrashanth Swaminathan
381*1fd5a2e1SPrashanth Swaminathan arg_types = cif->arg_types;
382*1fd5a2e1SPrashanth Swaminathan nargs = cif->nargs;
383*1fd5a2e1SPrashanth Swaminathan flags = cif->flags;
384*1fd5a2e1SPrashanth Swaminathan avalue = alloca(nargs * sizeof(void *));
385*1fd5a2e1SPrashanth Swaminathan
386*1fd5a2e1SPrashanth Swaminathan /* Copy the caller's structure return address so that the closure
387*1fd5a2e1SPrashanth Swaminathan returns the data directly to the caller. Also install it so we
388*1fd5a2e1SPrashanth Swaminathan can return the address in %o0. */
389*1fd5a2e1SPrashanth Swaminathan if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
390*1fd5a2e1SPrashanth Swaminathan {
391*1fd5a2e1SPrashanth Swaminathan void *new_rvalue = (void *)*argp;
392*1fd5a2e1SPrashanth Swaminathan *(void **)rvalue = new_rvalue;
393*1fd5a2e1SPrashanth Swaminathan rvalue = new_rvalue;
394*1fd5a2e1SPrashanth Swaminathan }
395*1fd5a2e1SPrashanth Swaminathan
396*1fd5a2e1SPrashanth Swaminathan /* Always skip the structure return address. */
397*1fd5a2e1SPrashanth Swaminathan argp++;
398*1fd5a2e1SPrashanth Swaminathan
399*1fd5a2e1SPrashanth Swaminathan /* Grab the addresses of the arguments from the stack frame. */
400*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < nargs; i++)
401*1fd5a2e1SPrashanth Swaminathan {
402*1fd5a2e1SPrashanth Swaminathan ffi_type *ty = arg_types[i];
403*1fd5a2e1SPrashanth Swaminathan int tt = ty->type;
404*1fd5a2e1SPrashanth Swaminathan void *a = argp;
405*1fd5a2e1SPrashanth Swaminathan size_t z;
406*1fd5a2e1SPrashanth Swaminathan
407*1fd5a2e1SPrashanth Swaminathan switch (tt)
408*1fd5a2e1SPrashanth Swaminathan {
409*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
410*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
411*1fd5a2e1SPrashanth Swaminathan by_reference:
412*1fd5a2e1SPrashanth Swaminathan /* Straight copy of invisible reference. */
413*1fd5a2e1SPrashanth Swaminathan a = (void *)*argp;
414*1fd5a2e1SPrashanth Swaminathan break;
415*1fd5a2e1SPrashanth Swaminathan
416*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
417*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
418*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
419*1fd5a2e1SPrashanth Swaminathan if ((unsigned long)a & 7)
420*1fd5a2e1SPrashanth Swaminathan {
421*1fd5a2e1SPrashanth Swaminathan /* Align on a 8-byte boundary. */
422*1fd5a2e1SPrashanth Swaminathan UINT64 *tmp = alloca(8);
423*1fd5a2e1SPrashanth Swaminathan *tmp = ((UINT64)argp[0] << 32) | argp[1];
424*1fd5a2e1SPrashanth Swaminathan a = tmp;
425*1fd5a2e1SPrashanth Swaminathan }
426*1fd5a2e1SPrashanth Swaminathan argp++;
427*1fd5a2e1SPrashanth Swaminathan break;
428*1fd5a2e1SPrashanth Swaminathan
429*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
430*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
431*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
432*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
433*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
434*1fd5a2e1SPrashanth Swaminathan break;
435*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
436*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
437*1fd5a2e1SPrashanth Swaminathan a += 2;
438*1fd5a2e1SPrashanth Swaminathan break;
439*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
440*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
441*1fd5a2e1SPrashanth Swaminathan a += 3;
442*1fd5a2e1SPrashanth Swaminathan break;
443*1fd5a2e1SPrashanth Swaminathan
444*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
445*1fd5a2e1SPrashanth Swaminathan tt = ty->elements[0]->type;
446*1fd5a2e1SPrashanth Swaminathan z = ty->size;
447*1fd5a2e1SPrashanth Swaminathan if (tt == FFI_TYPE_FLOAT || z > 8)
448*1fd5a2e1SPrashanth Swaminathan goto by_reference;
449*1fd5a2e1SPrashanth Swaminathan if (z < 4)
450*1fd5a2e1SPrashanth Swaminathan a += 4 - z;
451*1fd5a2e1SPrashanth Swaminathan else if (z > 4)
452*1fd5a2e1SPrashanth Swaminathan argp++;
453*1fd5a2e1SPrashanth Swaminathan break;
454*1fd5a2e1SPrashanth Swaminathan
455*1fd5a2e1SPrashanth Swaminathan default:
456*1fd5a2e1SPrashanth Swaminathan abort();
457*1fd5a2e1SPrashanth Swaminathan }
458*1fd5a2e1SPrashanth Swaminathan argp++;
459*1fd5a2e1SPrashanth Swaminathan avalue[i] = a;
460*1fd5a2e1SPrashanth Swaminathan }
461*1fd5a2e1SPrashanth Swaminathan
462*1fd5a2e1SPrashanth Swaminathan /* Invoke the closure. */
463*1fd5a2e1SPrashanth Swaminathan fun (cif, rvalue, avalue, user_data);
464*1fd5a2e1SPrashanth Swaminathan
465*1fd5a2e1SPrashanth Swaminathan /* Tell ffi_closure_sparc how to perform return type promotions. */
466*1fd5a2e1SPrashanth Swaminathan return flags;
467*1fd5a2e1SPrashanth Swaminathan }
468*1fd5a2e1SPrashanth Swaminathan #endif /* !SPARC64 */
469