Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
ffi.c
Go to the documentation of this file.
1 /* -----------------------------------------------------------------------
2  ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc.
3  Copyright (c) 2000 Hewlett Packard Company
4  Copyright (c) 2011 Anthony Green
5 
6  IA64 Foreign Function Interface
7 
8  Permission is hereby granted, free of charge, to any person obtaining
9  a copy of this software and associated documentation files (the
10  ``Software''), to deal in the Software without restriction, including
11  without limitation the rights to use, copy, modify, merge, publish,
12  distribute, sublicense, and/or sell copies of the Software, and to
13  permit persons to whom the Software is furnished to do so, subject to
14  the following conditions:
15 
16  The above copyright notice and this permission notice shall be included
17  in all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  DEALINGS IN THE SOFTWARE.
27  ----------------------------------------------------------------------- */
28 
29 #include <ffi.h>
30 #include <ffi_common.h>
31 
32 #include <stdlib.h>
33 #include <stdbool.h>
34 #include <float.h>
35 
36 #include "ia64_flags.h"
37 
38 /* A 64-bit pointer value. In LP64 mode, this is effectively a plain
39  pointer. In ILP32 mode, it's a pointer that's been extended to
40  64 bits by "addp4". */
41 typedef void *PTR64 __attribute__((mode(DI)));
42 
43 /* Memory image of fp register contents. This is the implementation
44  specific format used by ldf.fill/stf.spill. All we care about is
45  that it wants a 16 byte aligned slot. */
46 typedef struct
47 {
48  UINT64 x[2] __attribute__((aligned(16)));
49 } fpreg;
50 
51 
52 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */
53 
54 struct ia64_args
55 {
56  fpreg fp_regs[8]; /* Contents of 8 fp arg registers. */
57  UINT64 gp_regs[8]; /* Contents of 8 gp arg registers. */
58  UINT64 other_args[]; /* Arguments passed on stack, variable size. */
59 };
60 
61 
62 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */
63 
64 static inline void *
65 endian_adjust (void *addr, size_t len)
66 {
67 #ifdef __BIG_ENDIAN__
68  return addr + (8 - len);
69 #else
70  return addr;
71 #endif
72 }
73 
74 /* Store VALUE to ADDR in the current cpu implementation's fp spill format.
75  This is a macro instead of a function, so that it works for all 3 floating
76  point types without type conversions. Type conversion to long double breaks
77  the denorm support. */
78 
79 #define stf_spill(addr, value) \
80  asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
81 
82 /* Load a value from ADDR, which is in the current cpu implementation's
83  fp spill format. As above, this must also be a macro. */
84 
85 #define ldf_fill(result, addr) \
86  asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
87 
88 /* Return the size of the C type associated with with TYPE. Which will
89  be one of the FFI_IA64_TYPE_HFA_* values. */
90 
91 static size_t
92 hfa_type_size (int type)
93 {
94  switch (type)
95  {
97  return sizeof(float);
99  return sizeof(double);
101  return sizeof(__float80);
102  default:
103  abort ();
104  }
105 }
106 
107 /* Load from ADDR a value indicated by TYPE. Which will be one of
108  the FFI_IA64_TYPE_HFA_* values. */
109 
110 static void
111 hfa_type_load (fpreg *fpaddr, int type, void *addr)
112 {
113  switch (type)
114  {
116  stf_spill (fpaddr, *(float *) addr);
117  return;
119  stf_spill (fpaddr, *(double *) addr);
120  return;
122  stf_spill (fpaddr, *(__float80 *) addr);
123  return;
124  default:
125  abort ();
126  }
127 }
128 
129 /* Load VALUE into ADDR as indicated by TYPE. Which will be one of
130  the FFI_IA64_TYPE_HFA_* values. */
131 
132 static void
133 hfa_type_store (int type, void *addr, fpreg *fpaddr)
134 {
135  switch (type)
136  {
138  {
139  float result;
140  ldf_fill (result, fpaddr);
141  *(float *) addr = result;
142  break;
143  }
145  {
146  double result;
147  ldf_fill (result, fpaddr);
148  *(double *) addr = result;
149  break;
150  }
152  {
153  __float80 result;
154  ldf_fill (result, fpaddr);
155  *(__float80 *) addr = result;
156  break;
157  }
158  default:
159  abort ();
160  }
161 }
162 
163 /* Is TYPE a struct containing floats, doubles, or extended doubles,
164  all of the same fp type? If so, return the element type. Return
165  FFI_TYPE_VOID if not. */
166 
167 static int
168 hfa_element_type (ffi_type *type, int nested)
169 {
170  int element = FFI_TYPE_VOID;
171 
172  switch (type->type)
173  {
174  case FFI_TYPE_FLOAT:
175  /* We want to return VOID for raw floating-point types, but the
176  synthetic HFA type if we're nested within an aggregate. */
177  if (nested)
178  element = FFI_IA64_TYPE_HFA_FLOAT;
179  break;
180 
181  case FFI_TYPE_DOUBLE:
182  /* Similarly. */
183  if (nested)
184  element = FFI_IA64_TYPE_HFA_DOUBLE;
185  break;
186 
187  case FFI_TYPE_LONGDOUBLE:
188  /* Similarly, except that that HFA is true for double extended,
189  but not quad precision. Both have sizeof == 16, so tell the
190  difference based on the precision. */
191  if (LDBL_MANT_DIG == 64 && nested)
192  element = FFI_IA64_TYPE_HFA_LDOUBLE;
193  break;
194 
195  case FFI_TYPE_STRUCT:
196  {
197  ffi_type **ptr = &type->elements[0];
198 
199  for (ptr = &type->elements[0]; *ptr ; ptr++)
200  {
201  int sub_element = hfa_element_type (*ptr, 1);
202  if (sub_element == FFI_TYPE_VOID)
203  return FFI_TYPE_VOID;
204 
205  if (element == FFI_TYPE_VOID)
206  element = sub_element;
207  else if (element != sub_element)
208  return FFI_TYPE_VOID;
209  }
210  }
211  break;
212 
213  default:
214  return FFI_TYPE_VOID;
215  }
216 
217  return element;
218 }
219 
220 
221 /* Perform machine dependent cif processing. */
222 
223 ffi_status
224 ffi_prep_cif_machdep(ffi_cif *cif)
225 {
226  int flags;
227 
228  /* Adjust cif->bytes to include space for the bits of the ia64_args frame
229  that precedes the integer register portion. The estimate that the
230  generic bits did for the argument space required is good enough for the
231  integer component. */
232  cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
233  if (cif->bytes < sizeof(struct ia64_args))
234  cif->bytes = sizeof(struct ia64_args);
235 
236  /* Set the return type flag. */
237  flags = cif->rtype->type;
238  switch (cif->rtype->type)
239  {
240  case FFI_TYPE_LONGDOUBLE:
241  /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
242  and encode quad precision as a two-word integer structure. */
243  if (LDBL_MANT_DIG != 64)
244  flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
245  break;
246 
247  case FFI_TYPE_STRUCT:
248  {
249  size_t size = cif->rtype->size;
250  int hfa_type = hfa_element_type (cif->rtype, 0);
251 
252  if (hfa_type != FFI_TYPE_VOID)
253  {
254  size_t nelts = size / hfa_type_size (hfa_type);
255  if (nelts <= 8)
256  flags = hfa_type | (size << 8);
257  }
258  else
259  {
260  if (size <= 32)
261  flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
262  }
263  }
264  break;
265 
266  default:
267  break;
268  }
269  cif->flags = flags;
270 
271  return FFI_OK;
272 }
273 
274 extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
275 
276 void
277 ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
278 {
279  struct ia64_args *stack;
280  long i, avn, gpcount, fpcount;
281  ffi_type **p_arg;
282 
283  FFI_ASSERT (cif->abi == FFI_UNIX);
284 
285  /* If we have no spot for a return value, make one. */
286  if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
287  rvalue = alloca (cif->rtype->size);
288 
289  /* Allocate the stack frame. */
290  stack = alloca (cif->bytes);
291 
292  gpcount = fpcount = 0;
293  avn = cif->nargs;
294  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
295  {
296  switch ((*p_arg)->type)
297  {
298  case FFI_TYPE_SINT8:
299  stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
300  break;
301  case FFI_TYPE_UINT8:
302  stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
303  break;
304  case FFI_TYPE_SINT16:
305  stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
306  break;
307  case FFI_TYPE_UINT16:
308  stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
309  break;
310  case FFI_TYPE_SINT32:
311  stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
312  break;
313  case FFI_TYPE_UINT32:
314  stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
315  break;
316  case FFI_TYPE_SINT64:
317  case FFI_TYPE_UINT64:
318  stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
319  break;
320 
321  case FFI_TYPE_POINTER:
322  stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
323  break;
324 
325  case FFI_TYPE_FLOAT:
326  if (gpcount < 8 && fpcount < 8)
327  stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
328  {
329  UINT32 tmp;
330  memcpy (&tmp, avalue[i], sizeof (UINT32));
331  stack->gp_regs[gpcount++] = tmp;
332  }
333  break;
334 
335  case FFI_TYPE_DOUBLE:
336  if (gpcount < 8 && fpcount < 8)
337  stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
338  memcpy (&stack->gp_regs[gpcount++], avalue[i], sizeof (UINT64));
339  break;
340 
341  case FFI_TYPE_LONGDOUBLE:
342  if (gpcount & 1)
343  gpcount++;
344  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
345  stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
346  memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
347  gpcount += 2;
348  break;
349 
350  case FFI_TYPE_STRUCT:
351  {
352  size_t size = (*p_arg)->size;
353  size_t align = (*p_arg)->alignment;
354  int hfa_type = hfa_element_type (*p_arg, 0);
355 
356  FFI_ASSERT (align <= 16);
357  if (align == 16 && (gpcount & 1))
358  gpcount++;
359 
360  if (hfa_type != FFI_TYPE_VOID)
361  {
362  size_t hfa_size = hfa_type_size (hfa_type);
363  size_t offset = 0;
364  size_t gp_offset = gpcount * 8;
365 
366  while (fpcount < 8
367  && offset < size
368  && gp_offset < 8 * 8)
369  {
370  hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
371  avalue[i] + offset);
372  offset += hfa_size;
373  gp_offset += hfa_size;
374  fpcount += 1;
375  }
376  }
377 
378  memcpy (&stack->gp_regs[gpcount], avalue[i], size);
379  gpcount += (size + 7) / 8;
380  }
381  break;
382 
383  default:
384  abort ();
385  }
386  }
387 
388  ffi_call_unix (stack, rvalue, fn, cif->flags);
389 }
390 
391 /* Closures represent a pair consisting of a function pointer, and
392  some user data. A closure is invoked by reinterpreting the closure
393  as a function pointer, and branching to it. Thus we can make an
394  interpreted function callable as a C function: We turn the
395  interpreter itself, together with a pointer specifying the
396  interpreted procedure, into a closure.
397 
398  For IA64, function pointer are already pairs consisting of a code
399  pointer, and a gp pointer. The latter is needed to access global
400  variables. Here we set up such a pair as the first two words of
401  the closure (in the "trampoline" area), but we replace the gp
402  pointer with a pointer to the closure itself. We also add the real
403  gp pointer to the closure. This allows the function entry code to
404  both retrieve the user data, and to restore the correct gp pointer. */
405 
406 extern void ffi_closure_unix ();
407 
408 ffi_status
409 ffi_prep_closure_loc (ffi_closure* closure,
410  ffi_cif* cif,
411  void (*fun)(ffi_cif*,void*,void**,void*),
412  void *user_data,
413  void *codeloc)
414 {
415  /* The layout of a function descriptor. A C function pointer really
416  points to one of these. */
417  struct ia64_fd
418  {
419  UINT64 code_pointer;
420  UINT64 gp;
421  };
422 
423  struct ffi_ia64_trampoline_struct
424  {
425  UINT64 code_pointer; /* Pointer to ffi_closure_unix. */
426  UINT64 fake_gp; /* Pointer to closure, installed as gp. */
427  UINT64 real_gp; /* Real gp value. */
428  };
429 
430  struct ffi_ia64_trampoline_struct *tramp;
431  struct ia64_fd *fd;
432 
433  if (cif->abi != FFI_UNIX)
434  return FFI_BAD_ABI;
435 
436  tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
437  fd = (struct ia64_fd *)(void *)ffi_closure_unix;
438 
439  tramp->code_pointer = fd->code_pointer;
440  tramp->real_gp = fd->gp;
441  tramp->fake_gp = (UINT64)(PTR64)codeloc;
442  closure->cif = cif;
443  closure->user_data = user_data;
444  closure->fun = fun;
445 
446  return FFI_OK;
447 }
448 
449 
450 UINT64
451 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
452  void *rvalue, void *r8)
453 {
454  ffi_cif *cif;
455  void **avalue;
456  ffi_type **p_arg;
457  long i, avn, gpcount, fpcount;
458 
459  cif = closure->cif;
460  avn = cif->nargs;
461  avalue = alloca (avn * sizeof (void *));
462 
463  /* If the structure return value is passed in memory get that location
464  from r8 so as to pass the value directly back to the caller. */
465  if (cif->flags == FFI_TYPE_STRUCT)
466  rvalue = r8;
467 
468  gpcount = fpcount = 0;
469  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
470  {
471  switch ((*p_arg)->type)
472  {
473  case FFI_TYPE_SINT8:
474  case FFI_TYPE_UINT8:
475  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
476  break;
477  case FFI_TYPE_SINT16:
478  case FFI_TYPE_UINT16:
479  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
480  break;
481  case FFI_TYPE_SINT32:
482  case FFI_TYPE_UINT32:
483  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
484  break;
485  case FFI_TYPE_SINT64:
486  case FFI_TYPE_UINT64:
487  avalue[i] = &stack->gp_regs[gpcount++];
488  break;
489  case FFI_TYPE_POINTER:
490  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
491  break;
492 
493  case FFI_TYPE_FLOAT:
494  if (gpcount < 8 && fpcount < 8)
495  {
496  fpreg *addr = &stack->fp_regs[fpcount++];
497  float result;
498  avalue[i] = addr;
499  ldf_fill (result, addr);
500  *(float *)addr = result;
501  }
502  else
503  avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
504  gpcount++;
505  break;
506 
507  case FFI_TYPE_DOUBLE:
508  if (gpcount < 8 && fpcount < 8)
509  {
510  fpreg *addr = &stack->fp_regs[fpcount++];
511  double result;
512  avalue[i] = addr;
513  ldf_fill (result, addr);
514  *(double *)addr = result;
515  }
516  else
517  avalue[i] = &stack->gp_regs[gpcount];
518  gpcount++;
519  break;
520 
521  case FFI_TYPE_LONGDOUBLE:
522  if (gpcount & 1)
523  gpcount++;
524  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
525  {
526  fpreg *addr = &stack->fp_regs[fpcount++];
527  __float80 result;
528  avalue[i] = addr;
529  ldf_fill (result, addr);
530  *(__float80 *)addr = result;
531  }
532  else
533  avalue[i] = &stack->gp_regs[gpcount];
534  gpcount += 2;
535  break;
536 
537  case FFI_TYPE_STRUCT:
538  {
539  size_t size = (*p_arg)->size;
540  size_t align = (*p_arg)->alignment;
541  int hfa_type = hfa_element_type (*p_arg, 0);
542 
543  FFI_ASSERT (align <= 16);
544  if (align == 16 && (gpcount & 1))
545  gpcount++;
546 
547  if (hfa_type != FFI_TYPE_VOID)
548  {
549  size_t hfa_size = hfa_type_size (hfa_type);
550  size_t offset = 0;
551  size_t gp_offset = gpcount * 8;
552  void *addr = alloca (size);
553 
554  avalue[i] = addr;
555 
556  while (fpcount < 8
557  && offset < size
558  && gp_offset < 8 * 8)
559  {
560  hfa_type_store (hfa_type, addr + offset,
561  &stack->fp_regs[fpcount]);
562  offset += hfa_size;
563  gp_offset += hfa_size;
564  fpcount += 1;
565  }
566 
567  if (offset < size)
568  memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
569  size - offset);
570  }
571  else
572  avalue[i] = &stack->gp_regs[gpcount];
573 
574  gpcount += (size + 7) / 8;
575  }
576  break;
577 
578  default:
579  abort ();
580  }
581  }
582 
583  closure->fun (cif, rvalue, avalue, closure->user_data);
584 
585  return cif->flags;
586 }
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
i
uint32_t i
Definition: rb_mjit_min_header-2.7.1.h:5425
stf_spill
#define stf_spill(addr, value)
Definition: ffi.c:79
abort
void abort(void) __attribute__((__noreturn__))
FFI_TYPE_LONGDOUBLE
#define FFI_TYPE_LONGDOUBLE
Definition: ffi.c:40
double
double
Definition: rb_mjit_min_header-2.7.1.h:5884
fpreg
Definition: ffi.c:46
ia64_args
Definition: ffi.c:54
ffi_common.h
offsetof
#define offsetof(p_type, field)
Definition: addrinfo.h:186
FFI_IA64_TYPE_SMALL_STRUCT
#define FFI_IA64_TYPE_SMALL_STRUCT
Definition: ia64_flags.h:34
ptr
struct RIMemo * ptr
Definition: debug.c:74
stdbool.h
ia64_args::gp_regs
UINT64 gp_regs[8]
Definition: ffi.c:57
ia64_args::fp_regs
fpreg fp_regs[8]
Definition: ffi.c:56
NULL
#define NULL
Definition: _sdbm.c:101
__attribute__
void *PTR64 __attribute__((mode(DI)))
Definition: ffi.c:41
FFI_IA64_TYPE_HFA_DOUBLE
#define FFI_IA64_TYPE_HFA_DOUBLE
Definition: ia64_flags.h:39
FFI_UNIX
@ FFI_UNIX
Definition: ffitarget.h:41
ffi_closure_unix
void ffi_closure_unix()
size
int size
Definition: encoding.c:58
ffi_prep_cif_machdep
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
FFI_IA64_TYPE_HFA_LDOUBLE
#define FFI_IA64_TYPE_HFA_LDOUBLE
Definition: ia64_flags.h:40
ia64_flags.h
ffi_closure_unix_inner
UINT64 ffi_closure_unix_inner(ffi_closure *closure, struct ia64_args *stack, void *rvalue, void *r8)
Definition: ffi.c:451
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
len
uint8_t len
Definition: escape.c:17
ffi_call
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
alloca
#define alloca(size)
Definition: rb_mjit_min_header-2.7.1.h:2455
ffi_prep_closure_loc
ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void(*fun)(ffi_cif *, void *, void **, void *), void *user_data, void *codeloc)
Definition: ffi.c:928
ldf_fill
#define ldf_fill(result, addr)
Definition: ffi.c:85
ffi_call_unix
int ffi_call_unix(struct ia64_args *, PTR64, void(*)(void), UINT64)
ia64_args::other_args
UINT64 other_args[]
Definition: ffi.c:58
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
FFI_IA64_TYPE_HFA_FLOAT
#define FFI_IA64_TYPE_HFA_FLOAT
Definition: ia64_flags.h:38