]>
Commit | Line | Data |
---|---|---|
63e5e3e0 | 1 | /* ----------------------------------------------------------------------- |
0ce78f01 | 2 | ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc. |
63e5e3e0 | 3 | |
0ce78f01 | 4 | SPARC Foreign Function Interface |
63e5e3e0 | 5 | |
63e5e3e0 AG |
6 | Permission is hereby granted, free of charge, to any person obtaining |
7 | a copy of this software and associated documentation files (the | |
8 | ``Software''), to deal in the Software without restriction, including | |
9 | without limitation the rights to use, copy, modify, merge, publish, | |
10 | distribute, sublicense, and/or sell copies of the Software, and to | |
11 | permit persons to whom the Software is furnished to do so, subject to | |
12 | the following conditions: | |
13 | ||
14 | The above copyright notice and this permission notice shall be included | |
15 | in all copies or substantial portions of the Software. | |
16 | ||
17 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
20 | IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
23 | OTHER DEALINGS IN THE SOFTWARE. | |
24 | ----------------------------------------------------------------------- */ | |
25 | ||
26 | #include <ffi.h> | |
27 | #include <ffi_common.h> | |
28 | ||
29 | #include <stdlib.h> | |
30 | ||
c75c7793 | 31 | |
63e5e3e0 AG |
32 | /* ffi_prep_args is called by the assembly routine once stack space |
33 | has been allocated for the function's arguments */ | |
34 | ||
3791773c | 35 | void ffi_prep_args_v8(char *stack, extended_cif *ecif) |
63e5e3e0 AG |
36 | { |
37 | int i; | |
63e5e3e0 AG |
38 | void **p_argv; |
39 | char *argp; | |
40 | ffi_type **p_arg; | |
41 | ||
63e5e3e0 | 42 | /* Skip 16 words for the window save area */ |
3791773c | 43 | argp = stack + 16*sizeof(int); |
63e5e3e0 AG |
44 | |
45 | /* This should only really be done when we are returning a structure, | |
46 | however, it's faster just to do it all the time... | |
47 | ||
48 | if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */ | |
3791773c | 49 | *(int *) argp = (long)ecif->rvalue; |
63e5e3e0 AG |
50 | |
51 | /* And 1 word for the structure return value. */ | |
3791773c | 52 | argp += sizeof(int); |
63e5e3e0 AG |
53 | |
54 | #ifdef USING_PURIFY | |
55 | /* Purify will probably complain in our assembly routine, unless we | |
56 | zero out this memory. */ | |
57 | ||
58 | ((int*)argp)[0] = 0; | |
59 | ((int*)argp)[1] = 0; | |
60 | ((int*)argp)[2] = 0; | |
61 | ((int*)argp)[3] = 0; | |
62 | ((int*)argp)[4] = 0; | |
63 | ((int*)argp)[5] = 0; | |
64 | #endif | |
65 | ||
63e5e3e0 AG |
66 | p_argv = ecif->avalue; |
67 | ||
c94974ca | 68 | for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) |
63e5e3e0 AG |
69 | { |
70 | size_t z; | |
71 | ||
63e5e3e0 | 72 | if ((*p_arg)->type == FFI_TYPE_STRUCT |
3791773c JJ |
73 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
74 | || (*p_arg)->type == FFI_TYPE_LONGDOUBLE | |
75 | #endif | |
76 | ) | |
63e5e3e0 | 77 | { |
3791773c JJ |
78 | *(unsigned int *) argp = (unsigned long)(* p_argv); |
79 | z = sizeof(int); | |
63e5e3e0 AG |
80 | } |
81 | else | |
82 | { | |
83 | z = (*p_arg)->size; | |
84 | if (z < sizeof(int)) | |
85 | { | |
86 | z = sizeof(int); | |
87 | switch ((*p_arg)->type) | |
88 | { | |
89 | case FFI_TYPE_SINT8: | |
90 | *(signed int *) argp = *(SINT8 *)(* p_argv); | |
91 | break; | |
92 | ||
93 | case FFI_TYPE_UINT8: | |
94 | *(unsigned int *) argp = *(UINT8 *)(* p_argv); | |
95 | break; | |
96 | ||
97 | case FFI_TYPE_SINT16: | |
98 | *(signed int *) argp = *(SINT16 *)(* p_argv); | |
99 | break; | |
100 | ||
101 | case FFI_TYPE_UINT16: | |
102 | *(unsigned int *) argp = *(UINT16 *)(* p_argv); | |
103 | break; | |
3791773c | 104 | |
63e5e3e0 AG |
105 | default: |
106 | FFI_ASSERT(0); | |
107 | } | |
108 | } | |
109 | else | |
110 | { | |
111 | memcpy(argp, *p_argv, z); | |
112 | } | |
113 | } | |
114 | p_argv++; | |
115 | argp += z; | |
63e5e3e0 AG |
116 | } |
117 | ||
118 | return; | |
119 | } | |
120 | ||
3791773c JJ |
121 | int ffi_prep_args_v9(char *stack, extended_cif *ecif) |
122 | { | |
123 | int i, ret = 0; | |
124 | int tmp; | |
125 | void **p_argv; | |
126 | char *argp; | |
127 | ffi_type **p_arg; | |
128 | ||
129 | tmp = 0; | |
130 | ||
131 | /* Skip 16 words for the window save area */ | |
132 | argp = stack + 16*sizeof(long long); | |
133 | ||
134 | #ifdef USING_PURIFY | |
135 | /* Purify will probably complain in our assembly routine, unless we | |
136 | zero out this memory. */ | |
137 | ||
138 | ((long long*)argp)[0] = 0; | |
139 | ((long long*)argp)[1] = 0; | |
140 | ((long long*)argp)[2] = 0; | |
141 | ((long long*)argp)[3] = 0; | |
142 | ((long long*)argp)[4] = 0; | |
143 | ((long long*)argp)[5] = 0; | |
144 | #endif | |
145 | ||
146 | p_argv = ecif->avalue; | |
147 | ||
148 | if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && | |
149 | ecif->cif->rtype->size > 32) | |
150 | { | |
151 | *(unsigned long long *) argp = (unsigned long)ecif->rvalue; | |
0ce78f01 | 152 | argp += sizeof(long long); |
3791773c JJ |
153 | tmp = 1; |
154 | } | |
155 | ||
156 | for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; | |
157 | i++, p_arg++) | |
158 | { | |
159 | size_t z; | |
160 | ||
161 | z = (*p_arg)->size; | |
162 | switch ((*p_arg)->type) | |
163 | { | |
164 | case FFI_TYPE_STRUCT: | |
165 | if (z > 16) | |
166 | { | |
167 | /* For structures larger than 16 bytes we pass reference. */ | |
168 | *(unsigned long long *) argp = (unsigned long)* p_argv; | |
169 | argp += sizeof(long long); | |
170 | tmp++; | |
171 | p_argv++; | |
172 | continue; | |
173 | } | |
174 | /* FALLTHROUGH */ | |
175 | case FFI_TYPE_FLOAT: | |
176 | case FFI_TYPE_DOUBLE: | |
177 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
178 | case FFI_TYPE_LONGDOUBLE: | |
179 | #endif | |
180 | ret = 1; /* We should promote into FP regs as well as integer. */ | |
181 | break; | |
182 | } | |
183 | if (z < sizeof(long long)) | |
184 | { | |
185 | switch ((*p_arg)->type) | |
186 | { | |
187 | case FFI_TYPE_SINT8: | |
188 | *(signed long long *) argp = *(SINT8 *)(* p_argv); | |
189 | break; | |
190 | ||
191 | case FFI_TYPE_UINT8: | |
192 | *(unsigned long long *) argp = *(UINT8 *)(* p_argv); | |
193 | break; | |
194 | ||
195 | case FFI_TYPE_SINT16: | |
196 | *(signed long long *) argp = *(SINT16 *)(* p_argv); | |
197 | break; | |
198 | ||
199 | case FFI_TYPE_UINT16: | |
200 | *(unsigned long long *) argp = *(UINT16 *)(* p_argv); | |
201 | break; | |
202 | ||
203 | case FFI_TYPE_SINT32: | |
204 | *(signed long long *) argp = *(SINT32 *)(* p_argv); | |
205 | break; | |
206 | ||
207 | case FFI_TYPE_UINT32: | |
208 | *(unsigned long long *) argp = *(UINT32 *)(* p_argv); | |
209 | break; | |
210 | ||
211 | case FFI_TYPE_FLOAT: | |
212 | *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */ | |
213 | break; | |
214 | ||
215 | case FFI_TYPE_STRUCT: | |
216 | memcpy(argp, *p_argv, z); | |
217 | break; | |
218 | ||
219 | default: | |
220 | FFI_ASSERT(0); | |
221 | } | |
222 | z = sizeof(long long); | |
223 | tmp++; | |
224 | } | |
225 | else if (z == sizeof(long long)) | |
226 | { | |
227 | memcpy(argp, *p_argv, z); | |
228 | z = sizeof(long long); | |
229 | tmp++; | |
230 | } | |
231 | else | |
232 | { | |
233 | if ((tmp & 1) && (*p_arg)->alignment > 8) | |
234 | { | |
235 | tmp++; | |
236 | argp += sizeof(long long); | |
237 | } | |
238 | memcpy(argp, *p_argv, z); | |
239 | z = 2 * sizeof(long long); | |
240 | tmp += 2; | |
241 | } | |
242 | p_argv++; | |
243 | argp += z; | |
244 | } | |
245 | ||
246 | return ret; | |
247 | } | |
248 | ||
63e5e3e0 AG |
249 | /* Perform machine dependent cif processing */ |
250 | ffi_status ffi_prep_cif_machdep(ffi_cif *cif) | |
251 | { | |
3791773c JJ |
252 | int wordsize; |
253 | ||
254 | if (cif->abi != FFI_V9) | |
255 | { | |
256 | wordsize = 4; | |
63e5e3e0 | 257 | |
3791773c JJ |
258 | /* If we are returning a struct, this will already have been added. |
259 | Otherwise we need to add it because it's always got to be there! */ | |
63e5e3e0 | 260 | |
3791773c JJ |
261 | if (cif->rtype->type != FFI_TYPE_STRUCT) |
262 | cif->bytes += wordsize; | |
263 | ||
264 | /* sparc call frames require that space is allocated for 6 args, | |
265 | even if they aren't used. Make that space if necessary. */ | |
63e5e3e0 | 266 | |
3791773c JJ |
267 | if (cif->bytes < 4*6+4) |
268 | cif->bytes = 4*6+4; | |
269 | } | |
270 | else | |
271 | { | |
272 | wordsize = 8; | |
273 | ||
274 | /* sparc call frames require that space is allocated for 6 args, | |
275 | even if they aren't used. Make that space if necessary. */ | |
276 | ||
277 | if (cif->bytes < 8*6) | |
278 | cif->bytes = 8*6; | |
279 | } | |
63e5e3e0 AG |
280 | |
281 | /* Adjust cif->bytes. to include 16 words for the window save area, | |
282 | and maybe the struct/union return pointer area, */ | |
283 | ||
3791773c | 284 | cif->bytes += 16 * wordsize; |
63e5e3e0 | 285 | |
3791773c | 286 | /* The stack must be 2 word aligned, so round bytes up |
63e5e3e0 AG |
287 | appropriately. */ |
288 | ||
3791773c | 289 | cif->bytes = ALIGN(cif->bytes, 2 * wordsize); |
63e5e3e0 AG |
290 | |
291 | /* Set the return type flag */ | |
292 | switch (cif->rtype->type) | |
293 | { | |
294 | case FFI_TYPE_VOID: | |
63e5e3e0 | 295 | case FFI_TYPE_FLOAT: |
3791773c JJ |
296 | case FFI_TYPE_DOUBLE: |
297 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
298 | case FFI_TYPE_LONGDOUBLE: | |
299 | #endif | |
300 | cif->flags = cif->rtype->type; | |
63e5e3e0 AG |
301 | break; |
302 | ||
3791773c JJ |
303 | case FFI_TYPE_STRUCT: |
304 | if (cif->abi == FFI_V9 && cif->rtype->size > 32) | |
305 | cif->flags = FFI_TYPE_VOID; | |
306 | else | |
307 | cif->flags = FFI_TYPE_STRUCT; | |
63e5e3e0 AG |
308 | break; |
309 | ||
3791773c JJ |
310 | case FFI_TYPE_SINT64: |
311 | case FFI_TYPE_UINT64: | |
312 | if (cif->abi != FFI_V9) | |
313 | { | |
314 | cif->flags = FFI_TYPE_SINT64; | |
315 | break; | |
316 | } | |
317 | /* FALLTHROUGH */ | |
63e5e3e0 AG |
318 | default: |
319 | cif->flags = FFI_TYPE_INT; | |
320 | break; | |
321 | } | |
63e5e3e0 AG |
322 | return FFI_OK; |
323 | } | |
324 | ||
0ce78f01 | 325 | int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) |
3791773c JJ |
326 | { |
327 | ffi_type **ptr = &arg->elements[0]; | |
328 | ||
329 | while (*ptr != NULL) | |
330 | { | |
331 | if (off & ((*ptr)->alignment - 1)) | |
332 | off = ALIGN(off, (*ptr)->alignment); | |
333 | ||
334 | switch ((*ptr)->type) | |
335 | { | |
336 | case FFI_TYPE_STRUCT: | |
0ce78f01 EB |
337 | off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt); |
338 | off = ALIGN(off, FFI_SIZEOF_ARG); | |
3791773c JJ |
339 | break; |
340 | case FFI_TYPE_FLOAT: | |
341 | case FFI_TYPE_DOUBLE: | |
342 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
343 | case FFI_TYPE_LONGDOUBLE: | |
344 | #endif | |
0ce78f01 | 345 | memmove(ret + off, flt + off, (*ptr)->size); |
3791773c JJ |
346 | off += (*ptr)->size; |
347 | break; | |
348 | default: | |
0ce78f01 | 349 | memmove(ret + off, intg + off, (*ptr)->size); |
3791773c JJ |
350 | off += (*ptr)->size; |
351 | break; | |
352 | } | |
353 | ptr++; | |
354 | } | |
355 | return off; | |
356 | } | |
357 | ||
0ce78f01 EB |
358 | |
359 | #ifdef SPARC64 | |
360 | extern int ffi_call_v9(void *, extended_cif *, unsigned, | |
63e5e3e0 | 361 | unsigned, unsigned *, void (*fn)()); |
0ce78f01 EB |
362 | #else |
363 | extern int ffi_call_v8(void *, extended_cif *, unsigned, | |
3791773c | 364 | unsigned, unsigned *, void (*fn)()); |
0ce78f01 | 365 | #endif |
63e5e3e0 AG |
366 | |
367 | void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) | |
368 | { | |
369 | extended_cif ecif; | |
3791773c | 370 | void *rval = rvalue; |
63e5e3e0 AG |
371 | |
372 | ecif.cif = cif; | |
373 | ecif.avalue = avalue; | |
3791773c | 374 | |
63e5e3e0 AG |
375 | /* If the return value is a struct and we don't have a return */ |
376 | /* value address then we need to make one */ | |
3791773c JJ |
377 | |
378 | ecif.rvalue = rvalue; | |
379 | if (cif->rtype->type == FFI_TYPE_STRUCT) | |
380 | { | |
381 | if (cif->rtype->size <= 32) | |
382 | rval = alloca(64); | |
383 | else | |
384 | { | |
385 | rval = NULL; | |
386 | if (rvalue == NULL) | |
387 | ecif.rvalue = alloca(cif->rtype->size); | |
388 | } | |
389 | } | |
390 | ||
63e5e3e0 AG |
391 | switch (cif->abi) |
392 | { | |
393 | case FFI_V8: | |
3791773c JJ |
394 | #ifdef SPARC64 |
395 | /* We don't yet support calling 32bit code from 64bit */ | |
396 | FFI_ASSERT(0); | |
397 | #else | |
0ce78f01 | 398 | ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, |
63e5e3e0 | 399 | cif->flags, rvalue, fn); |
3791773c JJ |
400 | #endif |
401 | break; | |
402 | case FFI_V9: | |
403 | #ifdef SPARC64 | |
0ce78f01 | 404 | ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, |
3791773c JJ |
405 | cif->flags, rval, fn); |
406 | if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT) | |
0ce78f01 | 407 | ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32); |
3791773c JJ |
408 | #else |
409 | /* And vice versa */ | |
410 | FFI_ASSERT(0); | |
411 | #endif | |
63e5e3e0 AG |
412 | break; |
413 | default: | |
414 | FFI_ASSERT(0); | |
415 | break; | |
416 | } | |
3791773c | 417 | |
63e5e3e0 | 418 | } |
c75c7793 | 419 | |
0ce78f01 EB |
420 | |
421 | #ifdef SPARC64 | |
422 | extern void ffi_closure_v9(void); | |
423 | #else | |
424 | extern void ffi_closure_v8(void); | |
425 | #endif | |
426 | ||
c75c7793 JS |
427 | ffi_status |
428 | ffi_prep_closure (ffi_closure* closure, | |
429 | ffi_cif* cif, | |
430 | void (*fun)(ffi_cif*, void*, void**, void*), | |
431 | void *user_data) | |
432 | { | |
433 | unsigned int *tramp = (unsigned int *) &closure->tramp[0]; | |
434 | unsigned long fn; | |
c75c7793 JS |
435 | #ifdef SPARC64 |
436 | /* Trampoline address is equal to the closure address. We take advantage | |
437 | of that to reduce the trampoline size by 8 bytes. */ | |
438 | FFI_ASSERT (cif->abi == FFI_V9); | |
439 | fn = (unsigned long) ffi_closure_v9; | |
440 | tramp[0] = 0x83414000; /* rd %pc, %g1 */ | |
441 | tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */ | |
442 | tramp[2] = 0x81c14000; /* jmp %g5 */ | |
443 | tramp[3] = 0x01000000; /* nop */ | |
444 | *((unsigned long *) &tramp[4]) = fn; | |
445 | #else | |
0ce78f01 | 446 | unsigned long ctx = (unsigned long) closure; |
c75c7793 JS |
447 | FFI_ASSERT (cif->abi == FFI_V8); |
448 | fn = (unsigned long) ffi_closure_v8; | |
449 | tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */ | |
450 | tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */ | |
451 | tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */ | |
452 | tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */ | |
453 | #endif | |
454 | ||
455 | closure->cif = cif; | |
456 | closure->fun = fun; | |
457 | closure->user_data = user_data; | |
458 | ||
459 | /* Flush the Icache. FIXME: alignment isn't certain, assume 8 bytes */ | |
460 | #ifdef SPARC64 | |
461 | asm volatile ("flush %0" : : "r" (closure) : "memory"); | |
462 | asm volatile ("flush %0" : : "r" (((char *) closure) + 8) : "memory"); | |
463 | #else | |
464 | asm volatile ("iflush %0" : : "r" (closure) : "memory"); | |
465 | asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory"); | |
466 | #endif | |
467 | ||
468 | return FFI_OK; | |
469 | } | |
470 | ||
471 | int | |
0ce78f01 EB |
472 | ffi_closure_sparc_inner_v8(ffi_closure *closure, |
473 | void *rvalue, unsigned long *gpr) | |
c75c7793 JS |
474 | { |
475 | ffi_cif *cif; | |
c75c7793 | 476 | ffi_type **arg_types; |
0ce78f01 EB |
477 | void **avalue; |
478 | int i, argn; | |
c75c7793 JS |
479 | |
480 | cif = closure->cif; | |
0ce78f01 | 481 | arg_types = cif->arg_types; |
c75c7793 JS |
482 | avalue = alloca(cif->nargs * sizeof(void *)); |
483 | ||
0ce78f01 EB |
484 | /* Copy the caller's structure return address so that the closure |
485 | returns the data directly to the caller. */ | |
486 | if (cif->flags == FFI_TYPE_STRUCT | |
487 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
488 | || cif->flags == FFI_TYPE_LONGDOUBLE | |
489 | #endif | |
490 | ) | |
491 | rvalue = (void *) gpr[0]; | |
492 | ||
493 | /* Always skip the structure return address. */ | |
494 | argn = 1; | |
495 | ||
496 | /* Grab the addresses of the arguments from the stack frame. */ | |
497 | for (i = 0; i < cif->nargs; i++) | |
498 | { | |
499 | if (arg_types[i]->type == FFI_TYPE_STRUCT | |
500 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
501 | || arg_types[i]->type == FFI_TYPE_LONGDOUBLE | |
502 | #endif | |
503 | ) | |
504 | { | |
505 | /* Straight copy of invisible reference. */ | |
506 | avalue[i] = (void *)gpr[argn++]; | |
507 | } | |
508 | else | |
509 | { | |
510 | /* Always right-justify. */ | |
511 | argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; | |
512 | avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; | |
513 | } | |
514 | } | |
c75c7793 | 515 | |
0ce78f01 EB |
516 | /* Invoke the closure. */ |
517 | (closure->fun) (cif, rvalue, avalue, closure->user_data); | |
518 | ||
519 | /* Tell ffi_closure_sparc how to perform return type promotions. */ | |
520 | return cif->rtype->type; | |
521 | } | |
522 | ||
523 | int | |
524 | ffi_closure_sparc_inner_v9(ffi_closure *closure, | |
525 | void *rvalue, unsigned long *gpr, double *fpr) | |
526 | { | |
527 | ffi_cif *cif; | |
528 | ffi_type **arg_types; | |
529 | void **avalue; | |
530 | int i, argn, fp_slot_max; | |
531 | ||
532 | cif = closure->cif; | |
533 | arg_types = cif->arg_types; | |
534 | avalue = alloca(cif->nargs * sizeof(void *)); | |
535 | ||
536 | /* Copy the caller's structure return address so that the closure | |
c75c7793 | 537 | returns the data directly to the caller. */ |
0ce78f01 EB |
538 | if (cif->flags == FFI_TYPE_VOID |
539 | && cif->rtype->type == FFI_TYPE_STRUCT) | |
c75c7793 JS |
540 | { |
541 | rvalue = (void *) gpr[0]; | |
0ce78f01 | 542 | /* Skip the structure return address. */ |
c75c7793 JS |
543 | argn = 1; |
544 | } | |
0ce78f01 EB |
545 | else |
546 | argn = 0; | |
547 | ||
548 | fp_slot_max = 16 - argn; | |
c75c7793 | 549 | |
c75c7793 | 550 | /* Grab the addresses of the arguments from the stack frame. */ |
0ce78f01 | 551 | for (i = 0; i < cif->nargs; i++) |
c75c7793 | 552 | { |
0ce78f01 EB |
553 | if (arg_types[i]->type == FFI_TYPE_STRUCT) |
554 | { | |
555 | if (arg_types[i]->size > 16) | |
556 | { | |
557 | /* Straight copy of invisible reference. */ | |
558 | avalue[i] = (void *)gpr[argn++]; | |
559 | } | |
560 | else | |
561 | { | |
562 | /* Left-justify. */ | |
563 | ffi_v9_layout_struct(arg_types[i], | |
564 | 0, | |
565 | (char *) &gpr[argn], | |
566 | (char *) &gpr[argn], | |
567 | (char *) &fpr[argn]); | |
568 | avalue[i] = &gpr[argn]; | |
569 | argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; | |
570 | } | |
571 | } | |
572 | else | |
573 | { | |
574 | /* Right-justify. */ | |
575 | argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; | |
c75c7793 | 576 | |
0ce78f01 EB |
577 | if (i < fp_slot_max |
578 | && (arg_types[i]->type == FFI_TYPE_FLOAT | |
579 | || arg_types[i]->type == FFI_TYPE_DOUBLE | |
c75c7793 | 580 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
0ce78f01 | 581 | || arg_types[i]->type == FFI_TYPE_LONGDOUBLE |
c75c7793 | 582 | #endif |
0ce78f01 EB |
583 | )) |
584 | avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size; | |
585 | else | |
586 | avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; | |
587 | } | |
c75c7793 JS |
588 | } |
589 | ||
590 | /* Invoke the closure. */ | |
591 | (closure->fun) (cif, rvalue, avalue, closure->user_data); | |
592 | ||
593 | /* Tell ffi_closure_sparc how to perform return type promotions. */ | |
594 | return cif->rtype->type; | |
595 | } |