Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
ffi.c
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------
2  ffi.c - Copyright (c) 2013 Imagination Technologies
3 
4  Meta Foreign Function Interface
5  Permission is hereby granted, free of charge, to any person obtaining
6  a copy of this software and associated documentation files (the
7  `Software''), to deal in the Software without restriction, including
8  without limitation the rights to use, copy, modify, merge, publish,
9  distribute, sublicense, and/or sell copies of the Software, and to
10  permit persons to whom the Software is furnished to do so, subject to
11  the following conditions:
12 
13  The above copyright notice and this permission notice shall be included
14  in all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED `AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  OTHER DEALINGS IN THE SOFTWARE.
23 ----------------------------------------------------------------------- */
24 
25 #include <ffi.h>
26 #include <ffi_common.h>
27 
28 #include <stdlib.h>
29 
30 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
31 
32 /*
33  * ffi_prep_args is called by the assembly routine once stack space has been
34  * allocated for the function's arguments
35  */
36 
37 unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
38 {
39  register unsigned int i;
40  register void **p_argv;
41  register char *argp;
42  register ffi_type **p_arg;
43 
44  argp = stack;
45 
46  /* Store return value */
47  if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
48  argp -= 4;
49  *(void **) argp = ecif->rvalue;
50  }
51 
52  p_argv = ecif->avalue;
53 
54  /* point to next location */
55  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++)
56  {
57  size_t z;
58 
59  /* Move argp to address of argument */
60  z = (*p_arg)->size;
61  argp -= z;
62 
63  /* Align if necessary */
64  argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
65 
66  if (z < sizeof(int)) {
67  z = sizeof(int);
68  switch ((*p_arg)->type)
69  {
70  case FFI_TYPE_SINT8:
71  *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
72  break;
73  case FFI_TYPE_UINT8:
74  *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
75  break;
76  case FFI_TYPE_SINT16:
77  *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
78  break;
79  case FFI_TYPE_UINT16:
80  *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
81  case FFI_TYPE_STRUCT:
82  memcpy(argp, *p_argv, (*p_arg)->size);
83  break;
84  default:
85  FFI_ASSERT(0);
86  }
87  } else if ( z == sizeof(int)) {
88  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
89  } else {
90  memcpy(argp, *p_argv, z);
91  }
92  }
93 
94  /* return the size of the arguments to be passed in registers,
95  padded to an 8 byte boundary to preserve stack alignment */
96  return ALIGN(MIN(stack - argp, 6*4), 8);
97 }
98 
99 /* Perform machine dependent cif processing */
100 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
101 {
102  ffi_type **ptr;
103  unsigned i, bytes = 0;
104 
105  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) {
106  if ((*ptr)->size == 0)
107  return FFI_BAD_TYPEDEF;
108 
109  /* Perform a sanity check on the argument type, do this
110  check after the initialization. */
112 
113  /* Add any padding if necessary */
114  if (((*ptr)->alignment - 1) & bytes)
115  bytes = ALIGN(bytes, (*ptr)->alignment);
116 
117  bytes += ALIGN((*ptr)->size, 4);
118  }
119 
120  /* Ensure arg space is aligned to an 8-byte boundary */
121  bytes = ALIGN(bytes, 8);
122 
123  /* Make space for the return structure pointer */
124  if (cif->rtype->type == FFI_TYPE_STRUCT) {
125  bytes += sizeof(void*);
126 
127  /* Ensure stack is aligned to an 8-byte boundary */
128  bytes = ALIGN(bytes, 8);
129  }
130 
131  cif->bytes = bytes;
132 
133  /* Set the return type flag */
134  switch (cif->rtype->type) {
135  case FFI_TYPE_VOID:
136  case FFI_TYPE_FLOAT:
137  case FFI_TYPE_DOUBLE:
138  cif->flags = (unsigned) cif->rtype->type;
139  break;
140  case FFI_TYPE_SINT64:
141  case FFI_TYPE_UINT64:
142  cif->flags = (unsigned) FFI_TYPE_SINT64;
143  break;
144  case FFI_TYPE_STRUCT:
145  /* Meta can store return values which are <= 64 bits */
146  if (cif->rtype->size <= 4)
147  /* Returned to D0Re0 as 32-bit value */
148  cif->flags = (unsigned)FFI_TYPE_INT;
149  else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8))
150  /* Returned valued is stored to D1Re0|R0Re0 */
151  cif->flags = (unsigned)FFI_TYPE_DOUBLE;
152  else
153  /* value stored in memory */
154  cif->flags = (unsigned)FFI_TYPE_STRUCT;
155  break;
156  default:
157  cif->flags = (unsigned)FFI_TYPE_INT;
158  break;
159  }
160  return FFI_OK;
161 }
162 
163 extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *);
164 
165 /*
166  * Exported in API. Entry point
167  * cif -> ffi_cif object
168  * fn -> function pointer
169  * rvalue -> pointer to return value
170  * avalue -> vector of void * pointers pointing to memory locations holding the
171  * arguments
172  */
173 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
174 {
175  extended_cif ecif;
176 
177  int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT));
178  ecif.cif = cif;
179  ecif.avalue = avalue;
180 
181  double temp;
182 
183  /*
184  * If the return value is a struct and we don't have a return value address
185  * then we need to make one
186  */
187 
188  if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT))
189  ecif.rvalue = alloca(cif->rtype->size);
190  else if (small_struct)
191  ecif.rvalue = &temp;
192  else
193  ecif.rvalue = rvalue;
194 
195  switch (cif->abi) {
196  case FFI_SYSV:
197  ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
198  break;
199  default:
200  FFI_ASSERT(0);
201  break;
202  }
203 
204  if (small_struct)
205  memcpy (rvalue, &temp, cif->rtype->size);
206 }
207 
208 /* private members */
209 
210 static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
211  ffi_cif*, float *);
212 
213 void ffi_closure_SYSV (ffi_closure *);
214 
215 /* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
216 extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */
217 
218 /* end of private members */
219 
220 /*
221  * __tramp: trampoline memory location
222  * __fun: assembly routine
223  * __ctx: memory location for wrapper
224  *
225  * At this point, tramp[0] == __ctx !
226  */
227 void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) {
229  *(unsigned int*) &__tramp[40] = __ctx;
230  *(unsigned int*) &__tramp[44] = __fun;
231  /* This will flush the instruction cache */
232  __builtin_meta2_cachewd(&__tramp[0], 1);
233  __builtin_meta2_cachewd(&__tramp[47], 1);
234 }
235 
236 
237 
238 /* the cif must already be prepared */
239 
240 ffi_status
241 ffi_prep_closure_loc (ffi_closure *closure,
242  ffi_cif* cif,
243  void (*fun)(ffi_cif*,void*,void**,void*),
244  void *user_data,
245  void *codeloc)
246 {
247  void (*closure_func)(ffi_closure*) = NULL;
248 
249  if (cif->abi == FFI_SYSV)
250  closure_func = &ffi_closure_SYSV;
251  else
252  return FFI_BAD_ABI;
253 
255  (unsigned char*)&closure->tramp[0],
256  (unsigned int)closure_func,
257  (unsigned int)codeloc);
258 
259  closure->cif = cif;
260  closure->user_data = user_data;
261  closure->fun = fun;
262 
263  return FFI_OK;
264 }
265 
266 
267 /* This function is jumped to by the trampoline */
268 unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
269  ffi_closure *closure;
270  void **respp;
271  void *args;
272  void *vfp_args;
273 {
274  ffi_cif *cif;
275  void **arg_area;
276 
277  cif = closure->cif;
278  arg_area = (void**) alloca (cif->nargs * sizeof (void*));
279 
280  /*
281  * This call will initialize ARG_AREA, such that each
282  * element in that array points to the corresponding
283  * value on the stack; and if the function returns
284  * a structure, it will re-set RESP to point to the
285  * structure return address.
286  */
287  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
288 
289  (closure->fun) ( cif, *respp, arg_area, closure->user_data);
290 
291  return cif->flags;
292 }
293 
294 static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
295  void **avalue, ffi_cif *cif,
296  float *vfp_stack)
297 {
298  register unsigned int i;
299  register void **p_argv;
300  register char *argp;
301  register ffi_type **p_arg;
302 
303  /* stack points to original arguments */
304  argp = stack;
305 
306  /* Store return value */
307  if ( cif->flags == FFI_TYPE_STRUCT ) {
308  argp -= 4;
309  *rvalue = *(void **) argp;
310  }
311 
312  p_argv = avalue;
313 
314  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) {
315  size_t z;
316  size_t alignment;
317 
318  alignment = (*p_arg)->alignment;
319  if (alignment < 4)
320  alignment = 4;
321  if ((alignment - 1) & (unsigned)argp)
322  argp = (char *) ALIGN(argp, alignment);
323 
324  z = (*p_arg)->size;
325  *p_argv = (void*) argp;
326  p_argv++;
327  argp -= z;
328  }
329  return;
330 }
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
ffi_call_SYSV
void ffi_call_SYSV(unsigned(*)(struct call_context *context, unsigned char *, extended_cif *), struct call_context *context, extended_cif *, size_t, void(*fn)(void))
extended_cif::rvalue
void * rvalue
Definition: ffi_common.h:89
int
__inline__ int
Definition: rb_mjit_min_header-2.7.2.h:2845
i
uint32_t i
Definition: rb_mjit_min_header-2.7.2.h:5460
ffi_common.h
unsigned
#define unsigned
Definition: rb_mjit_min_header-2.7.2.h:2883
alloca
#define alloca(size)
Definition: rb_mjit_min_header-2.7.2.h:2493
ffi_init_trampoline
void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx)
Definition: ffi.c:227
FFI_SYSV
@ FFI_SYSV
Definition: ffitarget.h:36
ptr
struct RIMemo * ptr
Definition: debug.c:65
ALIGN
#define ALIGN(v, a)
Definition: ffi_common.h:77
NULL
#define NULL
Definition: _sdbm.c:101
ffi_prep_args
void ffi_prep_args(char *stack, extended_cif *ecif)
Definition: ffi.c:46
void
void
Definition: rb_mjit_min_header-2.7.2.h:13241
ffi_closure_SYSV_inner
void FFI_HIDDEN ffi_closure_SYSV_inner(ffi_closure *closure, struct call_context *context, void *stack)
Definition: ffi.c:964
FFI_ASSERT_VALID_TYPE
#define FFI_ASSERT_VALID_TYPE(x)
Definition: ffi_common.h:74
MIN
#define MIN(a, b)
Definition: ffi.c:30
ffi_prep_cif_machdep
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
extended_cif
Definition: ffi_common.h:87
ffi_closure_SYSV
void ffi_closure_SYSV(ffi_closure *)
Definition: ffi.c:420
extended_cif::avalue
void ** avalue
Definition: ffi_common.h:90
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
ffi_call
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
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
extended_cif::cif
ffi_cif * cif
Definition: ffi_common.h:88
ffi_metag_trampoline
unsigned int ffi_metag_trampoline[10]
ALIGN_DOWN
#define ALIGN_DOWN(v, a)
Definition: ffi_common.h:78