~ubuntu-branches/ubuntu/lucid/gauche-c-wrapper/lucid

« back to all changes in this revision

Viewing changes to libffi/src/frv/ffi.c

  • Committer: Bazaar Package Importer
  • Author(s): NIIBE Yutaka
  • Date: 2008-04-07 09:15:03 UTC
  • Revision ID: james.westby@ubuntu.com-20080407091503-wu0h414koe95kj4i
Tags: upstream-0.5.2
ImportĀ upstreamĀ versionĀ 0.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -----------------------------------------------------------------------
 
2
   ffi.c - Copyright (c) 2004  Anthony Green
 
3
   
 
4
   FR-V 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, EXPRESS
 
18
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
19
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
20
   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
21
   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
22
   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
23
   OTHER DEALINGS IN THE SOFTWARE.
 
24
   ----------------------------------------------------------------------- */
 
25
 
 
26
#include <ffi.h>
 
27
#include <ffi_common.h>
 
28
 
 
29
#include <stdlib.h>
 
30
 
 
31
/* ffi_prep_args is called by the assembly routine once stack space
 
32
   has been allocated for the function's arguments */
 
33
 
 
34
void *ffi_prep_args(char *stack, extended_cif *ecif)
 
35
{
 
36
  register unsigned int i;
 
37
  register void **p_argv;
 
38
  register char *argp;
 
39
  register ffi_type **p_arg;
 
40
  register int count = 0;
 
41
 
 
42
  p_argv = ecif->avalue;
 
43
  argp = stack;
 
44
 
 
45
  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
 
46
       (i != 0);
 
47
       i--, p_arg++)
 
48
    {
 
49
      size_t z;
 
50
      
 
51
      z = (*p_arg)->size;
 
52
 
 
53
      if ((*p_arg)->type == FFI_TYPE_STRUCT)
 
54
        {
 
55
          z = sizeof(void*);
 
56
          *(void **) argp = *p_argv;
 
57
        } 
 
58
      /*      if ((*p_arg)->type == FFI_TYPE_FLOAT)
 
59
        {
 
60
          if (count > 24)
 
61
            {
 
62
              // This is going on the stack.  Turn it into a double.  
 
63
              *(double *) argp = (double) *(float*)(* p_argv);
 
64
              z = sizeof(double);
 
65
            }
 
66
          else
 
67
            *(void **) argp = *(void **)(* p_argv);
 
68
        }  */
 
69
      else if (z < sizeof(int))
 
70
        {
 
71
          z = sizeof(int);
 
72
          switch ((*p_arg)->type)
 
73
            {
 
74
            case FFI_TYPE_SINT8:
 
75
              *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
 
76
              break;
 
77
              
 
78
            case FFI_TYPE_UINT8:
 
79
              *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
 
80
              break;
 
81
              
 
82
            case FFI_TYPE_SINT16:
 
83
              *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
 
84
              break;
 
85
                  
 
86
            case FFI_TYPE_UINT16:
 
87
              *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
 
88
              break;
 
89
                  
 
90
            default:
 
91
              FFI_ASSERT(0);
 
92
            }
 
93
        }
 
94
      else if (z == sizeof(int))
 
95
        {
 
96
          *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
 
97
        }
 
98
      else
 
99
        {
 
100
          memcpy(argp, *p_argv, z);
 
101
        }
 
102
      p_argv++;
 
103
      argp += z;
 
104
      count += z;
 
105
    }
 
106
 
 
107
  return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
 
108
}
 
109
 
 
110
/* Perform machine dependent cif processing */
 
111
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
 
112
{
 
113
  if (cif->rtype->type == FFI_TYPE_STRUCT)
 
114
    cif->flags = -1;
 
115
  else
 
116
    cif->flags = cif->rtype->size;
 
117
 
 
118
  cif->bytes = ALIGN (cif->bytes, 8);
 
119
 
 
120
  return FFI_OK;
 
121
}
 
122
 
 
123
extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
 
124
                          extended_cif *, 
 
125
                          unsigned, unsigned, 
 
126
                          unsigned *, 
 
127
                          void (*fn)());
 
128
 
 
129
void ffi_call(ffi_cif *cif, 
 
130
              void (*fn)(), 
 
131
              void *rvalue, 
 
132
              void **avalue)
 
133
{
 
134
  extended_cif ecif;
 
135
 
 
136
  ecif.cif = cif;
 
137
  ecif.avalue = avalue;
 
138
  
 
139
  /* If the return value is a struct and we don't have a return */
 
140
  /* value address then we need to make one                     */
 
141
 
 
142
  if ((rvalue == NULL) && 
 
143
      (cif->rtype->type == FFI_TYPE_STRUCT))
 
144
    {
 
145
      ecif.rvalue = alloca(cif->rtype->size);
 
146
    }
 
147
  else
 
148
    ecif.rvalue = rvalue;
 
149
    
 
150
  
 
151
  switch (cif->abi) 
 
152
    {
 
153
    case FFI_EABI:
 
154
      ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
 
155
                    cif->flags, ecif.rvalue, fn);
 
156
      break;
 
157
    default:
 
158
      FFI_ASSERT(0);
 
159
      break;
 
160
    }
 
161
}
 
162
 
 
163
void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
 
