Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / ctypes / libffi / src / moxie / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (C) 2009  Anthony Green
3    
4    Moxie 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,
18    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24    DEALINGS IN THE SOFTWARE.
25    ----------------------------------------------------------------------- */
26
27 #include <ffi.h>
28 #include <ffi_common.h>
29
30 #include <stdlib.h>
31
32 /* ffi_prep_args is called by the assembly routine once stack space
33    has been allocated for the function's arguments */
34
35 void *ffi_prep_args(char *stack, extended_cif *ecif)
36 {
37   register unsigned int i;
38   register void **p_argv;
39   register char *argp;
40   register ffi_type **p_arg;
41   register int count = 0;
42
43   p_argv = ecif->avalue;
44   argp = stack;
45
46   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
47        (i != 0);
48        i--, p_arg++)
49     {
50       size_t z;
51       
52       z = (*p_arg)->size;
53
54       if ((*p_arg)->type == FFI_TYPE_STRUCT)
55         {
56           z = sizeof(void*);
57           *(void **) argp = *p_argv;
58         } 
59       /*      if ((*p_arg)->type == FFI_TYPE_FLOAT)
60         {
61           if (count > 24)
62             {
63               // This is going on the stack.  Turn it into a double.  
64               *(double *) argp = (double) *(float*)(* p_argv);
65               z = sizeof(double);
66             }
67           else
68             *(void **) argp = *(void **)(* p_argv);
69         }  */
70       else if (z < sizeof(int))
71         {
72           z = sizeof(int);
73           switch ((*p_arg)->type)
74             {
75             case FFI_TYPE_SINT8:
76               *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
77               break;
78               
79             case FFI_TYPE_UINT8:
80               *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
81               break;
82               
83             case FFI_TYPE_SINT16:
84               *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
85               break;
86                   
87             case FFI_TYPE_UINT16:
88               *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
89               break;
90                   
91             default:
92               FFI_ASSERT(0);
93             }
94         }
95       else if (z == sizeof(int))
96         {
97           *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
98         }
99       else
100         {
101           memcpy(argp, *p_argv, z);
102         }
103       p_argv++;
104       argp += z;
105       count += z;
106     }
107
108   return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
109 }
110
111 /* Perform machine dependent cif processing */
112 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
113 {
114   if (cif->rtype->type == FFI_TYPE_STRUCT)
115     cif->flags = -1;
116   else
117     cif->flags = cif->rtype->size;
118
119   cif->bytes = ALIGN (cif->bytes, 8);
120
121   return FFI_OK;
122 }
123
124 extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
125                           extended_cif *, 
126                           unsigned, unsigned, 
127                           unsigned *, 
128                           void (*fn)(void));
129
130 void ffi_call(ffi_cif *cif, 
131               void (*fn)(void), 
132               void *rvalue, 
133               void **avalue)
134 {
135   extended_cif ecif;
136
137   ecif.cif = cif;
138   ecif.avalue = avalue;
139   
140   /* If the return value is a struct and we don't have a return */
141   /* value address then we need to make one                     */
142
143   if ((rvalue == NULL) && 
144       (cif->rtype->type == FFI_TYPE_STRUCT))
145     {
146       ecif.rvalue = alloca(cif->rtype->size);
147     }
148   else
149     ecif.rvalue = rvalue;
150     
151   
152   switch (cif->abi) 
153     {
154     case FFI_EABI:
155       ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
156                     cif->flags, ecif.rvalue, fn);
157       break;
158     default:
159       FFI_ASSERT(0);
160       break;
161     }
162 }
163
164 void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
165                        unsigned arg4, unsigned arg5, unsigned arg6)
166 {
167   /* This function is called by a trampoline.  The trampoline stows a
168      pointer to the ffi_closure object in gr7.  We must save this
169      pointer in a place that will persist while we do our work.  */
170   register ffi_closure *creg __asm__ ("gr7");
171   ffi_closure *closure = creg;
172
173   /* Arguments that don't fit in registers are found on the stack
174      at a fixed offset above the current frame pointer.  */
175   register char *frame_pointer __asm__ ("fp");
176   char *stack_args = frame_pointer + 16;
177
178   /* Lay the register arguments down in a continuous chunk of memory.  */
179   unsigned register_args[6] =
180     { arg1, arg2, arg3, arg4, arg5, arg6 };
181
182   ffi_cif *cif = closure->cif;
183   ffi_type **arg_types = cif->arg_types;
184   void **avalue = alloca (cif->nargs * sizeof(void *));
185   char *ptr = (char *) register_args;
186   int i;
187
188   /* Find the address of each argument.  */
189   for (i = 0; i < cif->nargs; i++)
190     {
191       switch (arg_types[i]->type)
192         {
193         case FFI_TYPE_SINT8:
194         case FFI_TYPE_UINT8:
195           avalue[i] = ptr + 3;
196           break;
197         case FFI_TYPE_SINT16:
198         case FFI_TYPE_UINT16:
199           avalue[i] = ptr + 2;
200           break;
201         case FFI_TYPE_SINT32:
202         case FFI_TYPE_UINT32:
203         case FFI_TYPE_FLOAT:
204           avalue[i] = ptr;
205           break;
206         case FFI_TYPE_STRUCT:
207           avalue[i] = *(void**)ptr;
208           break;
209         default:
210           /* This is an 8-byte value.  */
211           avalue[i] = ptr;
212           ptr += 4;
213           break;
214         }
215       ptr += 4;
216
217       /* If we've handled more arguments than fit in registers,
218          start looking at the those passed on the stack.  */
219       if (ptr == ((char *)register_args + (6*4)))
220         ptr = stack_args;
221     }
222
223   /* Invoke the closure.  */
224   if (cif->rtype->type == FFI_TYPE_STRUCT)
225     {
226       /* The caller allocates space for the return structure, and
227        passes a pointer to this space in gr3.  Use this value directly
228        as the return value.  */
229       register void *return_struct_ptr __asm__("gr3");
230       (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data);
231     }
232   else
233     {
234       /* Allocate space for the return value and call the function.  */
235       long long rvalue;
236       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
237
238       /* Functions return 4-byte or smaller results in gr8.  8-byte
239          values also use gr9.  We fill the both, even for small return
240          values, just to avoid a branch.  */ 
241       asm ("ldi  @(%0, #0), gr8" : : "r" (&rvalue));
242       asm ("ldi  @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1]));
243     }
244 }
245
246 ffi_status
247 ffi_prep_closure_loc (ffi_closure* closure,
248                       ffi_cif* cif,
249                       void (*fun)(ffi_cif*, void*, void**, void*),
250                       void *user_data,
251                       void *codeloc)
252 {
253   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
254   unsigned long fn = (long) ffi_closure_eabi;
255   unsigned long cls = (long) codeloc;
256   int i;
257
258   fn = (unsigned long) ffi_closure_eabi;
259
260   tramp[0] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
261   tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
262   tramp[2] = 0x8cf80000 + (fn  >> 16);    /* sethi hi(fn), gr6     */
263   tramp[3] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
264   tramp[4] = 0x80300006;                  /* jmpl @(gr0, gr6)      */
265
266   closure->cif = cif;
267   closure->fun = fun;
268   closure->user_data = user_data;
269
270   /* Cache flushing.  */
271   for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
272     __asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i),
273                       "r" (codeloc));
274
275   return FFI_OK;
276 }