Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / ctypes / libffi / src / x86 / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008  Red Hat, Inc.
3            Copyright (c) 2002  Ranjit Mathew
4            Copyright (c) 2002  Bo Thorsen
5            Copyright (c) 2002  Roger Sayle
6            Copyright (C) 2008  Free Software Foundation, Inc.
7
8    x86 Foreign Function Interface
9
10    Permission is hereby granted, free of charge, to any person obtaining
11    a copy of this software and associated documentation files (the
12    ``Software''), to deal in the Software without restriction, including
13    without limitation the rights to use, copy, modify, merge, publish,
14    distribute, sublicense, and/or sell copies of the Software, and to
15    permit persons to whom the Software is furnished to do so, subject to
16    the following conditions:
17
18    The above copyright notice and this permission notice shall be included
19    in all copies or substantial portions of the Software.
20
21    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
22    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28    DEALINGS IN THE SOFTWARE.
29    ----------------------------------------------------------------------- */
30
31 #if !defined(__x86_64__) || defined(_WIN64)
32
33 #ifdef _WIN64
34 #include <windows.h>
35 #endif
36
37 #include <ffi.h>
38 #include <ffi_common.h>
39
40 #include <stdlib.h>
41
42 /* ffi_prep_args is called by the assembly routine once stack space
43    has been allocated for the function's arguments */
44
45 void ffi_prep_args(char *stack, extended_cif *ecif)
46 {
47   register unsigned int i;
48   register void **p_argv;
49   register char *argp;
50   register ffi_type **p_arg;
51
52   argp = stack;
53
54   if (ecif->cif->flags == FFI_TYPE_STRUCT
55 #ifdef X86_WIN64
56       && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
57           && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
58 #endif
59       )
60     {
61       *(void **) argp = ecif->rvalue;
62       argp += sizeof(void*);
63     }
64
65   p_argv = ecif->avalue;
66
67   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
68        i != 0;
69        i--, p_arg++)
70     {
71       size_t z;
72
73       /* Align if necessary */
74       if ((sizeof(void*) - 1) & (size_t) argp)
75         argp = (char *) ALIGN(argp, sizeof(void*));
76
77       z = (*p_arg)->size;
78 #ifdef X86_WIN64
79       if (z > sizeof(ffi_arg)
80           || ((*p_arg)->type == FFI_TYPE_STRUCT
81               && (z != 1 && z != 2 && z != 4 && z != 8))
82 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
83           || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
84 #endif
85           )
86         {
87           z = sizeof(ffi_arg);
88           *(void **)argp = *p_argv;
89         }
90       else if ((*p_arg)->type == FFI_TYPE_FLOAT)
91         {
92           memcpy(argp, *p_argv, z);
93         }
94       else
95 #endif
96       if (z < sizeof(ffi_arg))
97         {
98           z = sizeof(ffi_arg);
99           switch ((*p_arg)->type)
100             {
101             case FFI_TYPE_SINT8:
102               *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
103               break;
104
105             case FFI_TYPE_UINT8:
106               *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
107               break;
108
109             case FFI_TYPE_SINT16:
110               *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
111               break;
112
113             case FFI_TYPE_UINT16:
114               *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
115               break;
116
117             case FFI_TYPE_SINT32:
118               *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
119               break;
120
121             case FFI_TYPE_UINT32:
122               *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
123               break;
124
125             case FFI_TYPE_STRUCT:
126               *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
127               break;
128
129             default:
130               FFI_ASSERT(0);
131             }
132         }
133       else
134         {
135           memcpy(argp, *p_argv, z);
136         }
137       p_argv++;
138 #ifdef X86_WIN64
139       argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
140 #else
141       argp += z;
142 #endif
143     }
144   
145   return;
146 }
147
148 /* Perform machine dependent cif processing */
149 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
150 {
151   unsigned int i;
152   ffi_type **ptr;
153
154   /* Set the return type flag */
155   switch (cif->rtype->type)
156     {
157     case FFI_TYPE_VOID:
158     case FFI_TYPE_UINT8:
159     case FFI_TYPE_UINT16:
160     case FFI_TYPE_SINT8:
161     case FFI_TYPE_SINT16:
162 #ifdef X86_WIN64
163     case FFI_TYPE_UINT32:
164     case FFI_TYPE_SINT32:
165 #endif
166     case FFI_TYPE_SINT64:
167     case FFI_TYPE_FLOAT:
168     case FFI_TYPE_DOUBLE:
169 #ifndef X86_WIN64
170 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
171     case FFI_TYPE_LONGDOUBLE:
172 #endif
173 #endif
174       cif->flags = (unsigned) cif->rtype->type;
175       break;
176
177     case FFI_TYPE_UINT64:
178 #ifdef X86_WIN64
179     case FFI_TYPE_POINTER:
180 #endif
181       cif->flags = FFI_TYPE_SINT64;
182       break;
183
184     case FFI_TYPE_STRUCT:
185 #ifndef X86
186       if (cif->rtype->size == 1)
187         {
188           cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
189         }
190       else if (cif->rtype->size == 2)
191         {
192           cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
193         }
194       else if (cif->rtype->size == 4)
195         {
196 #ifdef X86_WIN64
197           cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
198 #else
199           cif->flags = FFI_TYPE_INT; /* same as int type */
200 #endif
201         }
202       else if (cif->rtype->size == 8)
203         {
204           cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
205         }
206       else
207 #endif
208         {
209           cif->flags = FFI_TYPE_STRUCT;
210           /* allocate space for return value pointer */
211           cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
212         }
213       break;
214
215     default:
216 #ifdef X86_WIN64
217       cif->flags = FFI_TYPE_SINT64;
218       break;
219     case FFI_TYPE_INT:
220       cif->flags = FFI_TYPE_SINT32;
221 #else
222       cif->flags = FFI_TYPE_INT;
223 #endif
224       break;
225     }
226
227   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
228     {
229       if (((*ptr)->alignment - 1) & cif->bytes)
230         cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
231       cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
232     }
233
234 #ifdef X86_WIN64
235   /* ensure space for storing four registers */
236   cif->bytes += 4 * sizeof(ffi_arg);
237 #endif
238
239 #ifdef X86_DARWIN
240   cif->bytes = (cif->bytes + 15) & ~0xF;
241 #endif
242
243   return FFI_OK;
244 }
245
246 #ifdef X86_WIN64
247 extern int
248 ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
249                unsigned, unsigned, unsigned *, void (*fn)(void));
250 #elif defined(X86_WIN32)
251 extern void
252 ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
253                unsigned, unsigned, unsigned *, void (*fn)(void));
254 #else
255 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
256                           unsigned, unsigned, unsigned *, void (*fn)(void));
257 #endif
258
259 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
260 {
261   extended_cif ecif;
262
263   ecif.cif = cif;
264   ecif.avalue = avalue;
265   
266   /* If the return value is a struct and we don't have a return */
267   /* value address then we need to make one                     */
268
269 #ifdef X86_WIN64
270   if (rvalue == NULL
271       && cif->flags == FFI_TYPE_STRUCT
272       && cif->rtype->size != 1 && cif->rtype->size != 2
273       && cif->rtype->size != 4 && cif->rtype->size != 8)
274     {
275       ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
276     }
277 #else
278   if (rvalue == NULL
279       && cif->flags == FFI_TYPE_STRUCT)
280     {
281       ecif.rvalue = alloca(cif->rtype->size);
282     }
283 #endif
284   else
285     ecif.rvalue = rvalue;
286     
287   
288   switch (cif->abi) 
289     {
290 #ifdef X86_WIN64
291     case FFI_WIN64:
292       ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
293                      cif->flags, ecif.rvalue, fn);
294       break;
295 #elif defined(X86_WIN32)
296     case FFI_SYSV:
297     case FFI_STDCALL:
298       ffi_call_win32(ffi_prep_args, &ecif, cif->bytes, cif->flags,
299                      ecif.rvalue, fn);
300       break;
301 #else
302     case FFI_SYSV:
303       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
304                     fn);
305       break;
306 #endif
307     default:
308       FFI_ASSERT(0);
309       break;
310     }
311 }
312
313
314 /** private members **/
315
316 /* The following __attribute__((regparm(1))) decorations will have no effect
317    on MSVC - standard cdecl convention applies. */
318 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
319                                          void** args, ffi_cif* cif);
320 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
321      __attribute__ ((regparm(1)));
322 unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
323      __attribute__ ((regparm(1)));
324 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
325      __attribute__ ((regparm(1)));
326 #ifdef X86_WIN32
327 void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
328      __attribute__ ((regparm(1)));
329 #endif
330 #ifdef X86_WIN64
331 void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
332 #endif
333
334 /* This function is jumped to by the trampoline */
335
336 #ifdef X86_WIN64
337 void * FFI_HIDDEN
338 ffi_closure_win64_inner (ffi_closure *closure, void *args) {
339   ffi_cif       *cif;
340   void         **arg_area;
341   void          *result;
342   void          *resp = &result;
343
344   cif         = closure->cif;
345   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
346
347   /* this call will initialize ARG_AREA, such that each
348    * element in that array points to the corresponding 
349    * value on the stack; and if the function returns
350    * a structure, it will change RESP to point to the
351    * structure return address.  */
352
353   ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
354   
355   (closure->fun) (cif, resp, arg_area, closure->user_data);
356
357   /* The result is returned in rax.  This does the right thing for
358      result types except for floats; we have to 'mov xmm0, rax' in the
359      caller to correct this.
360      TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
361   */
362   return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
363 }
364
365 #else
366 unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
367 ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
368 {
369   /* our various things...  */
370   ffi_cif       *cif;
371   void         **arg_area;
372
373   cif         = closure->cif;
374   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
375
376   /* this call will initialize ARG_AREA, such that each
377    * element in that array points to the corresponding 
378    * value on the stack; and if the function returns
379    * a structure, it will change RESP to point to the
380    * structure return address.  */
381
382   ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
383
384   (closure->fun) (cif, *respp, arg_area, closure->user_data);
385
386   return cif->flags;
387 }
388 #endif /* !X86_WIN64 */
389
390 static void
391 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
392                             ffi_cif *cif)
393 {
394   register unsigned int i;
395   register void **p_argv;
396   register char *argp;
397   register ffi_type **p_arg;
398
399   argp = stack;
400
401 #ifdef X86_WIN64
402   if (cif->rtype->size > sizeof(ffi_arg)
403       || (cif->flags == FFI_TYPE_STRUCT
404           && (cif->rtype->size != 1 && cif->rtype->size != 2
405               && cif->rtype->size != 4 && cif->rtype->size != 8))) {
406     *rvalue = *(void **) argp;
407     argp += sizeof(void *);
408   }
409 #else
410   if ( cif->flags == FFI_TYPE_STRUCT ) {
411     *rvalue = *(void **) argp;
412     argp += sizeof(void *);
413   }
414 #endif
415
416   p_argv = avalue;
417
418   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
419     {
420       size_t z;
421
422       /* Align if necessary */
423       if ((sizeof(void*) - 1) & (size_t) argp) {
424         argp = (char *) ALIGN(argp, sizeof(void*));
425       }
426
427 #ifdef X86_WIN64
428       if ((*p_arg)->size > sizeof(ffi_arg)
429           || ((*p_arg)->type == FFI_TYPE_STRUCT
430               && ((*p_arg)->size != 1 && (*p_arg)->size != 2
431                   && (*p_arg)->size != 4 && (*p_arg)->size != 8)))
432         {
433           z = sizeof(void *);
434           *p_argv = *(void **)argp;
435         }
436       else
437 #endif
438         {
439           z = (*p_arg)->size;
440           
441           /* because we're little endian, this is what it turns into.   */
442           
443           *p_argv = (void*) argp;
444         }
445           
446       p_argv++;
447 #ifdef X86_WIN64
448       argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
449 #else
450       argp += z;
451 #endif
452     }
453   
454   return;
455 }
456
457 #define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
458 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
459    void*  __fun = (void*)(FUN); \
460    void*  __ctx = (void*)(CTX); \
461    *(unsigned char*) &__tramp[0] = 0x41; \
462    *(unsigned char*) &__tramp[1] = 0xbb; \
463    *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
464    *(unsigned char*) &__tramp[6] = 0x48; \
465    *(unsigned char*) &__tramp[7] = 0xb8; \
466    *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
467    *(unsigned char *)  &__tramp[16] = 0x49; \
468    *(unsigned char *)  &__tramp[17] = 0xba; \
469    *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
470    *(unsigned char *)  &__tramp[26] = 0x41; \
471    *(unsigned char *)  &__tramp[27] = 0xff; \
472    *(unsigned char *)  &__tramp[28] = 0xe2; /* jmp %r10 */ \
473  }
474
475 /* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
476
477 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
478 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
479    unsigned int  __fun = (unsigned int)(FUN); \
480    unsigned int  __ctx = (unsigned int)(CTX); \
481    unsigned int  __dis = __fun - (__ctx + 10);  \
482    *(unsigned char*) &__tramp[0] = 0xb8; \
483    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
484    *(unsigned char *)  &__tramp[5] = 0xe9; \
485    *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
486  }
487
488 #define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE)  \
489 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
490    unsigned int  __fun = (unsigned int)(FUN); \
491    unsigned int  __ctx = (unsigned int)(CTX); \
492    unsigned int  __dis = __fun - (__ctx + 10); \
493    unsigned short __size = (unsigned short)(SIZE); \
494    *(unsigned char*) &__tramp[0] = 0xb8; \
495    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
496    *(unsigned char *)  &__tramp[5] = 0xe8; \
497    *(unsigned int*)  &__tramp[6] = __dis; /* call __fun  */ \
498    *(unsigned char *)  &__tramp[10] = 0xc2; \
499    *(unsigned short*)  &__tramp[11] = __size; /* ret __size  */ \
500  }
501
502 /* the cif must already be prep'ed */
503
504 ffi_status
505 ffi_prep_closure_loc (ffi_closure* closure,
506                       ffi_cif* cif,
507                       void (*fun)(ffi_cif*,void*,void**,void*),
508                       void *user_data,
509                       void *codeloc)
510 {
511 #ifdef X86_WIN64
512 #define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
513 #define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
514   if (cif->abi == FFI_WIN64) 
515     {
516       int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
517       FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
518                                  &ffi_closure_win64,
519                                  codeloc, mask);
520       /* make sure we can execute here */
521     }
522 #else
523   if (cif->abi == FFI_SYSV)
524     {
525       FFI_INIT_TRAMPOLINE (&closure->tramp[0],
526                            &ffi_closure_SYSV,
527                            (void*)codeloc);
528     }
529 #ifdef X86_WIN32
530   else if (cif->abi == FFI_STDCALL)
531     {
532       FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
533                                    &ffi_closure_STDCALL,
534                                    (void*)codeloc, cif->bytes);
535     }
536 #endif /* X86_WIN32 */
537 #endif /* !X86_WIN64 */
538   else
539     {
540       return FFI_BAD_ABI;
541     }
542     
543   closure->cif  = cif;
544   closure->user_data = user_data;
545   closure->fun  = fun;
546
547   return FFI_OK;
548 }
549
550 /* ------- Native raw API support -------------------------------- */
551
552 #if !FFI_NO_RAW_API
553
554 ffi_status
555 ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
556                           ffi_cif* cif,
557                           void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
558                           void *user_data,
559                           void *codeloc)
560 {
561   int i;
562
563   if (cif->abi != FFI_SYSV) {
564     return FFI_BAD_ABI;
565   }
566
567   /* we currently don't support certain kinds of arguments for raw
568      closures.  This should be implemented by a separate assembly
569      language routine, since it would require argument processing,
570      something we don't do now for performance.  */
571
572   for (i = cif->nargs-1; i >= 0; i--)
573     {
574       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
575       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
576     }
577   
578
579   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
580                        codeloc);
581     
582   closure->cif  = cif;
583   closure->user_data = user_data;
584   closure->fun  = fun;
585
586   return FFI_OK;
587 }
588
589 static void 
590 ffi_prep_args_raw(char *stack, extended_cif *ecif)
591 {
592   memcpy (stack, ecif->avalue, ecif->cif->bytes);
593 }
594
595 /* we borrow this routine from libffi (it must be changed, though, to
596  * actually call the function passed in the first argument.  as of
597  * libffi-1.20, this is not the case.)
598  */
599
600 void
601 ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
602 {
603   extended_cif ecif;
604   void **avalue = (void **)fake_avalue;
605
606   ecif.cif = cif;
607   ecif.avalue = avalue;
608   
609   /* If the return value is a struct and we don't have a return */
610   /* value address then we need to make one                     */
611
612   if ((rvalue == NULL) && 
613       (cif->rtype->type == FFI_TYPE_STRUCT))
614     {
615       ecif.rvalue = alloca(cif->rtype->size);
616     }
617   else
618     ecif.rvalue = rvalue;
619     
620   
621   switch (cif->abi) 
622     {
623 #ifdef X86_WIN32
624     case FFI_SYSV:
625     case FFI_STDCALL:
626       ffi_call_win32(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
627                      ecif.rvalue, fn);
628       break;
629 #else
630     case FFI_SYSV:
631       ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
632                     ecif.rvalue, fn);
633       break;
634 #endif
635     default:
636       FFI_ASSERT(0);
637       break;
638     }
639 }
640
641 #endif
642
643 #endif /* !__x86_64__  || X86_WIN64 */
644