164
                       unsigned arg4, unsigned arg5, unsigned arg6)
 
165
{
 
166
  /* This function is called by a trampoline.  The trampoline stows a
 
167
     pointer to the ffi_closure object in gr7.  We must save this
 
168
     pointer in a place that will persist while we do our work.  */
 
169
  register ffi_closure *creg __asm__ ("gr7");
 
170
  ffi_closure *closure = creg;
 
171
 
 
172
  /* Arguments that don't fit in registers are found on the stack
 
173
     at a fixed offset above the current frame pointer.  */
 
174
  register char *frame_pointer __asm__ ("fp");
 
175
  char *stack_args = frame_pointer + 16;
 
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
 
 
181
  ffi_cif *cif = closure->cif;
 
182
  ffi_type **arg_types = cif->arg_types;
 
183
  void **avalue = alloca (cif->nargs * sizeof(void *));
 
184
  char *ptr = (char *) register_args;
 
185
  int i;
 
186
 
 
187
  /* Find the address of each argument.  */
 
188
  for (i = 0; i < cif->nargs; i++)
 
189
    {
 
190
      switch (arg_types[i]->type)
 
191
        {
 
192
        case FFI_TYPE_SINT8:
 
193
        case FFI_TYPE_UINT8:
 
194
          avalue[i] = ptr + 3;
 
195
          break;
 
196
        case FFI_TYPE_SINT16:
 
197
        case FFI_TYPE_UINT16:
 
198
          avalue[i] = ptr + 2;
 
199
          break;
 
200
        case FFI_TYPE_SINT32:
 
201
        case FFI_TYPE_UINT32:
 
202
        case FFI_TYPE_FLOAT:
 
203
          avalue[i] = ptr;
 
204
          break;
 
205
        case FFI_TYPE_STRUCT:
 
206
          avalue[i] = *(void**)ptr;
 
207
          break;
 
208
        default:
 
209
          /* This is an 8-byte value.  */
 
210
          avalue[i] = ptr;
 
211
          ptr += 4;
 
212
          break;
 
213
        }
 
214
      ptr += 4;
 
215
 
 
216
      /* If we've handled more arguments than fit in registers,
 
217
         start looking at the those passed on the stack.  */
 
218
      if (ptr == ((char *)register_args + (6*4)))
 
219
        ptr = stack_args;
 
220
    }
 
221
 
 
222
  /* Invoke the closure.  */
 
223
  if (cif->rtype->type == FFI_TYPE_STRUCT)
 
224
    {
 
225
      /* The caller allocates space for the return structure, and
 
226
       passes a pointer to this space in gr3.  Use this value directly
 
227
       as the return value.  */
 
228
      register void *return_struct_ptr __asm__("gr3");
 
229
      (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data);
 
230
    }
 
231
  else
 
232
    {
 
233
      /* Allocate space for the return value and call the function.  */
 
234
      long long rvalue;
 
235
      (closure->fun) (cif, &rvalue, avalue, closure->user_data);
 
236
 
 
237
      /* Functions return 4-byte or smaller results in gr8.  8-byte
 
238
         values also use gr9.  We fill the both, even for small return
 
239
         values, just to avoid a branch.  */ 
 
240
      asm ("ldi  @(%0, #0), gr8" : : "r" (&rvalue));
 
241
      asm ("ldi  @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1]));
 
242
    }
 
243
}
 
244
 
 
245
ffi_status
 
246
ffi_prep_closure (ffi_closure* closure,
 
247
                  ffi_cif* cif,
 
248
                  void (*fun)(ffi_cif*, void*, void**, void*),
 
249
                  void *user_data)
 
250
{
 
251
  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
 
252
  unsigned long fn = (long) ffi_closure_eabi;
 
253
  unsigned long cls = (long) closure;
 
254
#ifdef __FRV_FDPIC__
 
255
  register void *got __asm__("gr15");
 
256
#endif
 
257
  int i;
 
258
 
 
259
  fn = (unsigned long) ffi_closure_eabi;
 
260
 
 
261
#ifdef __FRV_FDPIC__
 
262
  tramp[0] = &tramp[2];
 
263
  tramp[1] = got;
 
264
  tramp[2] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
 
265
  tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
 
266
  tramp[4] = 0x8cf80000 + (fn  >> 16);    /* sethi hi(fn), gr6     */
 
267
  tramp[5] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
 
268
  tramp[6] = 0x9cc86000;                  /* ldi @(gr6, #0), gr14  */
 
269
  tramp[7] = 0x8030e000;                  /* jmpl @(gr14, gr0)     */
 
270
#else
 
271
  tramp[0] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
 
272
  tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
 
273
  tramp[2] = 0x8cf80000 + (fn  >> 16);    /* sethi hi(fn), gr6     */
 
274
  tramp[3] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
 
275
  tramp[4] = 0x80300006;                  /* jmpl @(gr0, gr6)      */
 
276
#endif
 
277
 
 
278
  closure->cif = cif;
 
279
  closure->fun = fun;
 
280
  closure->user_data = user_data;
 
281
 
 
282
  /* Cache flushing.  */
 
283
  for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
 
284
    __asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (tramp), "r" (i));
 
285
 
 
286
  return FFI_OK;
 
287
}