PageRenderTime 76ms CodeModel.GetById 23ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/Modules/_ctypes/libffi/src/sh/ffi.c

http://unladen-swallow.googlecode.com/
C | 716 lines | 584 code | 83 blank | 49 comment | 119 complexity | 67239bfdd657017e6c856aac9055bf28 MD5 | raw file
  1/* -----------------------------------------------------------------------
  2   ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Kaz Kojima
  3           Copyright (c) 2008 Red Hat, Inc.
  4   
  5   SuperH 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 4
 34#if defined(__SH4__)
 35#define NFREGARG 8
 36#endif
 37
 38#if defined(__HITACHI__)
 39#define STRUCT_VALUE_ADDRESS_WITH_ARG 1
 40#else
 41#define STRUCT_VALUE_ADDRESS_WITH_ARG 0
 42#endif
 43
 44/* If the structure has essentialy an unique element, return its type.  */
 45static int
 46simple_type (ffi_type *arg)
 47{
 48  if (arg->type != FFI_TYPE_STRUCT)
 49    return arg->type;
 50  else if (arg->elements[1])
 51    return FFI_TYPE_STRUCT;
 52
 53  return simple_type (arg->elements[0]);
 54}
 55
 56static int
 57return_type (ffi_type *arg)
 58{
 59  unsigned short type;
 60
 61  if (arg->type != FFI_TYPE_STRUCT)
 62    return arg->type;
 63
 64  type = simple_type (arg->elements[0]);
 65  if (! arg->elements[1])
 66    {
 67      switch (type)
 68	{
 69	case FFI_TYPE_SINT8:
 70	case FFI_TYPE_UINT8:
 71	case FFI_TYPE_SINT16:
 72	case FFI_TYPE_UINT16:
 73	case FFI_TYPE_SINT32:
 74	case FFI_TYPE_UINT32:
 75	  return FFI_TYPE_INT;
 76
 77	default:
 78	  return type;
 79	}
 80    }
 81
 82  /* gcc uses r0/r1 pair for some kind of structures.  */
 83  if (arg->size <= 2 * sizeof (int))
 84    {
 85      int i = 0;
 86      ffi_type *e;
 87
 88      while ((e = arg->elements[i++]))
 89	{
 90	  type = simple_type (e);
 91	  switch (type)
 92	    {
 93	    case FFI_TYPE_SINT32:
 94	    case FFI_TYPE_UINT32:
 95	    case FFI_TYPE_INT:
 96	    case FFI_TYPE_FLOAT:
 97	      return FFI_TYPE_UINT64;
 98
 99	    default:
100	      break;
101	    }
102	}
103    }
104
105  return FFI_TYPE_STRUCT;
106}
107
108/* ffi_prep_args is called by the assembly routine once stack space
109   has been allocated for the function's arguments */
110
111void ffi_prep_args(char *stack, extended_cif *ecif)
112{
113  register unsigned int i;
114  register int tmp;
115  register unsigned int avn;
116  register void **p_argv;
117  register char *argp;
118  register ffi_type **p_arg;
119  int greg, ireg;
120#if defined(__SH4__)
121  int freg = 0;
122#endif
123
124  tmp = 0;
125  argp = stack;
126
127  if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
128    {
129      *(void **) argp = ecif->rvalue;
130      argp += 4;
131      ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
132    }
133  else
134    ireg = 0;
135
136  /* Set arguments for registers.  */
137  greg = ireg;
138  avn = ecif->cif->nargs;
139  p_argv = ecif->avalue;
140
141  for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
142    {
143      size_t z;
144
145      z = (*p_arg)->size;
146      if (z < sizeof(int))
147	{
148	  if (greg++ >= NGREGARG)
149	    continue;
150
151	  z = sizeof(int);
152	  switch ((*p_arg)->type)
153	    {
154	    case FFI_TYPE_SINT8:
155	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
156	      break;
157  
158	    case FFI_TYPE_UINT8:
159	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
160	      break;
161  
162	    case FFI_TYPE_SINT16:
163	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
164	      break;
165  
166	    case FFI_TYPE_UINT16:
167	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
168	      break;
169  
170	    case FFI_TYPE_STRUCT:
171	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
172	      break;
173
174	    default:
175	      FFI_ASSERT(0);
176	    }
177	  argp += z;
178	}
179      else if (z == sizeof(int))
180	{
181#if defined(__SH4__)
182	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
183	    {
184	      if (freg++ >= NFREGARG)
185		continue;
186	    }
187	  else
188#endif
189	    {
190	      if (greg++ >= NGREGARG)
191		continue;
192	    }
193	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
194	  argp += z;
195	}
196#if defined(__SH4__)
197      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
198	{
199	  if (freg + 1 >= NFREGARG)
200	    continue;
201	  freg = (freg + 1) & ~1;
202	  freg += 2;
203	  memcpy (argp, *p_argv, z);
204	  argp += z;
205	}
206#endif
207      else
208	{
209	  int n = (z + sizeof (int) - 1) / sizeof (int);
210#if defined(__SH4__)
211	  if (greg + n - 1 >= NGREGARG)
212	    continue;
213#else
214	  if (greg >= NGREGARG)
215	    continue;
216#endif
217	  greg += n;
218	  memcpy (argp, *p_argv, z);
219	  argp += n * sizeof (int);
220	}
221    }
222
223  /* Set arguments on stack.  */
224  greg = ireg;
225#if defined(__SH4__)
226  freg = 0;
227#endif
228  p_argv = ecif->avalue;
229
230  for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
231    {
232      size_t z;
233
234      z = (*p_arg)->size;
235      if (z < sizeof(int))
236	{
237	  if (greg++ < NGREGARG)
238	    continue;
239
240	  z = sizeof(int);
241	  switch ((*p_arg)->type)
242	    {
243	    case FFI_TYPE_SINT8:
244	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
245	      break;
246  
247	    case FFI_TYPE_UINT8:
248	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
249	      break;
250  
251	    case FFI_TYPE_SINT16:
252	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
253	      break;
254  
255	    case FFI_TYPE_UINT16:
256	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
257	      break;
258  
259	    case FFI_TYPE_STRUCT:
260	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
261	      break;
262
263	    default:
264	      FFI_ASSERT(0);
265	    }
266	  argp += z;
267	}
268      else if (z == sizeof(int))
269	{
270#if defined(__SH4__)
271	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
272	    {
273	      if (freg++ < NFREGARG)
274		continue;
275	    }
276	  else
277#endif
278	    {
279	      if (greg++ < NGREGARG)
280		continue;
281	    }
282	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
283	  argp += z;
284	}
285#if defined(__SH4__)
286      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
287	{
288	  if (freg + 1 < NFREGARG)
289	    {
290	      freg = (freg + 1) & ~1;
291	      freg += 2;
292	      continue;
293	    }
294	  memcpy (argp, *p_argv, z);
295	  argp += z;
296	}
297#endif
298      else
299	{
300	  int n = (z + sizeof (int) - 1) / sizeof (int);
301	  if (greg + n - 1 < NGREGARG)
302	    {
303	      greg += n;
304	      continue;
305	    }
306#if (! defined(__SH4__))
307	  else if (greg < NGREGARG)
308	    {
309	      greg = NGREGARG;
310	      continue;
311	    }
312#endif
313	  memcpy (argp, *p_argv, z);
314	  argp += n * sizeof (int);
315	}
316    }
317
318  return;
319}
320
321/* Perform machine dependent cif processing */
322ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
323{
324  int i, j;
325  int size, type;
326  int n, m;
327  int greg;
328#if defined(__SH4__)
329  int freg = 0;
330#endif
331
332  cif->flags = 0;
333
334  greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
335	  STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
336
337#if defined(__SH4__)
338  for (i = j = 0; i < cif->nargs && j < 12; i++)
339    {
340      type = (cif->arg_types)[i]->type;
341      switch (type)
342	{
343	case FFI_TYPE_FLOAT:
344	  if (freg >= NFREGARG)
345	    continue;
346	  freg++;
347	  cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
348	  j++;
349	  break;
350
351	case FFI_TYPE_DOUBLE:
352	  if ((freg + 1) >= NFREGARG)
353	    continue;
354	  freg = (freg + 1) & ~1;
355	  freg += 2;
356	  cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
357	  j++;
358	  break;
359	      
360	default:
361	  size = (cif->arg_types)[i]->size;
362	  n = (size + sizeof (int) - 1) / sizeof (int);
363	  if (greg + n - 1 >= NGREGARG)
364		continue;
365	  greg += n;
366	  for (m = 0; m < n; m++)
367	    cif->flags += FFI_TYPE_INT << (2 * j++);
368	  break;
369	}
370    }
371#else
372  for (i = j = 0; i < cif->nargs && j < 4; i++)
373    {
374      size = (cif->arg_types)[i]->size;
375      n = (size + sizeof (int) - 1) / sizeof (int);
376      if (greg >= NGREGARG)
377	continue;
378      else if (greg + n - 1 >= NGREGARG)
379	n = NGREGARG - greg;
380      greg += n;
381      for (m = 0; m < n; m++)
382        cif->flags += FFI_TYPE_INT << (2 * j++);
383    }
384#endif
385
386  /* Set the return type flag */
387  switch (cif->rtype->type)
388    {
389    case FFI_TYPE_STRUCT:
390      cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
391      break;
392
393    case FFI_TYPE_VOID:
394    case FFI_TYPE_FLOAT:
395    case FFI_TYPE_DOUBLE:
396    case FFI_TYPE_SINT64:
397    case FFI_TYPE_UINT64:
398      cif->flags += (unsigned) cif->rtype->type << 24;
399      break;
400
401    default:
402      cif->flags += FFI_TYPE_INT << 24;
403      break;
404    }
405
406  return FFI_OK;
407}
408
409extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
410			  unsigned, unsigned, unsigned *, void (*fn)(void));
411
412void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
413{
414  extended_cif ecif;
415  UINT64 trvalue;
416
417  ecif.cif = cif;
418  ecif.avalue = avalue;
419  
420  /* If the return value is a struct and we don't have a return	*/
421  /* value address then we need to make one		        */
422
423  if (cif->rtype->type == FFI_TYPE_STRUCT
424      && return_type (cif->rtype) != FFI_TYPE_STRUCT)
425    ecif.rvalue = &trvalue;
426  else if ((rvalue == NULL) && 
427      (cif->rtype->type == FFI_TYPE_STRUCT))
428    {
429      ecif.rvalue = alloca(cif->rtype->size);
430    }
431  else
432    ecif.rvalue = rvalue;
433
434  switch (cif->abi) 
435    {
436    case FFI_SYSV:
437      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
438		    fn);
439      break;
440    default:
441      FFI_ASSERT(0);
442      break;
443    }
444
445  if (rvalue
446      && cif->rtype->type == FFI_TYPE_STRUCT
447      && return_type (cif->rtype) != FFI_TYPE_STRUCT)
448    memcpy (rvalue, &trvalue, cif->rtype->size);
449}
450
451extern void ffi_closure_SYSV (void);
452#if defined(__SH4__)
453extern void __ic_invalidate (void *line);
454#endif
455
456ffi_status
457ffi_prep_closure_loc (ffi_closure* closure,
458		      ffi_cif* cif,
459		      void (*fun)(ffi_cif*, void*, void**, void*),
460		      void *user_data,
461		      void *codeloc)
462{
463  unsigned int *tramp;
464  unsigned short insn;
465
466  FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
467
468  tramp = (unsigned int *) &closure->tramp[0];
469  /* Set T bit if the function returns a struct pointed with R2.  */
470  insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT
471	  ? 0x0018 /* sett */
472	  : 0x0008 /* clrt */);
473
474#ifdef __LITTLE_ENDIAN__
475  tramp[0] = 0xd301d102;
476  tramp[1] = 0x0000412b | (insn << 16);
477#else
478  tramp[0] = 0xd102d301;
479  tramp[1] = 0x412b0000 | insn;
480#endif
481  *(void **) &tramp[2] = (void *)codeloc;          /* ctx */
482  *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
483
484  closure->cif = cif;
485  closure->fun = fun;
486  closure->user_data = user_data;
487
488#if defined(__SH4__)
489  /* Flush the icache.  */
490  __ic_invalidate(codeloc);
491#endif
492
493  return FFI_OK;
494}
495
496/* Basically the trampoline invokes ffi_closure_SYSV, and on 
497 * entry, r3 holds the address of the closure.
498 * After storing the registers that could possibly contain
499 * parameters to be passed into the stack frame and setting
500 * up space for a return value, ffi_closure_SYSV invokes the 
501 * following helper function to do most of the work.
502 */
503
504#ifdef __LITTLE_ENDIAN__
505#define OFS_INT8	0
506#define OFS_INT16	0
507#else
508#define OFS_INT8	3
509#define OFS_INT16	2
510#endif
511
512int
513ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, 
514			 unsigned long *pgr, unsigned long *pfr, 
515			 unsigned long *pst)
516{
517  void **avalue;
518  ffi_type **p_arg;
519  int i, avn;
520  int ireg, greg = 0;
521#if defined(__SH4__)
522  int freg = 0;
523#endif
524  ffi_cif *cif; 
525
526  cif = closure->cif;
527  avalue = alloca(cif->nargs * sizeof(void *));
528
529  /* Copy the caller's structure return value address so that the closure
530     returns the data directly to the caller.  */
531  if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
532    {
533      rvalue = (void *) *pgr++;
534      ireg = 1;
535    }
536  else
537    ireg = 0;
538
539  cif = closure->cif;
540  greg = ireg;
541  avn = cif->nargs;
542
543  /* Grab the addresses of the arguments from the stack frame.  */
544  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
545    {
546      size_t z;
547
548      z = (*p_arg)->size;
549      if (z < sizeof(int))
550	{
551	  if (greg++ >= NGREGARG)
552	    continue;
553
554	  z = sizeof(int);
555	  switch ((*p_arg)->type)
556	    {
557	    case FFI_TYPE_SINT8:
558	    case FFI_TYPE_UINT8:
559	      avalue[i] = (((char *)pgr) + OFS_INT8);
560	      break;
561  
562	    case FFI_TYPE_SINT16:
563	    case FFI_TYPE_UINT16:
564	      avalue[i] = (((char *)pgr) + OFS_INT16);
565	      break;
566  
567	    case FFI_TYPE_STRUCT:
568	      avalue[i] = pgr;
569	      break;
570
571	    default:
572	      FFI_ASSERT(0);
573	    }
574	  pgr++;
575	}
576      else if (z == sizeof(int))
577	{
578#if defined(__SH4__)
579	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
580	    {
581	      if (freg++ >= NFREGARG)
582		continue;
583	      avalue[i] = pfr;
584	      pfr++;
585	    }
586	  else
587#endif
588	    {
589	      if (greg++ >= NGREGARG)
590		continue;
591	      avalue[i] = pgr;
592	      pgr++;
593	    }
594	}
595#if defined(__SH4__)
596      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
597	{
598	  if (freg + 1 >= NFREGARG)
599	    continue;
600	  if (freg & 1)
601	    pfr++;
602	  freg = (freg + 1) & ~1;
603	  freg += 2;
604	  avalue[i] = pfr;
605	  pfr += 2;
606	}
607#endif
608      else
609	{
610	  int n = (z + sizeof (int) - 1) / sizeof (int);
611#if defined(__SH4__)
612	  if (greg + n - 1 >= NGREGARG)
613	    continue;
614#else
615	  if (greg >= NGREGARG)
616	    continue;
617#endif
618	  greg += n;
619	  avalue[i] = pgr;
620	  pgr += n;
621	}
622    }
623
624  greg = ireg;
625#if defined(__SH4__)
626  freg = 0;
627#endif
628
629  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
630    {
631      size_t z;
632
633      z = (*p_arg)->size;
634      if (z < sizeof(int))
635	{
636	  if (greg++ < NGREGARG)
637	    continue;
638
639	  z = sizeof(int);
640	  switch ((*p_arg)->type)
641	    {
642	    case FFI_TYPE_SINT8:
643	    case FFI_TYPE_UINT8:
644	      avalue[i] = (((char *)pst) + OFS_INT8);
645	      break;
646  
647	    case FFI_TYPE_SINT16:
648	    case FFI_TYPE_UINT16:
649	      avalue[i] = (((char *)pst) + OFS_INT16);
650	      break;
651  
652	    case FFI_TYPE_STRUCT:
653	      avalue[i] = pst;
654	      break;
655
656	    default:
657	      FFI_ASSERT(0);
658	    }
659	  pst++;
660	}
661      else if (z == sizeof(int))
662	{
663#if defined(__SH4__)
664	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
665	    {
666	      if (freg++ < NFREGARG)
667		continue;
668	    }
669	  else
670#endif
671	    {
672	      if (greg++ < NGREGARG)
673		continue;
674	    }
675	  avalue[i] = pst;
676	  pst++;
677	}
678#if defined(__SH4__)
679      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
680	{
681	  if (freg + 1 < NFREGARG)
682	    {
683	      freg = (freg + 1) & ~1;
684	      freg += 2;
685	      continue;
686	    }
687	  avalue[i] = pst;
688	  pst += 2;
689	}
690#endif
691      else
692	{
693	  int n = (z + sizeof (int) - 1) / sizeof (int);
694	  if (greg + n - 1 < NGREGARG)
695	    {
696	      greg += n;
697	      continue;
698	    }
699#if (! defined(__SH4__))
700	  else if (greg < NGREGARG)
701	    {
702	      greg += n;
703	      pst += greg - NGREGARG;
704	      continue;
705	    }
706#endif
707	  avalue[i] = pst;
708	  pst += n;
709	}
710    }
711
712  (closure->fun) (cif, rvalue, avalue, closure->user_data);
713
714  /* Tell ffi_closure_SYSV how to perform return type promotions.  */
715  return return_type (cif->rtype);
716}