OSDN Git Service

cheets: Add external/wayland and external/cheets-libffi
[android-x86/external-libffi.git] / src / cris / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1998 Cygnus Solutions
3            Copyright (c) 2004 Simon Posnjak
4            Copyright (c) 2005 Axis Communications AB
5            Copyright (C) 2007 Free Software Foundation, Inc.
6
7    CRIS Foreign Function Interface
8
9    Permission is hereby granted, free of charge, to any person obtaining
10    a copy of this software and associated documentation files (the
11    ``Software''), to deal in the Software without restriction, including
12    without limitation the rights to use, copy, modify, merge, publish,
13    distribute, sublicense, and/or sell copies of the Software, and to
14    permit persons to whom the Software is furnished to do so, subject to
15    the following conditions:
16
17    The above copyright notice and this permission notice shall be included
18    in all copies or substantial portions of the Software.
19
20    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23    IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
24    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26    OTHER DEALINGS IN THE SOFTWARE.
27    ----------------------------------------------------------------------- */
28
29 #include <ffi.h>
30 #include <ffi_common.h>
31
32 #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
33
34 static ffi_status
35 initialize_aggregate_packed_struct (ffi_type * arg)
36 {
37   ffi_type **ptr;
38
39   FFI_ASSERT (arg != NULL);
40
41   FFI_ASSERT (arg->elements != NULL);
42   FFI_ASSERT (arg->size == 0);
43   FFI_ASSERT (arg->alignment == 0);
44
45   ptr = &(arg->elements[0]);
46
47   while ((*ptr) != NULL)
48     {
49       if (((*ptr)->size == 0)
50           && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
51         return FFI_BAD_TYPEDEF;
52
53       FFI_ASSERT (ffi_type_test ((*ptr)));
54
55       arg->size += (*ptr)->size;
56
57       arg->alignment = (arg->alignment > (*ptr)->alignment) ?
58         arg->alignment : (*ptr)->alignment;
59
60       ptr++;
61     }
62
63   if (arg->size == 0)
64     return FFI_BAD_TYPEDEF;
65   else
66     return FFI_OK;
67 }
68
69 int
70 ffi_prep_args (char *stack, extended_cif * ecif)
71 {
72   unsigned int i;
73   unsigned int struct_count = 0;
74   void **p_argv;
75   char *argp;
76   ffi_type **p_arg;
77
78   argp = stack;
79
80   p_argv = ecif->avalue;
81
82   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
83        (i != 0); i--, p_arg++)
84     {
85       size_t z;
86
87       switch ((*p_arg)->type)
88         {
89         case FFI_TYPE_STRUCT:
90           {
91             z = (*p_arg)->size;
92             if (z <= 4)
93               {
94                 memcpy (argp, *p_argv, z);
95                 z = 4;
96               }
97             else if (z <= 8)
98               {
99                 memcpy (argp, *p_argv, z);
100                 z = 8;
101               }
102             else
103               {
104                 unsigned int uiLocOnStack;
105                 z = sizeof (void *);
106                 uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
107                 struct_count = struct_count + (*p_arg)->size;
108                 *(unsigned int *) argp =
109                   (unsigned int) (UINT32 *) (stack + uiLocOnStack);
110                 memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
111               }
112             break;
113           }
114         default:
115           z = (*p_arg)->size;
116           if (z < sizeof (int))
117             {
118               switch ((*p_arg)->type)
119                 {
120                 case FFI_TYPE_SINT8:
121                   *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
122                   break;
123
124                 case FFI_TYPE_UINT8:
125                   *(unsigned int *) argp =
126                     (unsigned int) *(UINT8 *) (*p_argv);
127                   break;
128
129                 case FFI_TYPE_SINT16:
130                   *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
131                   break;
132
133                 case FFI_TYPE_UINT16:
134                   *(unsigned int *) argp =
135                     (unsigned int) *(UINT16 *) (*p_argv);
136                   break;
137
138                 default:
139                   FFI_ASSERT (0);
140                 }
141               z = sizeof (int);
142             }
143           else if (z == sizeof (int))
144             *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
145           else
146             memcpy (argp, *p_argv, z);
147           break;
148         }
149       p_argv++;
150       argp += z;
151     }
152
153   return (struct_count);
154 }
155
156 ffi_status FFI_HIDDEN
157 ffi_prep_cif_core (ffi_cif * cif,
158                    ffi_abi abi, unsigned int isvariadic,
159                    unsigned int nfixedargs, unsigned int ntotalargs,
160                    ffi_type * rtype, ffi_type ** atypes)
161 {
162   unsigned bytes = 0;
163   unsigned int i;
164   ffi_type **ptr;
165
166   FFI_ASSERT (cif != NULL);
167   FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
168   FFI_ASSERT(nfixedargs <= ntotalargs);
169   FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
170
171   cif->abi = abi;
172   cif->arg_types = atypes;
173   cif->nargs = ntotalargs;
174   cif->rtype = rtype;
175
176   cif->flags = 0;
177
178   if ((cif->rtype->size == 0)
179       && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
180     return FFI_BAD_TYPEDEF;
181
182   FFI_ASSERT_VALID_TYPE (cif->rtype);
183
184   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
185     {
186       if (((*ptr)->size == 0)
187           && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
188         return FFI_BAD_TYPEDEF;
189
190       FFI_ASSERT_VALID_TYPE (*ptr);
191
192       if (((*ptr)->alignment - 1) & bytes)
193         bytes = ALIGN (bytes, (*ptr)->alignment);
194       if ((*ptr)->type == FFI_TYPE_STRUCT)
195         {
196           if ((*ptr)->size > 8)
197             {
198               bytes += (*ptr)->size;
199               bytes += sizeof (void *);
200             }
201           else
202             {
203               if ((*ptr)->size > 4)
204                 bytes += 8;
205               else
206                 bytes += 4;
207             }
208         }
209       else
210         bytes += STACK_ARG_SIZE ((*ptr)->size);
211     }
212
213   cif->bytes = bytes;
214
215   return ffi_prep_cif_machdep (cif);
216 }
217
218 ffi_status
219 ffi_prep_cif_machdep (ffi_cif * cif)
220 {
221   switch (cif->rtype->type)
222     {
223     case FFI_TYPE_VOID:
224     case FFI_TYPE_STRUCT:
225     case FFI_TYPE_FLOAT:
226     case FFI_TYPE_DOUBLE:
227     case FFI_TYPE_SINT64:
228     case FFI_TYPE_UINT64:
229       cif->flags = (unsigned) cif->rtype->type;
230       break;
231
232     default:
233       cif->flags = FFI_TYPE_INT;
234       break;
235     }
236
237   return FFI_OK;
238 }
239
240 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
241                            extended_cif *,
242                            unsigned, unsigned, unsigned *, void (*fn) ())
243      __attribute__ ((__visibility__ ("hidden")));
244
245 void
246 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
247 {
248   extended_cif ecif;
249
250   ecif.cif = cif;
251   ecif.avalue = avalue;
252
253   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
254     {
255       ecif.rvalue = alloca (cif->rtype->size);
256     }
257   else
258     ecif.rvalue = rvalue;
259
260   switch (cif->abi)
261     {
262     case FFI_SYSV:
263       ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
264                      cif->flags, ecif.rvalue, fn);
265       break;
266     default:
267       FFI_ASSERT (0);
268       break;
269     }
270 }
271
272 /* Because the following variables are not exported outside libffi, we
273    mark them hidden.  */
274
275 /* Assembly code for the jump stub.  */
276 extern const char ffi_cris_trampoline_template[]
277  __attribute__ ((__visibility__ ("hidden")));
278
279 /* Offset into ffi_cris_trampoline_template of where to put the
280    ffi_prep_closure_inner function.  */
281 extern const int ffi_cris_trampoline_fn_offset
282  __attribute__ ((__visibility__ ("hidden")));
283
284 /* Offset into ffi_cris_trampoline_template of where to put the
285    closure data.  */
286 extern const int ffi_cris_trampoline_closure_offset
287  __attribute__ ((__visibility__ ("hidden")));
288
289 /* This function is sibling-called (jumped to) by the closure
290    trampoline.  We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
291    PARAMS[4] to simplify handling of a straddling parameter.  A copy
292    of R9 is at PARAMS[5] and SP at PARAMS[6].  These parameters are
293    put at the appropriate place in CLOSURE which is then executed and
294    the return value is passed back to the caller.  */
295
296 static unsigned long long
297 ffi_prep_closure_inner (void **params, ffi_closure* closure)
298 {
299   char *register_args = (char *) params;
300   void *struct_ret = params[5];
301   char *stack_args = params[6];
302   char *ptr = register_args;
303   ffi_cif *cif = closure->cif;
304   ffi_type **arg_types = cif->arg_types;
305
306   /* Max room needed is number of arguments as 64-bit values.  */
307   void **avalue = alloca (closure->cif->nargs * sizeof(void *));
308   int i;
309   int doing_regs;
310   long long llret = 0;
311
312   /* Find the address of each argument.  */
313   for (i = 0, doing_regs = 1; i < cif->nargs; i++)
314     {
315       /* Types up to and including 8 bytes go by-value.  */
316       if (arg_types[i]->size <= 4)
317         {
318           avalue[i] = ptr;
319           ptr += 4;
320         }
321       else if (arg_types[i]->size <= 8)
322         {
323           avalue[i] = ptr;
324           ptr += 8;
325         }
326       else
327         {
328           FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
329
330           /* Passed by-reference, so copy the pointer.  */
331           avalue[i] = *(void **) ptr;
332           ptr += 4;
333         }
334
335       /* If we've handled more arguments than fit in registers, start
336          looking at the those passed on the stack.  Step over the
337          first one if we had a straddling parameter.  */
338       if (doing_regs && ptr >= register_args + 4*4)
339         {
340           ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
341           doing_regs = 0;
342         }
343     }
344
345   /* Invoke the closure.  */
346   (closure->fun) (cif,
347
348                   cif->rtype->type == FFI_TYPE_STRUCT
349                   /* The caller allocated space for the return
350                      structure, and passed a pointer to this space in
351                      R9.  */
352                   ? struct_ret
353
354                   /* We take advantage of being able to ignore that
355                      the high part isn't set if the return value is
356                      not in R10:R11, but in R10 only.  */
357                   : (void *) &llret,
358
359                   avalue, closure->user_data);
360
361   return llret;
362 }
363
364 /* API function: Prepare the trampoline.  */
365
366 ffi_status
367 ffi_prep_closure_loc (ffi_closure* closure,
368                       ffi_cif* cif,
369                       void (*fun)(ffi_cif *, void *, void **, void*),
370                       void *user_data,
371                       void *codeloc)
372 {
373   void *innerfn = ffi_prep_closure_inner;
374   FFI_ASSERT (cif->abi == FFI_SYSV);
375   closure->cif  = cif;
376   closure->user_data = user_data;
377   closure->fun  = fun;
378   memcpy (closure->tramp, ffi_cris_trampoline_template,
379           FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
380   memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
381           &innerfn, sizeof (void *));
382   memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
383           &codeloc, sizeof (void *));
384
385   return FFI_OK;
386 }