github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libffi/src/moxie/ffi.c (about)

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (C) 2012, 2013  Anthony Green
     3     
     4     Moxie 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  /* ffi_prep_args is called by the assembly routine once stack space
    33     has been allocated for the function's arguments */
    34  
    35  void *ffi_prep_args(char *stack, extended_cif *ecif)
    36  {
    37    register unsigned int i;
    38    register void **p_argv;
    39    register char *argp;
    40    register ffi_type **p_arg;
    41    register int count = 0;
    42  
    43    p_argv = ecif->avalue;
    44    argp = stack;
    45  
    46    if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
    47      {
    48        *(void **) argp = ecif->rvalue;
    49        argp += 4;
    50      }
    51  
    52    for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
    53         (i != 0);
    54         i--, p_arg++)
    55      {
    56        size_t z;
    57        
    58        z = (*p_arg)->size;
    59  
    60        if ((*p_arg)->type == FFI_TYPE_STRUCT)
    61  	{
    62  	  z = sizeof(void*);
    63  	  *(void **) argp = *p_argv;
    64  	} 
    65        else if (z < sizeof(int))
    66  	{
    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  	      
    74  	    case FFI_TYPE_UINT8:
    75  	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
    76  	      break;
    77  	      
    78  	    case FFI_TYPE_SINT16:
    79  	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
    80  	      break;
    81  		  
    82  	    case FFI_TYPE_UINT16:
    83  	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
    84  	      break;
    85  		  
    86  	    default:
    87  	      FFI_ASSERT(0);
    88  	    }
    89  	}
    90        else if (z == sizeof(int))
    91  	{
    92  	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
    93  	}
    94        else
    95  	{
    96  	  memcpy(argp, *p_argv, z);
    97  	}
    98        p_argv++;
    99        argp += z;
   100        count += z;
   101      }
   102  
   103    return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
   104  }
   105  
   106  /* Perform machine dependent cif processing */
   107  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
   108  {
   109    if (cif->rtype->type == FFI_TYPE_STRUCT)
   110      cif->flags = -1;
   111    else
   112      cif->flags = cif->rtype->size;
   113  
   114    cif->bytes = ALIGN (cif->bytes, 8);
   115  
   116    return FFI_OK;
   117  }
   118  
   119  extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
   120  			  extended_cif *, 
   121  			  unsigned, unsigned, 
   122  			  unsigned *, 
   123  			  void (*fn)(void));
   124  
   125  void ffi_call(ffi_cif *cif, 
   126  	      void (*fn)(void), 
   127  	      void *rvalue, 
   128  	      void **avalue)
   129  {
   130    extended_cif ecif;
   131  
   132    ecif.cif = cif;
   133    ecif.avalue = avalue;
   134    
   135    /* If the return value is a struct and we don't have a return	*/
   136    /* value address then we need to make one		        */
   137  
   138    if ((rvalue == NULL) && 
   139        (cif->rtype->type == FFI_TYPE_STRUCT))
   140      {
   141        ecif.rvalue = alloca(cif->rtype->size);
   142      }
   143    else
   144      ecif.rvalue = rvalue;
   145  
   146    switch (cif->abi) 
   147      {
   148      case FFI_EABI:
   149        ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
   150  		    cif->flags, ecif.rvalue, fn);
   151        break;
   152      default:
   153        FFI_ASSERT(0);
   154        break;
   155      }
   156  }
   157  
   158  void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
   159  		       unsigned arg4, unsigned arg5, unsigned arg6)
   160  {
   161    /* This function is called by a trampoline.  The trampoline stows a
   162       pointer to the ffi_closure object in $r7.  We must save this
   163       pointer in a place that will persist while we do our work.  */
   164    register ffi_closure *creg __asm__ ("$r12");
   165    ffi_closure *closure = creg;
   166  
   167    /* Arguments that don't fit in registers are found on the stack
   168       at a fixed offset above the current frame pointer.  */
   169    register char *frame_pointer __asm__ ("$fp");
   170  
   171    /* Pointer to a struct return value.  */
   172    void *struct_rvalue = (void *) arg1;
   173  
   174    /* 6 words reserved for register args + 3 words from jsr */
   175    char *stack_args = frame_pointer + 9*4; 
   176  
   177    /* Lay the register arguments down in a continuous chunk of memory.  */
   178    unsigned register_args[6] =
   179      { arg1, arg2, arg3, arg4, arg5, arg6 };
   180    char *register_args_ptr = (char *) register_args;
   181  
   182    ffi_cif *cif = closure->cif;
   183    ffi_type **arg_types = cif->arg_types;
   184    void **avalue = alloca (cif->nargs * sizeof(void *));
   185    char *ptr = (char *) register_args;
   186    int i;
   187  
   188    /* preserve struct type return pointer passing */
   189    if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
   190      ptr += 4;
   191      register_args_ptr = (char *)&register_args[1];
   192    }
   193  
   194    /* Find the address of each argument.  */
   195    for (i = 0; i < cif->nargs; i++)
   196      {
   197        switch (arg_types[i]->type)
   198  	{
   199  	case FFI_TYPE_SINT8:
   200  	case FFI_TYPE_UINT8:
   201  	  avalue[i] = ptr + 3;
   202  	  break;
   203  	case FFI_TYPE_SINT16:
   204  	case FFI_TYPE_UINT16:
   205  	  avalue[i] = ptr + 2;
   206  	  break;
   207  	case FFI_TYPE_SINT32:
   208  	case FFI_TYPE_UINT32:
   209  	case FFI_TYPE_FLOAT:
   210  	case FFI_TYPE_POINTER:
   211  	  avalue[i] = ptr;
   212  	  break;
   213  	case FFI_TYPE_STRUCT:
   214  	  avalue[i] = *(void**)ptr;
   215  	  break;
   216  	default:
   217  	  /* This is an 8-byte value.  */
   218  	  avalue[i] = ptr;
   219  	  ptr += 4;
   220  	  break;
   221  	}
   222        ptr += 4;
   223  
   224        /* If we've handled more arguments than fit in registers,
   225  	 start looking at the those passed on the stack.  */
   226        if (ptr == &register_args[6])
   227  	ptr = stack_args;
   228      }
   229  
   230    /* Invoke the closure.  */
   231    if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
   232      {
   233        (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
   234      }
   235    else
   236      {
   237        /* Allocate space for the return value and call the function.  */
   238        long long rvalue;
   239        (closure->fun) (cif, &rvalue, avalue, closure->user_data);
   240        asm ("mov $r12, %0\n ld.l $r0, ($r12)\n ldo.l $r1, 4($r12)" : : "r" (&rvalue));
   241      }
   242  }
   243  
   244  ffi_status
   245  ffi_prep_closure_loc (ffi_closure* closure,
   246  		      ffi_cif* cif,
   247  		      void (*fun)(ffi_cif*, void*, void**, void*),
   248  		      void *user_data,
   249  		      void *codeloc)
   250  {
   251    unsigned short *tramp = (unsigned short *) &closure->tramp[0];
   252    unsigned long fn = (long) ffi_closure_eabi;
   253    unsigned long cls = (long) codeloc;
   254  
   255    if (cif->abi != FFI_EABI)
   256      return FFI_BAD_ABI;
   257  
   258    fn = (unsigned long) ffi_closure_eabi;
   259  
   260    tramp[0] = 0x01e0; /* ldi.l $r7, .... */
   261    tramp[1] = cls >> 16;
   262    tramp[2] = cls & 0xffff;
   263    tramp[3] = 0x1a00; /* jmpa .... */
   264    tramp[4] = fn >> 16;
   265    tramp[5] = fn & 0xffff;
   266  
   267    closure->cif = cif;
   268    closure->fun = fun;
   269    closure->user_data = user_data;
   270  
   271    return FFI_OK;
   272  }