Restore execute permissions
[platform/upstream/libffi.git] / .pc / remove-warnings / 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 #if defined(X86) || defined (X86_WIN32) || defined(X86_FREEBSD) || defined(X86_DARWIN) || defined(X86_WIN64)
159     case FFI_TYPE_UINT8:
160     case FFI_TYPE_UINT16:
161     case FFI_TYPE_SINT8:
162     case FFI_TYPE_SINT16:
163 #endif
164 #ifdef X86_WIN64
165     case FFI_TYPE_UINT32:
166     case FFI_TYPE_SINT32:
167 #endif
168     case FFI_TYPE_SINT64:
169     case FFI_TYPE_FLOAT:
170     case FFI_TYPE_DOUBLE:
171 #ifndef X86_WIN64
172 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
173     case FFI_TYPE_LONGDOUBLE:
174 #endif
175 #endif
176       cif->flags = (unsigned) cif->rtype->type;
177       break;
178
179     case FFI_TYPE_UINT64:
180 #ifdef X86_WIN64
181     case FFI_TYPE_POINTER:
182 #endif
183       cif->flags = FFI_TYPE_SINT64;
184       break;
185
186     case FFI_TYPE_STRUCT:
187 #ifndef X86
188       if (cif->rtype->size == 1)
189         {
190           cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
191         }
192       else if (cif->rtype->size == 2)
193         {
194           cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
195         }
196       else if (cif->rtype->size == 4)
197         {
198 #ifdef X86_WIN64
199           cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
200 #else
201           cif->flags = FFI_TYPE_INT; /* same as int type */
202 #endif
203         }
204       else if (cif->rtype->size == 8)
205         {
206           cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
207         }
208       else
209 #endif
210         {
211           cif->flags = FFI_TYPE_STRUCT;
212           // allocate space for return value pointer
213           cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
214         }
215       break;
216
217     default:
218 #ifdef X86_WIN64
219       cif->flags = FFI_TYPE_SINT64;
220       break;
221     case FFI_TYPE_INT:
222       cif->flags = FFI_TYPE_SINT32;
223 #else
224       cif->flags = FFI_TYPE_INT;
225 #endif
226       break;
227     }
228
229   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
230     {
231       if (((*ptr)->alignment - 1) & cif->bytes)
232         cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
233       cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
234     }
235
236 #ifdef X86_WIN64
237   // ensure space for storing four registers
238   cif->bytes += 4 * sizeof(ffi_arg);
239 #endif
240
241 #ifdef X86_DARWIN
242   cif->bytes = (cif->bytes + 15) & ~0xF;
243 #endif
244
245   return FFI_OK;
246 }
247
248 #ifdef X86_WIN64
249 extern int
250 ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
251                unsigned, unsigned, unsigned *, void (*fn)(void));
252 #elif defined(X86_WIN32)
253 extern void
254 ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
255                unsigned, unsigned, unsigned *, void (*fn)(void));
256 #else
257 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
258                           unsigned, unsigned, unsigned *, void (*fn)(void));
259 #endif
260
261 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
262 {
263   extended_cif ecif;
264
265   ecif.cif = cif;
266   ecif.avalue = avalue;
267   
268   /* If the return value is a struct and we don't have a return */
269   /* value address then we need to make one                     */
270
271 #ifdef X86_WIN64
272   if (rvalue == NULL
273       && cif->flags == FFI_TYPE_STRUCT
274       && cif->rtype->size != 1 && cif->rtype->size != 2
275       && cif->rtype->size != 4 && cif->rtype->size != 8)
276     {
277       ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
278     }
279 #else
280   if (rvalue == NULL
281       && cif->flags == FFI_TYPE_STRUCT)
282     {
283       ecif.rvalue = alloca(cif->rtype->size);
284     }
285 #endif
286   else
287     ecif.rvalue = rvalue;
288     
289   
290   switch (cif->abi) 
291     {
292 #ifdef X86_WIN64
293     case FFI_WIN64:
294       {
295         // Make copies of all struct arguments
296         // NOTE: not sure if responsibility should be here or in caller
297         unsigned int i;
298         for (i=0; i < cif->nargs;i++) {
299           size_t size = cif->arg_types[i]->size;
300           if ((cif->arg_types[i]->type == FFI_TYPE_STRUCT
301                && (size != 1 && size != 2 && size != 4 && size != 8))
302 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
303               || cif->arg_types[i]->type == FFI_TYPE_LONGDOUBLE
304 #endif
305               )
306             {
307               void *local = alloca(size);
308               memcpy(local, avalue[i], size);
309               avalue[i] = local;
310             }
311         }
312         ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
313                        cif->flags, ecif.rvalue, fn);
314       }
315       break;
316 #elif defined(X86_WIN32)
317     case FFI_SYSV:
318     case FFI_STDCALL:
319       ffi_call_win32(ffi_prep_args, &ecif, cif->bytes, cif->flags,
320                      ecif.rvalue, fn);
321       break;
322 #else
323     case FFI_SYSV:
324       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
325                     fn);
326       break;
327 #endif
328     default:
329       FFI_ASSERT(0);
330       break;
331     }
332 }
333
334
335 /** private members **/
336
337 /* The following __attribute__((regparm(1))) decorations will have no effect
338    on MSVC - standard cdecl convention applies. */
339 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
340                                          void** args, ffi_cif* cif);
341 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
342      __attribute__ ((regparm(1)));
343 unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
344      __attribute__ ((regparm(1)));
345 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
346      __attribute__ ((regparm(1)));
347 #ifdef X86_WIN32
348 void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
349      __attribute__ ((regparm(1)));
350 #endif
351 #ifdef X86_WIN64
352 void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
353 #endif
354
355 /* This function is jumped to by the trampoline */
356
357 #ifdef X86_WIN64
358 void * FFI_HIDDEN
359 ffi_closure_win64_inner (ffi_closure *closure, void *args) {
360   ffi_cif       *cif;
361   void         **arg_area;
362   void          *result;
363   void          *resp = &result;
364
365   cif         = closure->cif;
366   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
367
368   /* this call will initialize ARG_AREA, such that each
369    * element in that array points to the corresponding 
370    * value on the stack; and if the function returns
371    * a structure, it will change RESP to point to the
372    * structure return address.  */
373
374   ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
375   
376   (closure->fun) (cif, resp, arg_area, closure->user_data);
377
378   /* The result is returned in rax.  This does the right thing for
379      result types except for floats; we have to 'mov xmm0, rax' in the
380      caller to correct this.
381      TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
382   */
383   return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
384 }
385
386 #else
387 unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
388 ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
389 {
390   /* our various things...  */
391   ffi_cif       *cif;
392   void         **arg_area;
393
394   cif         = closure->cif;
395   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
396
397   /* this call will initialize ARG_AREA, such that each
398    * element in that array points to the corresponding 
399    * value on the stack; and if the function returns
400    * a structure, it will change RESP to point to the
401    * structure return address.  */
402
403   ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
404
405   (closure->fun) (cif, *respp, arg_area, closure->user_data);
406
407   return cif->flags;
408 }
409 #endif /* !X86_WIN64 */
410
411 static void
412 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
413                             ffi_cif *cif)
414 {
415   register unsigned int i;
416   register void **p_argv;
417   register char *argp;
418   register ffi_type **p_arg;
419
420   argp = stack;
421
422 #ifdef X86_WIN64
423   if (cif->rtype->size > sizeof(ffi_arg)
424       || (cif->flags == FFI_TYPE_STRUCT
425           && (cif->rtype->size != 1 && cif->rtype->size != 2
426               && cif->rtype->size != 4 && cif->rtype->size != 8))) {
427     *rvalue = *(void **) argp;
428     argp += sizeof(void *);
429   }
430 #else
431   if ( cif->flags == FFI_TYPE_STRUCT ) {
432     *rvalue = *(void **) argp;
433     argp += sizeof(void *);
434   }
435 #endif
436
437   p_argv = avalue;
438
439   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
440     {
441       size_t z;
442
443       /* Align if necessary */
444       if ((sizeof(void*) - 1) & (size_t) argp) {
445         argp = (char *) ALIGN(argp, sizeof(void*));
446       }
447
448 #ifdef X86_WIN64
449       if ((*p_arg)->size > sizeof(ffi_arg)
450           || ((*p_arg)->type == FFI_TYPE_STRUCT
451               && ((*p_arg)->size != 1 && (*p_arg)->size != 2
452                   && (*p_arg)->size != 4 && (*p_arg)->size != 8)))
453         {
454           z = sizeof(void *);
455           *p_argv = *(void **)argp;
456         }
457       else
458 #endif
459         {
460           z = (*p_arg)->size;
461           
462           /* because we're little endian, this is what it turns into.   */
463           
464           *p_argv = (void*) argp;
465         }
466           
467       p_argv++;
468 #ifdef X86_WIN64
469       argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
470 #else
471       argp += z;
472 #endif
473     }
474   
475   return;
476 }
477
478 #define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
479 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
480    void*  __fun = (void*)(FUN); \
481    void*  __ctx = (void*)(CTX); \
482    *(unsigned char*) &__tramp[0] = 0x41; \
483    *(unsigned char*) &__tramp[1] = 0xbb; \
484    *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
485    *(unsigned char*) &__tramp[6] = 0x48; \
486    *(unsigned char*) &__tramp[7] = 0xb8; \
487    *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
488    *(unsigned char *)  &__tramp[16] = 0x49; \
489    *(unsigned char *)  &__tramp[17] = 0xba; \
490    *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
491    *(unsigned char *)  &__tramp[26] = 0x41; \
492    *(unsigned char *)  &__tramp[27] = 0xff; \
493    *(unsigned char *)  &__tramp[28] = 0xe2; /* jmp %r10 */ \
494  }
495
496 /* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
497
498 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
499 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
500    unsigned int  __fun = (unsigned int)(FUN); \
501    unsigned int  __ctx = (unsigned int)(CTX); \
502    unsigned int  __dis = __fun - (__ctx + 10);  \
503    *(unsigned char*) &__tramp[0] = 0xb8; \
504    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
505    *(unsigned char *)  &__tramp[5] = 0xe9; \
506    *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
507  }
508
509 #define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE)  \
510 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
511    unsigned int  __fun = (unsigned int)(FUN); \
512    unsigned int  __ctx = (unsigned int)(CTX); \
513    unsigned int  __dis = __fun - (__ctx + 10); \
514    unsigned short __size = (unsigned short)(SIZE); \
515    *(unsigned char*) &__tramp[0] = 0xb8; \
516    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
517    *(unsigned char *)  &__tramp[5] = 0xe8; \
518    *(unsigned int*)  &__tramp[6] = __dis; /* call __fun  */ \
519    *(unsigned char *)  &__tramp[10] = 0xc2; \
520    *(unsigned short*)  &__tramp[11] = __size; /* ret __size  */ \
521  }
522
523 /* the cif must already be prep'ed */
524
525 ffi_status
526 ffi_prep_closure_loc (ffi_closure* closure,
527                       ffi_cif* cif,
528                       void (*fun)(ffi_cif*,void*,void**,void*),
529                       void *user_data,
530                       void *codeloc)
531 {
532 #ifdef X86_WIN64
533 #define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
534 #define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
535   if (cif->abi == FFI_WIN64) 
536     {
537       int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
538       FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
539                                  &ffi_closure_win64,
540                                  codeloc, mask);
541       /* make sure we can execute here */
542     }
543 #else
544   if (cif->abi == FFI_SYSV)
545     {
546       FFI_INIT_TRAMPOLINE (&closure->tramp[0],
547                            &ffi_closure_SYSV,
548                            (void*)codeloc);
549     }
550 #ifdef X86_WIN32
551   else if (cif->abi == FFI_STDCALL)
552     {
553       FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
554                                    &ffi_closure_STDCALL,
555                                    (void*)codeloc, cif->bytes);
556     }
557 #endif /* X86_WIN32 */
558 #endif /* !X86_WIN64 */
559   else
560     {
561       return FFI_BAD_ABI;
562     }
563     
564   closure->cif  = cif;
565   closure->user_data = user_data;
566   closure->fun  = fun;
567
568   return FFI_OK;
569 }
570
571 /* ------- Native raw API support -------------------------------- */
572
573 #if !FFI_NO_RAW_API
574
575 ffi_status
576 ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
577                           ffi_cif* cif,
578                           void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
579                           void *user_data,
580                           void *codeloc)
581 {
582   int i;
583
584   if (cif->abi != FFI_SYSV) {
585     return FFI_BAD_ABI;
586   }
587
588   /* we currently don't support certain kinds of arguments for raw
589      closures.  This should be implemented by a separate assembly
590      language routine, since it would require argument processing,
591      something we don't do now for performance.  */
592
593   for (i = cif->nargs-1; i >= 0; i--)
594     {
595       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
596       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
597     }
598   
599
600   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
601                        codeloc);
602     
603   closure->cif  = cif;
604   closure->user_data = user_data;
605   closure->fun  = fun;
606
607   return FFI_OK;
608 }
609
610 static void 
611 ffi_prep_args_raw(char *stack, extended_cif *ecif)
612 {
613   memcpy (stack, ecif->avalue, ecif->cif->bytes);
614 }
615
616 /* we borrow this routine from libffi (it must be changed, though, to
617  * actually call the function passed in the first argument.  as of
618  * libffi-1.20, this is not the case.)
619  */
620
621 void
622 ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
623 {
624   extended_cif ecif;
625   void **avalue = (void **)fake_avalue;
626
627   ecif.cif = cif;
628   ecif.avalue = avalue;
629   
630   /* If the return value is a struct and we don't have a return */
631   /* value address then we need to make one                     */
632
633   if ((rvalue == NULL) && 
634       (cif->rtype->type == FFI_TYPE_STRUCT))
635     {
636       ecif.rvalue = alloca(cif->rtype->size);
637     }
638   else
639     ecif.rvalue = rvalue;
640     
641   
642   switch (cif->abi) 
643     {
644 #ifdef X86_WIN32
645     case FFI_SYSV:
646     case FFI_STDCALL:
647       ffi_call_win32(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
648                      ecif.rvalue, fn);
649       break;
650 #else
651     case FFI_SYSV:
652       ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
653                     ecif.rvalue, fn);
654       break;
655 #endif
656     default:
657       FFI_ASSERT(0);
658       break;
659     }
660 }
661
662 #endif
663
664 #endif /* !__x86_64__  || X86_WIN64 */
665