OSDN Git Service

Initial Contribution
[android-x86/external-libffi.git] / src / sh / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006 Kaz Kojima
3    
4    SuperH Foreign Function Interface 
5
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
31 #define NGREGARG 4
32 #if defined(__SH4__)
33 #define NFREGARG 8
34 #endif
35
36 #if defined(__HITACHI__)
37 #define STRUCT_VALUE_ADDRESS_WITH_ARG 1
38 #else
39 #define STRUCT_VALUE_ADDRESS_WITH_ARG 0
40 #endif
41
42 /* If the structure has essentialy an unique element, return its type.  */
43 static int
44 simple_type (ffi_type *arg)
45 {
46   if (arg->type != FFI_TYPE_STRUCT)
47     return arg->type;
48   else if (arg->elements[1])
49     return FFI_TYPE_STRUCT;
50
51   return simple_type (arg->elements[0]);
52 }
53
54 static int
55 return_type (ffi_type *arg)
56 {
57   unsigned short type;
58
59   if (arg->type != FFI_TYPE_STRUCT)
60     return arg->type;
61
62   type = simple_type (arg->elements[0]);
63   if (! arg->elements[1])
64     {
65       switch (type)
66         {
67         case FFI_TYPE_SINT8:
68         case FFI_TYPE_UINT8:
69         case FFI_TYPE_SINT16:
70         case FFI_TYPE_UINT16:
71         case FFI_TYPE_SINT32:
72         case FFI_TYPE_UINT32:
73           return FFI_TYPE_INT;
74
75         default:
76           return type;
77         }
78     }
79
80   /* gcc uses r0/r1 pair for some kind of structures.  */
81   if (arg->size <= 2 * sizeof (int))
82     {
83       int i = 0;
84       ffi_type *e;
85
86       while ((e = arg->elements[i++]))
87         {
88           type = simple_type (e);
89           switch (type)
90             {
91             case FFI_TYPE_SINT32:
92             case FFI_TYPE_UINT32:
93             case FFI_TYPE_INT:
94             case FFI_TYPE_FLOAT:
95               return FFI_TYPE_UINT64;
96
97             default:
98               break;
99             }
100         }
101     }
102
103   return FFI_TYPE_STRUCT;
104 }
105
106 /* ffi_prep_args is called by the assembly routine once stack space
107    has been allocated for the function's arguments */
108
109 void ffi_prep_args(char *stack, extended_cif *ecif)
110 {
111   register unsigned int i;
112   register int tmp;
113   register unsigned int avn;
114   register void **p_argv;
115   register char *argp;
116   register ffi_type **p_arg;
117   int greg, ireg;
118 #if defined(__SH4__)
119   int freg = 0;
120 #endif
121
122   tmp = 0;
123   argp = stack;
124
125   if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
126     {
127       *(void **) argp = ecif->rvalue;
128       argp += 4;
129       ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
130     }
131   else
132     ireg = 0;
133
134   /* Set arguments for registers.  */
135   greg = ireg;
136   avn = ecif->cif->nargs;
137   p_argv = ecif->avalue;
138
139   for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
140     {
141       size_t z;
142
143       z = (*p_arg)->size;
144       if (z < sizeof(int))
145         {
146           if (greg++ >= NGREGARG)
147             continue;
148
149           z = sizeof(int);
150           switch ((*p_arg)->type)
151             {
152             case FFI_TYPE_SINT8:
153               *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
154               break;
155   
156             case FFI_TYPE_UINT8:
157               *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
158               break;
159   
160             case FFI_TYPE_SINT16:
161               *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
162               break;
163   
164             case FFI_TYPE_UINT16:
165               *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
166               break;
167   
168             case FFI_TYPE_STRUCT:
169               *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
170               break;
171
172             default:
173               FFI_ASSERT(0);
174             }
175           argp += z;
176         }
177       else if (z == sizeof(int))
178         {
179 #if defined(__SH4__)
180           if ((*p_arg)->type == FFI_TYPE_FLOAT)
181             {
182               if (freg++ >= NFREGARG)
183                 continue;
184             }
185           else
186 #endif
187             {
188               if (greg++ >= NGREGARG)
189                 continue;
190             }
191           *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
192           argp += z;
193         }
194 #if defined(__SH4__)
195       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
196         {
197           if (freg + 1 >= NFREGARG)
198             continue;
199           freg = (freg + 1) & ~1;
200           freg += 2;
201           memcpy (argp, *p_argv, z);
202           argp += z;
203         }
204 #endif
205       else
206         {
207           int n = (z + sizeof (int) - 1) / sizeof (int);
208 #if defined(__SH4__)
209           if (greg + n - 1 >= NGREGARG)
210             continue;
211 #else
212           if (greg >= NGREGARG)
213             continue;
214 #endif
215           greg += n;
216           memcpy (argp, *p_argv, z);
217           argp += n * sizeof (int);
218         }
219     }
220
221   /* Set arguments on stack.  */
222   greg = ireg;
223 #if defined(__SH4__)
224   freg = 0;
225 #endif
226   p_argv = ecif->avalue;
227
228   for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
229     {
230       size_t z;
231
232       z = (*p_arg)->size;
233       if (z < sizeof(int))
234         {
235           if (greg++ < NGREGARG)
236             continue;
237
238           z = sizeof(int);
239           switch ((*p_arg)->type)
240             {
241             case FFI_TYPE_SINT8:
242               *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
243               break;
244   
245             case FFI_TYPE_UINT8:
246               *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
247               break;
248   
249             case FFI_TYPE_SINT16:
250               *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
251               break;
252   
253             case FFI_TYPE_UINT16:
254               *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
255               break;
256   
257             case FFI_TYPE_STRUCT:
258               *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
259               break;
260
261             default:
262               FFI_ASSERT(0);
263             }
264           argp += z;
265         }
266       else if (z == sizeof(int))
267         {
268 #if defined(__SH4__)
269           if ((*p_arg)->type == FFI_TYPE_FLOAT)
270             {
271               if (freg++ < NFREGARG)
272                 continue;
273             }
274           else
275 #endif
276             {
277               if (greg++ < NGREGARG)
278                 continue;
279             }
280           *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
281           argp += z;
282         }
283 #if defined(__SH4__)
284       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
285         {
286           if (freg + 1 < NFREGARG)
287             {
288               freg = (freg + 1) & ~1;
289               freg += 2;
290               continue;
291             }
292           memcpy (argp, *p_argv, z);
293           argp += z;
294         }
295 #endif
296       else
297         {
298           int n = (z + sizeof (int) - 1) / sizeof (int);
299           if (greg + n - 1 < NGREGARG)
300             {
301               greg += n;
302               continue;
303             }
304 #if (! defined(__SH4__))
305           else if (greg < NGREGARG)
306             {
307               greg = NGREGARG;
308               continue;
309             }
310 #endif
311           memcpy (argp, *p_argv, z);
312           argp += n * sizeof (int);
313         }
314     }
315
316   return;
317 }
318
319 /* Perform machine dependent cif processing */
320 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
321 {
322   int i, j;
323   int size, type;
324   int n, m;
325   int greg;
326 #if defined(__SH4__)
327   int freg = 0;
328 #endif
329
330   cif->flags = 0;
331
332   greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
333           STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
334
335 #if defined(__SH4__)
336   for (i = j = 0; i < cif->nargs && j < 12; i++)
337     {
338       type = (cif->arg_types)[i]->type;
339       switch (type)
340         {
341         case FFI_TYPE_FLOAT:
342           if (freg >= NFREGARG)
343             continue;
344           freg++;
345           cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
346           j++;
347           break;
348
349         case FFI_TYPE_DOUBLE:
350           if ((freg + 1) >= NFREGARG)
351             continue;
352           freg = (freg + 1) & ~1;
353           freg += 2;
354           cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
355           j++;
356           break;
357               
358         default:
359           size = (cif->arg_types)[i]->size;
360           n = (size + sizeof (int) - 1) / sizeof (int);
361           if (greg + n - 1 >= NGREGARG)
362                 continue;
363           greg += n;
364           for (m = 0; m < n; m++)
365             cif->flags += FFI_TYPE_INT << (2 * j++);
366           break;
367         }
368     }
369 #else
370   for (i = j = 0; i < cif->nargs && j < 4; i++)
371     {
372       size = (cif->arg_types)[i]->size;
373       n = (size + sizeof (int) - 1) / sizeof (int);
374       if (greg >= NGREGARG)
375         continue;
376       else if (greg + n - 1 >= NGREGARG)
377         n = NGREGARG - greg;
378       greg += n;
379       for (m = 0; m < n; m++)
380         cif->flags += FFI_TYPE_INT << (2 * j++);
381     }
382 #endif
383
384   /* Set the return type flag */
385   switch (cif->rtype->type)
386     {
387     case FFI_TYPE_STRUCT:
388       cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
389       break;
390
391     case FFI_TYPE_VOID:
392     case FFI_TYPE_FLOAT:
393     case FFI_TYPE_DOUBLE:
394     case FFI_TYPE_SINT64:
395     case FFI_TYPE_UINT64:
396       cif->flags += (unsigned) cif->rtype->type << 24;
397       break;
398
399     default:
400       cif->flags += FFI_TYPE_INT << 24;
401       break;
402     }
403
404   return FFI_OK;
405 }
406
407 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
408                           unsigned, unsigned, unsigned *, void (*fn)());
409
410 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
411 {
412   extended_cif ecif;
413   UINT64 trvalue;
414
415   ecif.cif = cif;
416   ecif.avalue = avalue;
417   
418   /* If the return value is a struct and we don't have a return */
419   /* value address then we need to make one                     */
420
421   if (cif->rtype->type == FFI_TYPE_STRUCT
422       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
423     ecif.rvalue = &trvalue;
424   else if ((rvalue == NULL) && 
425       (cif->rtype->type == FFI_TYPE_STRUCT))
426     {
427       ecif.rvalue = alloca(cif->rtype->size);
428     }
429   else
430     ecif.rvalue = rvalue;
431
432   switch (cif->abi) 
433     {
434     case FFI_SYSV:
435       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
436                     fn);
437       break;
438     default:
439       FFI_ASSERT(0);
440       break;
441     }
442
443   if (rvalue
444       && cif->rtype->type == FFI_TYPE_STRUCT
445       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
446     memcpy (rvalue, &trvalue, cif->rtype->size);
447 }
448
449 extern void ffi_closure_SYSV (void);
450 #if defined(__SH4__)
451 extern void __ic_invalidate (void *line);
452 #endif
453
454 ffi_status
455 ffi_prep_closure (ffi_closure* closure,
456                   ffi_cif* cif,
457                   void (*fun)(ffi_cif*, void*, void**, void*),
458                   void *user_data)
459 {
460   unsigned int *tramp;
461   unsigned short insn;
462
463   FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
464
465   tramp = (unsigned int *) &closure->tramp[0];
466   /* Set T bit if the function returns a struct pointed with R2.  */
467   insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT
468           ? 0x0018 /* sett */
469           : 0x0008 /* clrt */);
470
471 #ifdef __LITTLE_ENDIAN__
472   tramp[0] = 0xd301d102;
473   tramp[1] = 0x0000412b | (insn << 16);
474 #else
475   tramp[0] = 0xd102d301;
476   tramp[1] = 0x412b0000 | insn;
477 #endif
478   *(void **) &tramp[2] = (void *)closure;          /* ctx */
479   *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
480
481   closure->cif = cif;
482   closure->fun = fun;
483   closure->user_data = user_data;
484
485 #if defined(__SH4__)
486   /* Flush the icache.  */
487   __ic_invalidate(&closure->tramp[0]);
488 #endif
489
490   return FFI_OK;
491 }
492
493 /* Basically the trampoline invokes ffi_closure_SYSV, and on 
494  * entry, r3 holds the address of the closure.
495  * After storing the registers that could possibly contain
496  * parameters to be passed into the stack frame and setting
497  * up space for a return value, ffi_closure_SYSV invokes the 
498  * following helper function to do most of the work.
499  */
500
501 #ifdef __LITTLE_ENDIAN__
502 #define OFS_INT8        0
503 #define OFS_INT16       0
504 #else
505 #define OFS_INT8        3
506 #define OFS_INT16       2
507 #endif
508
509 int
510 ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, 
511                          unsigned long *pgr, unsigned long *pfr, 
512                          unsigned long *pst)
513 {
514   void **avalue;
515   ffi_type **p_arg;
516   int i, avn;
517   int ireg, greg = 0;
518 #if defined(__SH4__)
519   int freg = 0;
520 #endif
521   ffi_cif *cif; 
522
523   cif = closure->cif;
524   avalue = alloca(cif->nargs * sizeof(void *));
525
526   /* Copy the caller's structure return value address so that the closure
527      returns the data directly to the caller.  */
528   if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
529     {
530       rvalue = (void *) *pgr++;
531       ireg = 1;
532     }
533   else
534     ireg = 0;
535
536   cif = closure->cif;
537   greg = ireg;
538   avn = cif->nargs;
539
540   /* Grab the addresses of the arguments from the stack frame.  */
541   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
542     {
543       size_t z;
544
545       z = (*p_arg)->size;
546       if (z < sizeof(int))
547         {
548           if (greg++ >= NGREGARG)
549             continue;
550
551           z = sizeof(int);
552           switch ((*p_arg)->type)
553             {
554             case FFI_TYPE_SINT8:
555             case FFI_TYPE_UINT8:
556               avalue[i] = (((char *)pgr) + OFS_INT8);
557               break;
558   
559             case FFI_TYPE_SINT16:
560             case FFI_TYPE_UINT16:
561               avalue[i] = (((char *)pgr) + OFS_INT16);
562               break;
563   
564             case FFI_TYPE_STRUCT:
565               avalue[i] = pgr;
566               break;
567
568             default:
569               FFI_ASSERT(0);
570             }
571           pgr++;
572         }
573       else if (z == sizeof(int))
574         {
575 #if defined(__SH4__)
576           if ((*p_arg)->type == FFI_TYPE_FLOAT)
577             {
578               if (freg++ >= NFREGARG)
579                 continue;
580               avalue[i] = pfr;
581               pfr++;
582             }
583           else
584 #endif
585             {
586               if (greg++ >= NGREGARG)
587                 continue;
588               avalue[i] = pgr;
589               pgr++;
590             }
591         }
592 #if defined(__SH4__)
593       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
594         {
595           if (freg + 1 >= NFREGARG)
596             continue;
597           if (freg & 1)
598             pfr++;
599           freg = (freg + 1) & ~1;
600           freg += 2;
601           avalue[i] = pfr;
602           pfr += 2;
603         }
604 #endif
605       else
606         {
607           int n = (z + sizeof (int) - 1) / sizeof (int);
608 #if defined(__SH4__)
609           if (greg + n - 1 >= NGREGARG)
610             continue;
611 #else
612           if (greg >= NGREGARG)
613             continue;
614 #endif
615           greg += n;
616           avalue[i] = pgr;
617           pgr += n;
618         }
619     }
620
621   greg = ireg;
622 #if defined(__SH4__)
623   freg = 0;
624 #endif
625
626   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
627     {
628       size_t z;
629
630       z = (*p_arg)->size;
631       if (z < sizeof(int))
632         {
633           if (greg++ < NGREGARG)
634             continue;
635
636           z = sizeof(int);
637           switch ((*p_arg)->type)
638             {
639             case FFI_TYPE_SINT8:
640             case FFI_TYPE_UINT8:
641               avalue[i] = (((char *)pst) + OFS_INT8);
642               break;
643   
644             case FFI_TYPE_SINT16:
645             case FFI_TYPE_UINT16:
646               avalue[i] = (((char *)pst) + OFS_INT16);
647               break;
648   
649             case FFI_TYPE_STRUCT:
650               avalue[i] = pst;
651               break;
652
653             default:
654               FFI_ASSERT(0);
655             }
656           pst++;
657         }
658       else if (z == sizeof(int))
659         {
660 #if defined(__SH4__)
661           if ((*p_arg)->type == FFI_TYPE_FLOAT)
662             {
663               if (freg++ < NFREGARG)
664                 continue;
665             }
666           else
667 #endif
668             {
669               if (greg++ < NGREGARG)
670                 continue;
671             }
672           avalue[i] = pst;
673           pst++;
674         }
675 #if defined(__SH4__)
676       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
677         {
678           if (freg + 1 < NFREGARG)
679             {
680               freg = (freg + 1) & ~1;
681               freg += 2;
682               continue;
683             }
684           avalue[i] = pst;
685           pst += 2;
686         }
687 #endif
688       else
689         {
690           int n = (z + sizeof (int) - 1) / sizeof (int);
691           if (greg + n - 1 < NGREGARG)
692             {
693               greg += n;
694               continue;
695             }
696 #if (! defined(__SH4__))
697           else if (greg < NGREGARG)
698             {
699               greg += n;
700               pst += greg - NGREGARG;
701               continue;
702             }
703 #endif
704           avalue[i] = pst;
705           pst += n;
706         }
707     }
708
709   (closure->fun) (cif, rvalue, avalue, closure->user_data);
710
711   /* Tell ffi_closure_SYSV how to perform return type promotions.  */
712   return return_type (cif->rtype);
713 }