Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
ffi.c
Go to the documentation of this file.
1 /* -----------------------------------------------------------------------
2  ffi.c - Copyright (c) 2013 Tensilica, Inc.
3 
4  XTENSA 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 /*
31  |----------------------------------------|
32  | |
33  on entry to ffi_call ----> |----------------------------------------|
34  | caller stack frame for registers a0-a3 |
35  |----------------------------------------|
36  | |
37  | additional arguments |
38  entry of the function ---> |----------------------------------------|
39  | copy of function arguments a2-a7 |
40  | - - - - - - - - - - - - - |
41  | |
42 
43  The area below the entry line becomes the new stack frame for the function.
44 
45 */
46 
47 
48 #define FFI_TYPE_STRUCT_REGS FFI_TYPE_LAST
49 
50 
51 extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags,
52  void(*fn)(void), unsigned nbytes, extended_cif*);
53 extern void ffi_closure_SYSV(void) FFI_HIDDEN;
54 
55 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
56 {
57  switch(cif->rtype->type) {
58  case FFI_TYPE_SINT8:
59  case FFI_TYPE_UINT8:
60  case FFI_TYPE_SINT16:
61  case FFI_TYPE_UINT16:
62  cif->flags = cif->rtype->type;
63  break;
64  case FFI_TYPE_VOID:
65  case FFI_TYPE_FLOAT:
66  cif->flags = FFI_TYPE_UINT32;
67  break;
68  case FFI_TYPE_DOUBLE:
69  case FFI_TYPE_UINT64:
70  case FFI_TYPE_SINT64:
71  cif->flags = FFI_TYPE_UINT64; // cif->rtype->type;
72  break;
73  case FFI_TYPE_STRUCT:
74  cif->flags = FFI_TYPE_STRUCT; //_REGS;
75  /* Up to 16 bytes are returned in registers */
76  if (cif->rtype->size > 4 * 4) {
77  /* returned structure is referenced by a register; use 8 bytes
78  (including 4 bytes for potential additional alignment) */
79  cif->flags = FFI_TYPE_STRUCT;
80  cif->bytes += 8;
81  }
82  break;
83 
84  default:
85  cif->flags = FFI_TYPE_UINT32;
86  break;
87  }
88 
89  /* Round the stack up to a full 4 register frame, just in case
90  (we use this size in movsp). This way, it's also a multiple of
91  8 bytes for 64-bit arguments. */
92  cif->bytes = ALIGN(cif->bytes, 16);
93 
94  return FFI_OK;
95 }
96 
97 void ffi_prep_args(extended_cif *ecif, unsigned char* stack)
98 {
99  unsigned int i;
100  unsigned long *addr;
101  ffi_type **ptr;
102 
103  union {
104  void **v;
105  char **c;
106  signed char **sc;
107  unsigned char **uc;
108  signed short **ss;
109  unsigned short **us;
110  unsigned int **i;
111  long long **ll;
112  float **f;
113  double **d;
114  } p_argv;
115 
116  /* Verify that everything is aligned up properly */
117  FFI_ASSERT (((unsigned long) stack & 0x7) == 0);
118 
119  p_argv.v = ecif->avalue;
120  addr = (unsigned long*)stack;
121 
122  /* structures with a size greater than 16 bytes are passed in memory */
123  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 16)
124  {
125  *addr++ = (unsigned long)ecif->rvalue;
126  }
127 
128  for (i = ecif->cif->nargs, ptr = ecif->cif->arg_types;
129  i > 0;
130  i--, ptr++, p_argv.v++)
131  {
132  switch ((*ptr)->type)
133  {
134  case FFI_TYPE_SINT8:
135  *addr++ = **p_argv.sc;
136  break;
137  case FFI_TYPE_UINT8:
138  *addr++ = **p_argv.uc;
139  break;
140  case FFI_TYPE_SINT16:
141  *addr++ = **p_argv.ss;
142  break;
143  case FFI_TYPE_UINT16:
144  *addr++ = **p_argv.us;
145  break;
146  case FFI_TYPE_FLOAT:
147  case FFI_TYPE_INT:
148  case FFI_TYPE_UINT32:
149  case FFI_TYPE_SINT32:
150  case FFI_TYPE_POINTER:
151  *addr++ = **p_argv.i;
152  break;
153  case FFI_TYPE_DOUBLE:
154  case FFI_TYPE_UINT64:
155  case FFI_TYPE_SINT64:
156  if (((unsigned long)addr & 4) != 0)
157  addr++;
158  *(unsigned long long*)addr = **p_argv.ll;
159  addr += sizeof(unsigned long long) / sizeof (addr);
160  break;
161 
162  case FFI_TYPE_STRUCT:
163  {
164  unsigned long offs;
165  unsigned long size;
166 
167  if (((unsigned long)addr & 4) != 0 && (*ptr)->alignment > 4)
168  addr++;
169 
170  offs = (unsigned long) addr - (unsigned long) stack;
171  size = (*ptr)->size;
172 
173  /* Entire structure must fit the argument registers or referenced */
174  if (offs < FFI_REGISTER_NARGS * 4
175  && offs + size > FFI_REGISTER_NARGS * 4)
176  addr = (unsigned long*) (stack + FFI_REGISTER_NARGS * 4);
177 
178  memcpy((char*) addr, *p_argv.c, size);
179  addr += (size + 3) / 4;
180  break;
181  }
182 
183  default:
184  FFI_ASSERT(0);
185  }
186  }
187 }
188 
189 
190 void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue)
191 {
192  extended_cif ecif;
193  unsigned long rsize = cif->rtype->size;
194  int flags = cif->flags;
195  void *alloc = NULL;
196 
197  ecif.cif = cif;
198  ecif.avalue = avalue;
199 
200  /* Note that for structures that are returned in registers (size <= 16 bytes)
201  we allocate a temporary buffer and use memcpy to copy it to the final
202  destination. The reason is that the target address might be misaligned or
203  the length not a multiple of 4 bytes. Handling all those cases would be
204  very complex. */
205 
206  if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL))
207  {
208  alloc = alloca(ALIGN(rsize, 4));
209  ecif.rvalue = alloc;
210  }
211  else
212  {
213  ecif.rvalue = rvalue;
214  }
215 
216  if (cif->abi != FFI_SYSV)
217  FFI_ASSERT(0);
218 
219  ffi_call_SYSV (ecif.rvalue, rsize, cif->flags, fn, cif->bytes, &ecif);
220 
221  if (alloc != NULL && rvalue != NULL)
222  memcpy(rvalue, alloc, rsize);
223 }
224 
225 extern void ffi_trampoline();
226 extern void ffi_cacheflush(void* start, void* end);
227 
228 ffi_status
229 ffi_prep_closure_loc (ffi_closure* closure,
230  ffi_cif* cif,
231  void (*fun)(ffi_cif*, void*, void**, void*),
232  void *user_data,
233  void *codeloc)
234 {
235  /* copye trampoline to stack and patch 'ffi_closure_SYSV' pointer */
236  memcpy(closure->tramp, ffi_trampoline, FFI_TRAMPOLINE_SIZE);
237  *(unsigned int*)(&closure->tramp[8]) = (unsigned int)ffi_closure_SYSV;
238 
239  // Do we have this function?
240  // __builtin___clear_cache(closer->tramp, closer->tramp + FFI_TRAMPOLINE_SIZE)
241  ffi_cacheflush(closure->tramp, closure->tramp + FFI_TRAMPOLINE_SIZE);
242 
243  closure->cif = cif;
244  closure->fun = fun;
245  closure->user_data = user_data;
246  return FFI_OK;
247 }
248 
249 
250 long FFI_HIDDEN
251 ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue)
252 {
253  ffi_cif *cif;
254  ffi_type **arg_types;
255  void **avalue;
256  int i, areg;
257 
258  cif = closure->cif;
259  if (cif->abi != FFI_SYSV)
260  return FFI_BAD_ABI;
261 
262  areg = 0;
263 
264  int rtype = cif->rtype->type;
265  if (rtype == FFI_TYPE_STRUCT && cif->rtype->size > 4 * 4)
266  {
267  rvalue = *values;
268  areg++;
269  }
270 
271  cif = closure->cif;
272  arg_types = cif->arg_types;
273  avalue = alloca(cif->nargs * sizeof(void *));
274 
275  for (i = 0; i < cif->nargs; i++)
276  {
277  if (arg_types[i]->alignment == 8 && (areg & 1) != 0)
278  areg++;
279 
280  // skip the entry 16,a1 framework, add 16 bytes (4 registers)
281  if (areg == FFI_REGISTER_NARGS)
282  areg += 4;
283 
284  if (arg_types[i]->type == FFI_TYPE_STRUCT)
285  {
286  int numregs = ((arg_types[i]->size + 3) & ~3) / 4;
287  if (areg < FFI_REGISTER_NARGS && areg + numregs > FFI_REGISTER_NARGS)
288  areg = FFI_REGISTER_NARGS + 4;
289  }
290 
291  avalue[i] = &values[areg];
292  areg += (arg_types[i]->size + 3) / 4;
293  }
294 
295  (closure->fun)(cif, rvalue, avalue, closure->user_data);
296 
297  return rtype;
298 }
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
i
uint32_t i
Definition: rb_mjit_min_header-2.7.1.h:5464
long
#define long
Definition: rb_mjit_min_header-2.7.1.h:2880
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
ffi_common.h
FFI_HIDDEN
const UINT64 ffi_template_tramp_tile[] FFI_HIDDEN
FFI_TRAMPOLINE_SIZE
#define FFI_TRAMPOLINE_SIZE
Definition: ffitarget.h:45
FFI_SYSV
@ FFI_SYSV
Definition: ffitarget.h:36
ptr
struct RIMemo * ptr
Definition: debug.c:74
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
FFI_REGISTER_NARGS
#define FFI_REGISTER_NARGS
Definition: ffitarget.h:45
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_trampoline
void ffi_trampoline()
size
int size
Definition: encoding.c:58
ffi_prep_cif_machdep
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
extended_cif
Definition: ffi_common.h:86
ffi_closure_SYSV
void ffi_closure_SYSV(ffi_closure *)
Definition: ffi.c:420
f
#define f
extended_cif::avalue
void ** avalue
Definition: ffi_common.h:90
int
__inline__ int
Definition: rb_mjit_min_header-2.7.1.h:2839
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
ffi_cacheflush
void ffi_cacheflush(void *start, void *end)
v
int VALUE v
Definition: rb_mjit_min_header-2.7.1.h:12337
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:2487
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
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39