11abb0017da71126419f6e3e79831c0ea3b3bd01
[platform/upstream/libffi.git] / src / moxie / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (C) 2012  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       else if (z < sizeof(int))
60         {
61           z = sizeof(int);
62           switch ((*p_arg)->type)
63             {
64             case FFI_TYPE_SINT8:
65               *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
66               break;
67               
68             case FFI_TYPE_UINT8:
69               *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
70               break;
71               
72             case FFI_TYPE_SINT16:
73               *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
74               break;
75                   
76             case FFI_TYPE_UINT16:
77               *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
78               break;
79                   
80             default:
81               FFI_ASSERT(0);
82             }
83         }
84       else if (z == sizeof(int))
85         {
86           *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
87         }
88       else
89         {
90           memcpy(argp, *p_argv, z);
91         }
92       p_argv++;
93       argp += z;
94       count += z;
95     }
96
97   return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
98 }
99
100 /* Perform machine dependent cif processing */
101 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
102 {
103   if (cif->rtype->type == FFI_TYPE_STRUCT)
104     cif->flags = -1;
105   else
106     cif->flags = cif->rtype->size;
107
108   cif->bytes = ALIGN (cif->bytes, 8);
109
110   return FFI_OK;
111 }
112
113 extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
114                           extended_cif *, 
115                           unsigned, unsigned, 
116                           unsigned *, 
117                           void (*fn)(void));
118
119 void ffi_call(ffi_cif *cif, 
120               void (*fn)(void), 
121               void *rvalue, 
122               void **avalue)
123 {
124   extended_cif ecif;
125
126   ecif.cif = cif;
127   ecif.avalue = avalue;
128   
129   /* If the return value is a struct and we don't have a return */
130   /* value address then we need to make one                     */
131
132   if ((rvalue == NULL) && 
133       (cif->rtype->type == FFI_TYPE_STRUCT))
134     {
135       ecif.rvalue = alloca(cif->rtype->size);
136     }
137   else
138     ecif.rvalue = rvalue;
139     
140   
141   switch (cif->abi) 
142     {
143     case FFI_EABI:
144       ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
145                     cif->flags, ecif.rvalue, fn);
146       break;
147     default:
148       FFI_ASSERT(0);
149       break;
150     }
151 }
152
153 void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
154                        unsigned arg4, unsigned arg5, unsigned arg6)
155 {
156   /* This function is called by a trampoline.  The trampoline stows a
157      pointer to the ffi_closure object in gr7.  We must save this
158      pointer in a place that will persist while we do our work.  */
159   register ffi_closure *creg __asm__ ("$r7");
160   ffi_closure *closure = creg;
161
162   /* Arguments that don't fit in registers are found on the stack
163      at a fixed offset above the current frame pointer.  */
164   register char *frame_pointer __asm__ ("$fp");
165   char *stack_args = frame_pointer + 16;
166
167   /* Lay the register arguments down in a continuous chunk of memory.  */
168   unsigned register_args[6] =
169     { arg1, arg2, arg3, arg4, arg5, arg6 };
170
171   ffi_cif *cif = closure->cif;
172   ffi_type **arg_types = cif->arg_types;
173   void **avalue = alloca (cif->nargs * sizeof(void *));
174   char *ptr = (char *) register_args;
175   int i;
176
177   /* Find the address of each argument.  */
178   for (i = 0; i < cif->nargs; i++)
179     {
180       switch (arg_types[i]->type)
181         {
182         case FFI_TYPE_SINT8:
183         case FFI_TYPE_UINT8:
184           avalue[i] = ptr + 3;
185           break;
186         case FFI_TYPE_SINT16:
187         case FFI_TYPE_UINT16:
188           avalue[i] = ptr + 2;
189           break;
190         case FFI_TYPE_SINT32:
191         case FFI_TYPE_UINT32:
192         case FFI_TYPE_FLOAT:
193           avalue[i] = ptr;
194           break;
195         case FFI_TYPE_STRUCT:
196           avalue[i] = *(void**)ptr;
197           break;
198         default:
199           /* This is an 8-byte value.  */
200           avalue[i] = ptr;
201           ptr += 4;
202           break;
203         }
204       ptr += 4;
205
206       /* If we've handled more arguments than fit in registers,
207          start looking at the those passed on the stack.  */
208       if (ptr == ((char *)register_args + (6*4)))
209         ptr = stack_args;
210     }
211
212   /* Invoke the closure.  */
213   if (cif->rtype->type == FFI_TYPE_STRUCT)
214     {
215       /* The caller allocates space for the return structure, and
216        passes a pointer to this space in gr3.  Use this value directly
217        as the return value.  */
218       register void *return_struct_ptr __asm__("$r0");
219       (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data);
220     }
221   else
222     {
223       /* Allocate space for the return value and call the function.  */
224       long long rvalue;
225       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
226
227       /* Functions return 4-byte or smaller results in gr8.  8-byte
228          values also use gr9.  We fill the both, even for small return
229          values, just to avoid a branch.  */ /*
230       asm ("ldi  @(%0, #0), gr8" : : "r" (&rvalue));
231       asm ("ldi  @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1])); */
232     }
233 }
234
235 ffi_status
236 ffi_prep_closure_loc (ffi_closure* closure,
237                       ffi_cif* cif,
238                       void (*fun)(ffi_cif*, void*, void**, void*),
239                       void *user_data,
240                       void *codeloc)
241 {
242   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
243   unsigned long fn = (long) ffi_closure_eabi;
244   unsigned long cls = (long) codeloc;
245   int i;
246
247   fn = (unsigned long) ffi_closure_eabi;
248
249   tramp[0] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
250   tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
251   tramp[2] = 0x8cf80000 + (fn  >> 16);    /* sethi hi(fn), gr6     */
252   tramp[3] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
253   tramp[4] = 0x80300006;                  /* jmpl @(gr0, gr6)      */
254
255   closure->cif = cif;
256   closure->fun = fun;
257   closure->user_data = user_data;
258
259   return FFI_OK;
260 }