PageRenderTime 88ms CodeModel.GetById 20ms app.highlight 63ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://unladen-swallow.googlecode.com/
C | 610 lines | 448 code | 83 blank | 79 comment | 87 complexity | 0e696d546b342a37d9bdcb56bc332515 MD5 | raw file
  1/* -----------------------------------------------------------------------
  2   ffi.c - Copyright (c) 1996, 2003, 2004, 2007, 2008 Red Hat, Inc.
  3   
  4   SPARC 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#include <stdlib.h>
 31
 32
 33/* ffi_prep_args is called by the assembly routine once stack space
 34   has been allocated for the function's arguments */
 35
 36void ffi_prep_args_v8(char *stack, extended_cif *ecif)
 37{
 38  int i;
 39  void **p_argv;
 40  char *argp;
 41  ffi_type **p_arg;
 42
 43  /* Skip 16 words for the window save area */
 44  argp = stack + 16*sizeof(int);
 45
 46  /* This should only really be done when we are returning a structure,
 47     however, it's faster just to do it all the time...
 48
 49  if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
 50  *(int *) argp = (long)ecif->rvalue;
 51
 52  /* And 1 word for the  structure return value. */
 53  argp += sizeof(int);
 54
 55#ifdef USING_PURIFY
 56  /* Purify will probably complain in our assembly routine, unless we
 57     zero out this memory. */
 58
 59  ((int*)argp)[0] = 0;
 60  ((int*)argp)[1] = 0;
 61  ((int*)argp)[2] = 0;
 62  ((int*)argp)[3] = 0;
 63  ((int*)argp)[4] = 0;
 64  ((int*)argp)[5] = 0;
 65#endif
 66
 67  p_argv = ecif->avalue;
 68
 69  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
 70    {
 71      size_t z;
 72
 73	  if ((*p_arg)->type == FFI_TYPE_STRUCT
 74#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 75	      || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
 76#endif
 77	      )
 78	    {
 79	      *(unsigned int *) argp = (unsigned long)(* p_argv);
 80	      z = sizeof(int);
 81	    }
 82	  else
 83	    {
 84	      z = (*p_arg)->size;
 85	      if (z < sizeof(int))
 86		{
 87		  z = sizeof(int);
 88		  switch ((*p_arg)->type)
 89		    {
 90		    case FFI_TYPE_SINT8:
 91		      *(signed int *) argp = *(SINT8 *)(* p_argv);
 92		      break;
 93		      
 94		    case FFI_TYPE_UINT8:
 95		      *(unsigned int *) argp = *(UINT8 *)(* p_argv);
 96		      break;
 97		      
 98		    case FFI_TYPE_SINT16:
 99		      *(signed int *) argp = *(SINT16 *)(* p_argv);
100		      break;
101		      
102		    case FFI_TYPE_UINT16:
103		      *(unsigned int *) argp = *(UINT16 *)(* p_argv);
104		      break;
105
106		    default:
107		      FFI_ASSERT(0);
108		    }
109		}
110	      else
111		{
112		  memcpy(argp, *p_argv, z);
113		}
114	    }
115	  p_argv++;
116	  argp += z;
117    }
118  
119  return;
120}
121
122int ffi_prep_args_v9(char *stack, extended_cif *ecif)
123{
124  int i, ret = 0;
125  int tmp;
126  void **p_argv;
127  char *argp;
128  ffi_type **p_arg;
129
130  tmp = 0;
131
132  /* Skip 16 words for the window save area */
133  argp = stack + 16*sizeof(long long);
134
135#ifdef USING_PURIFY
136  /* Purify will probably complain in our assembly routine, unless we
137     zero out this memory. */
138
139  ((long long*)argp)[0] = 0;
140  ((long long*)argp)[1] = 0;
141  ((long long*)argp)[2] = 0;
142  ((long long*)argp)[3] = 0;
143  ((long long*)argp)[4] = 0;
144  ((long long*)argp)[5] = 0;
145#endif
146
147  p_argv = ecif->avalue;
148
149  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
150      ecif->cif->rtype->size > 32)
151    {
152      *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
153      argp += sizeof(long long);
154      tmp = 1;
155    }
156
157  for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
158       i++, p_arg++)
159    {
160      size_t z;
161
162      z = (*p_arg)->size;
163      switch ((*p_arg)->type)
164	{
165	case FFI_TYPE_STRUCT:
166	  if (z > 16)
167	    {
168	      /* For structures larger than 16 bytes we pass reference.  */
169	      *(unsigned long long *) argp = (unsigned long)* p_argv;
170	      argp += sizeof(long long);
171	      tmp++;
172	      p_argv++;
173	      continue;
174	    }
175	  /* FALLTHROUGH */
176	case FFI_TYPE_FLOAT:
177	case FFI_TYPE_DOUBLE:
178#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
179	case FFI_TYPE_LONGDOUBLE:
180#endif
181	  ret = 1; /* We should promote into FP regs as well as integer.  */
182	  break;
183	}
184      if (z < sizeof(long long))
185	{
186	  switch ((*p_arg)->type)
187	    {
188	    case FFI_TYPE_SINT8:
189	      *(signed long long *) argp = *(SINT8 *)(* p_argv);
190	      break;
191
192	    case FFI_TYPE_UINT8:
193	      *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
194	      break;
195
196	    case FFI_TYPE_SINT16:
197	      *(signed long long *) argp = *(SINT16 *)(* p_argv);
198	      break;
199
200	    case FFI_TYPE_UINT16:
201	      *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
202	      break;
203
204	    case FFI_TYPE_SINT32:
205	      *(signed long long *) argp = *(SINT32 *)(* p_argv);
206	      break;
207
208	    case FFI_TYPE_UINT32:
209	      *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
210	      break;
211
212	    case FFI_TYPE_FLOAT:
213	      *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
214	      break;
215
216	    case FFI_TYPE_STRUCT:
217	      memcpy(argp, *p_argv, z);
218	      break;
219
220	    default:
221	      FFI_ASSERT(0);
222	    }
223	  z = sizeof(long long);
224	  tmp++;
225	}
226      else if (z == sizeof(long long))
227	{
228	  memcpy(argp, *p_argv, z);
229	  z = sizeof(long long);
230	  tmp++;
231	}
232      else
233	{
234	  if ((tmp & 1) && (*p_arg)->alignment > 8)
235	    {
236	      tmp++;
237	      argp += sizeof(long long);
238	    }
239	  memcpy(argp, *p_argv, z);
240	  z = 2 * sizeof(long long);
241	  tmp += 2;
242	}
243      p_argv++;
244      argp += z;
245    }
246
247  return ret;
248}
249
250/* Perform machine dependent cif processing */
251ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
252{
253  int wordsize;
254
255  if (cif->abi != FFI_V9)
256    {
257      wordsize = 4;
258
259      /* If we are returning a struct, this will already have been added.
260	 Otherwise we need to add it because it's always got to be there! */
261
262      if (cif->rtype->type != FFI_TYPE_STRUCT)
263	cif->bytes += wordsize;
264
265      /* sparc call frames require that space is allocated for 6 args,
266	 even if they aren't used. Make that space if necessary. */
267  
268      if (cif->bytes < 4*6+4)
269	cif->bytes = 4*6+4;
270    }
271  else
272    {
273      wordsize = 8;
274
275      /* sparc call frames require that space is allocated for 6 args,
276	 even if they aren't used. Make that space if necessary. */
277  
278      if (cif->bytes < 8*6)
279	cif->bytes = 8*6;
280    }
281
282  /* Adjust cif->bytes. to include 16 words for the window save area,
283     and maybe the struct/union return pointer area, */
284
285  cif->bytes += 16 * wordsize;
286
287  /* The stack must be 2 word aligned, so round bytes up
288     appropriately. */
289
290  cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
291
292  /* Set the return type flag */
293  switch (cif->rtype->type)
294    {
295    case FFI_TYPE_VOID:
296    case FFI_TYPE_FLOAT:
297    case FFI_TYPE_DOUBLE:
298#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
299    case FFI_TYPE_LONGDOUBLE:
300#endif
301      cif->flags = cif->rtype->type;
302      break;
303
304    case FFI_TYPE_STRUCT:
305      if (cif->abi == FFI_V9 && cif->rtype->size > 32)
306	cif->flags = FFI_TYPE_VOID;
307      else
308	cif->flags = FFI_TYPE_STRUCT;
309      break;
310
311    case FFI_TYPE_SINT64:
312    case FFI_TYPE_UINT64:
313      if (cif->abi != FFI_V9)
314	{
315	  cif->flags = FFI_TYPE_SINT64;
316	  break;
317	}
318      /* FALLTHROUGH */
319    default:
320      cif->flags = FFI_TYPE_INT;
321      break;
322    }
323  return FFI_OK;
324}
325
326int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
327{
328  ffi_type **ptr = &arg->elements[0];
329
330  while (*ptr != NULL)
331    {
332      if (off & ((*ptr)->alignment - 1))
333	off = ALIGN(off, (*ptr)->alignment);
334
335      switch ((*ptr)->type)
336	{
337	case FFI_TYPE_STRUCT:
338	  off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
339	  off = ALIGN(off, FFI_SIZEOF_ARG);
340	  break;
341	case FFI_TYPE_FLOAT:
342	case FFI_TYPE_DOUBLE:
343#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
344	case FFI_TYPE_LONGDOUBLE:
345#endif
346	  memmove(ret + off, flt + off, (*ptr)->size);
347	  off += (*ptr)->size;
348	  break;
349	default:
350	  memmove(ret + off, intg + off, (*ptr)->size);
351	  off += (*ptr)->size;
352	  break;
353	}
354      ptr++;
355    }
356  return off;
357}
358
359
360#ifdef SPARC64
361extern int ffi_call_v9(void *, extended_cif *, unsigned, 
362		       unsigned, unsigned *, void (*fn)(void));
363#else
364extern int ffi_call_v8(void *, extended_cif *, unsigned, 
365		       unsigned, unsigned *, void (*fn)(void));
366#endif
367
368void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
369{
370  extended_cif ecif;
371  void *rval = rvalue;
372
373  ecif.cif = cif;
374  ecif.avalue = avalue;
375
376  /* If the return value is a struct and we don't have a return	*/
377  /* value address then we need to make one		        */
378
379  ecif.rvalue = rvalue;
380  if (cif->rtype->type == FFI_TYPE_STRUCT)
381    {
382      if (cif->rtype->size <= 32)
383	rval = alloca(64);
384      else
385	{
386	  rval = NULL;
387	  if (rvalue == NULL)
388	    ecif.rvalue = alloca(cif->rtype->size);
389	}
390    }
391
392  switch (cif->abi) 
393    {
394    case FFI_V8:
395#ifdef SPARC64
396      /* We don't yet support calling 32bit code from 64bit */
397      FFI_ASSERT(0);
398#else
399      ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, 
400		  cif->flags, rvalue, fn);
401#endif
402      break;
403    case FFI_V9:
404#ifdef SPARC64
405      ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
406		  cif->flags, rval, fn);
407      if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
408	ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
409#else
410      /* And vice versa */
411      FFI_ASSERT(0);
412#endif
413      break;
414    default:
415      FFI_ASSERT(0);
416      break;
417    }
418
419}
420
421
422#ifdef SPARC64
423extern void ffi_closure_v9(void);
424#else
425extern void ffi_closure_v8(void);
426#endif
427
428ffi_status
429ffi_prep_closure_loc (ffi_closure* closure,
430		      ffi_cif* cif,
431		      void (*fun)(ffi_cif*, void*, void**, void*),
432		      void *user_data,
433		      void *codeloc)
434{
435  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
436  unsigned long fn;
437#ifdef SPARC64
438  /* Trampoline address is equal to the closure address.  We take advantage
439     of that to reduce the trampoline size by 8 bytes. */
440  FFI_ASSERT (cif->abi == FFI_V9);
441  fn = (unsigned long) ffi_closure_v9;
442  tramp[0] = 0x83414000;	/* rd	%pc, %g1	*/
443  tramp[1] = 0xca586010;	/* ldx	[%g1+16], %g5	*/
444  tramp[2] = 0x81c14000;	/* jmp	%g5		*/
445  tramp[3] = 0x01000000;	/* nop			*/
446  *((unsigned long *) &tramp[4]) = fn;
447#else
448  unsigned long ctx = (unsigned long) codeloc;
449  FFI_ASSERT (cif->abi == FFI_V8);
450  fn = (unsigned long) ffi_closure_v8;
451  tramp[0] = 0x03000000 | fn >> 10;	/* sethi %hi(fn), %g1	*/
452  tramp[1] = 0x05000000 | ctx >> 10;	/* sethi %hi(ctx), %g2	*/
453  tramp[2] = 0x81c06000 | (fn & 0x3ff);	/* jmp   %g1+%lo(fn)	*/
454  tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx)	*/
455#endif
456
457  closure->cif = cif;
458  closure->fun = fun;
459  closure->user_data = user_data;
460
461  /* Flush the Icache.  FIXME: alignment isn't certain, assume 8 bytes */
462#ifdef SPARC64
463  asm volatile ("flush	%0" : : "r" (closure) : "memory");
464  asm volatile ("flush	%0" : : "r" (((char *) closure) + 8) : "memory");
465#else
466  asm volatile ("iflush	%0" : : "r" (closure) : "memory");
467  asm volatile ("iflush	%0" : : "r" (((char *) closure) + 8) : "memory");
468#endif
469
470  return FFI_OK;
471}
472
473int
474ffi_closure_sparc_inner_v8(ffi_closure *closure,
475  void *rvalue, unsigned long *gpr, unsigned long *scratch)
476{
477  ffi_cif *cif;
478  ffi_type **arg_types;
479  void **avalue;
480  int i, argn;
481
482  cif = closure->cif;
483  arg_types = cif->arg_types;
484  avalue = alloca(cif->nargs * sizeof(void *));
485
486  /* Copy the caller's structure return address so that the closure
487     returns the data directly to the caller.  */
488  if (cif->flags == FFI_TYPE_STRUCT
489#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE  
490      || cif->flags == FFI_TYPE_LONGDOUBLE
491#endif
492     )
493    rvalue = (void *) gpr[0];
494
495  /* Always skip the structure return address.  */
496  argn = 1;
497
498  /* Grab the addresses of the arguments from the stack frame.  */
499  for (i = 0; i < cif->nargs; i++)
500    {
501      if (arg_types[i]->type == FFI_TYPE_STRUCT
502#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
503	  || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
504#endif
505         )
506	{
507	  /* Straight copy of invisible reference.  */
508	  avalue[i] = (void *)gpr[argn++];
509	}
510      else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
511	       || arg_types[i]->type == FFI_TYPE_SINT64
512	       || arg_types[i]->type == FFI_TYPE_UINT64)
513	       /* gpr is 8-byte aligned.  */
514	       && (argn % 2) != 0)
515	{
516	  /* Align on a 8-byte boundary.  */
517	  scratch[0] = gpr[argn];
518	  scratch[1] = gpr[argn+1];
519	  avalue[i] = scratch;
520	  scratch -= 2;
521	  argn += 2;
522	}
523      else
524	{
525	  /* Always right-justify.  */
526	  argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
527	  avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
528	}
529    }
530
531  /* Invoke the closure.  */
532  (closure->fun) (cif, rvalue, avalue, closure->user_data);
533
534  /* Tell ffi_closure_sparc how to perform return type promotions.  */
535  return cif->rtype->type;
536}
537
538int
539ffi_closure_sparc_inner_v9(ffi_closure *closure,
540  void *rvalue, unsigned long *gpr, double *fpr)
541{
542  ffi_cif *cif;
543  ffi_type **arg_types;
544  void **avalue;
545  int i, argn, fp_slot_max;
546
547  cif = closure->cif;
548  arg_types = cif->arg_types;
549  avalue = alloca(cif->nargs * sizeof(void *));
550
551  /* Copy the caller's structure return address so that the closure
552     returns the data directly to the caller.  */
553  if (cif->flags == FFI_TYPE_VOID
554      && cif->rtype->type == FFI_TYPE_STRUCT)
555    {
556      rvalue = (void *) gpr[0];
557      /* Skip the structure return address.  */
558      argn = 1;
559    }
560  else
561    argn = 0;
562
563  fp_slot_max = 16 - argn;
564
565  /* Grab the addresses of the arguments from the stack frame.  */
566  for (i = 0; i < cif->nargs; i++)
567    {
568      if (arg_types[i]->type == FFI_TYPE_STRUCT)
569	{
570	  if (arg_types[i]->size > 16)
571	    {
572	      /* Straight copy of invisible reference.  */
573	      avalue[i] = (void *)gpr[argn++];
574	    }
575	  else
576	    {
577	      /* Left-justify.  */
578	      ffi_v9_layout_struct(arg_types[i],
579				   0,
580				   (char *) &gpr[argn],
581				   (char *) &gpr[argn],
582				   (char *) &fpr[argn]);
583	      avalue[i] = &gpr[argn];
584	      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
585	    }
586	}
587      else
588	{
589	  /* Right-justify.  */
590	  argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
591
592	  if (i < fp_slot_max
593	      && (arg_types[i]->type == FFI_TYPE_FLOAT
594		  || arg_types[i]->type == FFI_TYPE_DOUBLE
595#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
596		  || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
597#endif
598		  ))
599	    avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
600	  else
601	    avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
602	}
603    }
604
605  /* Invoke the closure.  */
606  (closure->fun) (cif, rvalue, avalue, closure->user_data);
607
608  /* Tell ffi_closure_sparc how to perform return type promotions.  */
609  return cif->rtype->type;
610}