Ruby  2.4.2p198(2017-09-14revision59899)
ffi.c
Go to the documentation of this file.
1 /* -----------------------------------------------------------------------
2  ffi.c - Copyright (c) 2003, 2004, 2006, 2007, 2012 Kaz Kojima
3  Copyright (c) 2008 Anthony Green
4 
5  SuperH SHmedia Foreign Function Interface
6 
7  Permission is hereby granted, free of charge, to any person obtaining
8  a copy of this software and associated documentation files (the
9  ``Software''), to deal in the Software without restriction, including
10  without limitation the rights to use, copy, modify, merge, publish,
11  distribute, sublicense, and/or sell copies of the Software, and to
12  permit persons to whom the Software is furnished to do so, subject to
13  the following conditions:
14 
15  The above copyright notice and this permission notice shall be included
16  in all copies or substantial portions of the Software.
17 
18  THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  DEALINGS IN THE SOFTWARE.
26  ----------------------------------------------------------------------- */
27 
28 #include <ffi.h>
29 #include <ffi_common.h>
30 
31 #include <stdlib.h>
32 
33 #define NGREGARG 8
34 #define NFREGARG 12
35 
36 static int
37 return_type (ffi_type *arg)
38 {
39 
40  if (arg->type != FFI_TYPE_STRUCT)
41  return arg->type;
42 
43  /* gcc uses r2 if the result can be packed in on register. */
44  if (arg->size <= sizeof (UINT8))
45  return FFI_TYPE_UINT8;
46  else if (arg->size <= sizeof (UINT16))
47  return FFI_TYPE_UINT16;
48  else if (arg->size <= sizeof (UINT32))
49  return FFI_TYPE_UINT32;
50  else if (arg->size <= sizeof (UINT64))
51  return FFI_TYPE_UINT64;
52 
53  return FFI_TYPE_STRUCT;
54 }
55 
56 /* ffi_prep_args is called by the assembly routine once stack space
57  has been allocated for the function's arguments */
58 
59 void ffi_prep_args(char *stack, extended_cif *ecif)
60 {
61  register unsigned int i;
62  register unsigned int avn;
63  register void **p_argv;
64  register char *argp;
65  register ffi_type **p_arg;
66 
67  argp = stack;
68 
69  if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
70  {
71  *(void **) argp = ecif->rvalue;
72  argp += sizeof (UINT64);
73  }
74 
75  avn = ecif->cif->nargs;
76  p_argv = ecif->avalue;
77 
78  for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
79  {
80  size_t z;
81  int align;
82 
83  z = (*p_arg)->size;
84  align = (*p_arg)->alignment;
85  if (z < sizeof (UINT32))
86  {
87  switch ((*p_arg)->type)
88  {
89  case FFI_TYPE_SINT8:
90  *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
91  break;
92 
93  case FFI_TYPE_UINT8:
94  *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
95  break;
96 
97  case FFI_TYPE_SINT16:
98  *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
99  break;
100 
101  case FFI_TYPE_UINT16:
102  *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
103  break;
104 
105  case FFI_TYPE_STRUCT:
106  memcpy (argp, *p_argv, z);
107  break;
108 
109  default:
110  FFI_ASSERT(0);
111  }
112  argp += sizeof (UINT64);
113  }
114  else if (z == sizeof (UINT32) && align == sizeof (UINT32))
115  {
116  switch ((*p_arg)->type)
117  {
118  case FFI_TYPE_INT:
119  case FFI_TYPE_SINT32:
120  *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
121  break;
122 
123  case FFI_TYPE_FLOAT:
124  case FFI_TYPE_POINTER:
125  case FFI_TYPE_UINT32:
126  case FFI_TYPE_STRUCT:
127  *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
128  break;
129 
130  default:
131  FFI_ASSERT(0);
132  break;
133  }
134  argp += sizeof (UINT64);
135  }
136  else if (z == sizeof (UINT64)
137  && align == sizeof (UINT64)
138  && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
139  {
140  *(UINT64 *) argp = *(UINT64 *) (*p_argv);
141  argp += sizeof (UINT64);
142  }
143  else
144  {
145  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
146 
147  memcpy (argp, *p_argv, z);
148  argp += n * sizeof (UINT64);
149  }
150  }
151 
152  return;
153 }
154 
155 /* Perform machine dependent cif processing */
156 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
157 {
158  int i, j;
159  int size, type;
160  int n, m;
161  int greg;
162  int freg;
163  int fpair = -1;
164 
165  greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
166  freg = 0;
167  cif->flags2 = 0;
168 
169  for (i = j = 0; i < cif->nargs; i++)
170  {
171  type = (cif->arg_types)[i]->type;
172  switch (type)
173  {
174  case FFI_TYPE_FLOAT:
175  greg++;
176  cif->bytes += sizeof (UINT64) - sizeof (float);
177  if (freg >= NFREGARG - 1)
178  continue;
179  if (fpair < 0)
180  {
181  fpair = freg;
182  freg += 2;
183  }
184  else
185  fpair = -1;
186  cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
187  break;
188 
189  case FFI_TYPE_DOUBLE:
190  if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
191  continue;
192  if ((freg + 1) < NFREGARG)
193  {
194  freg += 2;
195  cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
196  }
197  else
198  cif->flags2 += FFI_TYPE_INT << (2 * j++);
199  break;
200 
201  default:
202  size = (cif->arg_types)[i]->size;
203  if (size < sizeof (UINT64))
204  cif->bytes += sizeof (UINT64) - size;
205  n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
206  if (greg >= NGREGARG)
207  continue;
208  else if (greg + n - 1 >= NGREGARG)
209  greg = NGREGARG;
210  else
211  greg += n;
212  for (m = 0; m < n; m++)
213  cif->flags2 += FFI_TYPE_INT << (2 * j++);
214  break;
215  }
216  }
217 
218  /* Set the return type flag */
219  switch (cif->rtype->type)
220  {
221  case FFI_TYPE_STRUCT:
222  cif->flags = return_type (cif->rtype);
223  break;
224 
225  case FFI_TYPE_VOID:
226  case FFI_TYPE_FLOAT:
227  case FFI_TYPE_DOUBLE:
228  case FFI_TYPE_SINT64:
229  case FFI_TYPE_UINT64:
230  cif->flags = cif->rtype->type;
231  break;
232 
233  default:
234  cif->flags = FFI_TYPE_INT;
235  break;
236  }
237 
238  return FFI_OK;
239 }
240 
241 /*@-declundef@*/
242 /*@-exportheader@*/
243 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
244  /*@out@*/ extended_cif *,
245  unsigned, unsigned, long long,
246  /*@out@*/ unsigned *,
247  void (*fn)(void));
248 /*@=declundef@*/
249 /*@=exportheader@*/
250 
251 void ffi_call(/*@dependent@*/ ffi_cif *cif,
252  void (*fn)(void),
253  /*@out@*/ void *rvalue,
254  /*@dependent@*/ void **avalue)
255 {
256  extended_cif ecif;
257  UINT64 trvalue;
258 
259  ecif.cif = cif;
260  ecif.avalue = avalue;
261 
262  /* If the return value is a struct and we don't have a return */
263  /* value address then we need to make one */
264 
265  if (cif->rtype->type == FFI_TYPE_STRUCT
266  && return_type (cif->rtype) != FFI_TYPE_STRUCT)
267  ecif.rvalue = &trvalue;
268  else if ((rvalue == NULL) &&
269  (cif->rtype->type == FFI_TYPE_STRUCT))
270  {
271  ecif.rvalue = alloca(cif->rtype->size);
272  }
273  else
274  ecif.rvalue = rvalue;
275 
276  switch (cif->abi)
277  {
278  case FFI_SYSV:
279  ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
280  ecif.rvalue, fn);
281  break;
282  default:
283  FFI_ASSERT(0);
284  break;
285  }
286 
287  if (rvalue
288  && cif->rtype->type == FFI_TYPE_STRUCT
289  && return_type (cif->rtype) != FFI_TYPE_STRUCT)
290  memcpy (rvalue, &trvalue, cif->rtype->size);
291 }
292 
293 extern void ffi_closure_SYSV (void);
294 extern void __ic_invalidate (void *line);
295 
296 ffi_status
297 ffi_prep_closure_loc (ffi_closure *closure,
298  ffi_cif *cif,
299  void (*fun)(ffi_cif*, void*, void**, void*),
300  void *user_data,
301  void *codeloc)
302 {
303  unsigned int *tramp;
304 
305  if (cif->abi != FFI_SYSV)
306  return FFI_BAD_ABI;
307 
308  tramp = (unsigned int *) &closure->tramp[0];
309  /* Since ffi_closure is an aligned object, the ffi trampoline is
310  called as an SHcompact code. Sigh.
311  SHcompact part:
312  mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
313  SHmedia part:
314  movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
315  movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
316 #ifdef __LITTLE_ENDIAN__
317  tramp[0] = 0x7001c701;
318  tramp[1] = 0x0009402b;
319 #else
320  tramp[0] = 0xc7017001;
321  tramp[1] = 0x402b0009;
322 #endif
323  tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
324  tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
325  tramp[4] = 0x6bf10600;
326  tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
327  tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
328  tramp[7] = 0x4401fff0;
329 
330  closure->cif = cif;
331  closure->fun = fun;
332  closure->user_data = user_data;
333 
334  /* Flush the icache. */
335  asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
336  "r"(codeloc));
337 
338  return FFI_OK;
339 }
340 
341 /* Basically the trampoline invokes ffi_closure_SYSV, and on
342  * entry, r3 holds the address of the closure.
343  * After storing the registers that could possibly contain
344  * parameters to be passed into the stack frame and setting
345  * up space for a return value, ffi_closure_SYSV invokes the
346  * following helper function to do most of the work.
347  */
348 
349 int
350 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
351  UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
352 {
353  void **avalue;
354  ffi_type **p_arg;
355  int i, avn;
356  int greg, freg;
357  ffi_cif *cif;
358  int fpair = -1;
359 
360  cif = closure->cif;
361  avalue = alloca (cif->nargs * sizeof (void *));
362 
363  /* Copy the caller's structure return value address so that the closure
364  returns the data directly to the caller. */
365  if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
366  {
367  rvalue = (UINT64 *) *pgr;
368  greg = 1;
369  }
370  else
371  greg = 0;
372 
373  freg = 0;
374  cif = closure->cif;
375  avn = cif->nargs;
376 
377  /* Grab the addresses of the arguments from the stack frame. */
378  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
379  {
380  size_t z;
381  void *p;
382 
383  z = (*p_arg)->size;
384  if (z < sizeof (UINT32))
385  {
386  p = pgr + greg++;
387 
388  switch ((*p_arg)->type)
389  {
390  case FFI_TYPE_SINT8:
391  case FFI_TYPE_UINT8:
392  case FFI_TYPE_SINT16:
393  case FFI_TYPE_UINT16:
394  case FFI_TYPE_STRUCT:
395 #ifdef __LITTLE_ENDIAN__
396  avalue[i] = p;
397 #else
398  avalue[i] = ((char *) p) + sizeof (UINT32) - z;
399 #endif
400  break;
401 
402  default:
403  FFI_ASSERT(0);
404  }
405  }
406  else if (z == sizeof (UINT32))
407  {
408  if ((*p_arg)->type == FFI_TYPE_FLOAT)
409  {
410  if (freg < NFREGARG - 1)
411  {
412  if (fpair >= 0)
413  {
414  avalue[i] = (UINT32 *) pfr + fpair;
415  fpair = -1;
416  }
417  else
418  {
419 #ifdef __LITTLE_ENDIAN__
420  fpair = freg;
421  avalue[i] = (UINT32 *) pfr + (1 ^ freg);
422 #else
423  fpair = 1 ^ freg;
424  avalue[i] = (UINT32 *) pfr + freg;
425 #endif
426  freg += 2;
427  }
428  }
429  else
430 #ifdef __LITTLE_ENDIAN__
431  avalue[i] = pgr + greg;
432 #else
433  avalue[i] = (UINT32 *) (pgr + greg) + 1;
434 #endif
435  }
436  else
437 #ifdef __LITTLE_ENDIAN__
438  avalue[i] = pgr + greg;
439 #else
440  avalue[i] = (UINT32 *) (pgr + greg) + 1;
441 #endif
442  greg++;
443  }
444  else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
445  {
446  if (freg + 1 >= NFREGARG)
447  avalue[i] = pgr + greg;
448  else
449  {
450  avalue[i] = pfr + (freg >> 1);
451  freg += 2;
452  }
453  greg++;
454  }
455  else
456  {
457  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
458 
459  avalue[i] = pgr + greg;
460  greg += n;
461  }
462  }
463 
464  (closure->fun) (cif, rvalue, avalue, closure->user_data);
465 
466  /* Tell ffi_closure_SYSV how to perform return type promotions. */
467  return return_type (cif->rtype);
468 }
469 
void __ic_invalidate(void *line)
static int return_type(ffi_type *arg)
Definition: ffi.c:37
void ffi_closure_helper_SYSV(ffi_closure *, unsigned long *, unsigned long long *, unsigned long *)
Definition: ffi.c:553
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
void ffi_call_SYSV(unsigned(*)(struct call_context *context, unsigned char *, extended_cif *), struct call_context *context, extended_cif *, size_t, void(*fn)(void))
ffi_cif * cif
Definition: ffi_common.h:88
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
#define NGREGARG
Definition: ffi.c:33
void * rvalue
Definition: ffi_common.h:89
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
char * alloca()
#define NFREGARG
Definition: ffi.c:34
int size
Definition: encoding.c:57
#define memcpy(d, s, n)
Definition: ffi_common.h:55
void ffi_prep_args(char *stack, extended_cif *ecif)
Definition: ffi.c:46
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
#define NULL
Definition: _sdbm.c:102
void ** avalue
Definition: ffi_common.h:90
void ffi_closure_SYSV(ffi_closure *)
Definition: ffi.c:420