ffi.c (OFS_INT16): Set 0 for little endian case.
[platform/upstream/gcc.git] / libffi / src / java_raw_api.c
1 /* -----------------------------------------------------------------------
2    java_raw_api.c - Copyright (c) 1999  Cygnus Solutions
3
4    Cloned from raw_api.c
5
6    Raw_api.c author: Kresten Krab Thorup <krab@gnu.org>
7    Java_raw_api.c author: Hans-J. Boehm <hboehm@hpl.hp.com>
8
9    $Id $
10
11    Permission is hereby granted, free of charge, to any person obtaining
12    a copy of this software and associated documentation files (the
13    ``Software''), to deal in the Software without restriction, including
14    without limitation the rights to use, copy, modify, merge, publish,
15    distribute, sublicense, and/or sell copies of the Software, and to
16    permit persons to whom the Software is furnished to do so, subject to
17    the following conditions:
18
19    The above copyright notice and this permission notice shall be included
20    in all copies or substantial portions of the Software.
21
22    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28    OTHER DEALINGS IN THE SOFTWARE.
29    ----------------------------------------------------------------------- */
30
31 /* This defines a Java- and 64-bit specific variant of the raw API.     */
32 /* It assumes that "raw" argument blocks look like Java stacks on a     */
33 /* 64-bit machine.  Arguments that can be stored in a single stack      */
34 /* stack slots (longs, doubles) occupy 128 bits, but only the first     */
35 /* 64 bits are actually used.                                           */
36
37 #include <ffi.h>
38 #include <ffi_common.h>
39
40 #if !defined(NO_JAVA_RAW_API) && !defined(FFI_NO_RAW_API)
41
42 size_t
43 ffi_java_raw_size (ffi_cif *cif)
44 {
45   size_t result = 0;
46   int i;
47
48   ffi_type **at = cif->arg_types;
49
50   for (i = cif->nargs-1; i >= 0; i--, at++)
51     {
52       switch((*at) -> type) {
53         case FFI_TYPE_UINT64:
54         case FFI_TYPE_SINT64:
55         case FFI_TYPE_DOUBLE:
56           result += 2 * SIZEOF_ARG;
57           break;
58         case FFI_TYPE_STRUCT:
59           /* No structure parameters in Java.   */
60           abort();
61         default:
62           result += SIZEOF_ARG;
63       }
64     }
65
66   return result;
67 }
68
69
70 void
71 ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
72 {
73   unsigned i;
74   ffi_type **tp = cif->arg_types;
75
76 #if WORDS_BIGENDIAN
77
78   for (i = 0; i < cif->nargs; i++, tp++, args++)
79     {     
80       switch ((*tp)->type)
81         {
82         case FFI_TYPE_UINT8:
83         case FFI_TYPE_SINT8:
84           *args = (void*) ((char*)(raw++) + 3);
85           break;
86           
87         case FFI_TYPE_UINT16:
88         case FFI_TYPE_SINT16:
89           *args = (void*) ((char*)(raw++) + 2);
90           break;
91
92 #if SIZEOF_ARG == 8       
93         case FFI_TYPE_UINT64:
94         case FFI_TYPE_SINT64:
95         case FFI_TYPE_DOUBLE:
96           *args = (void *)raw;
97           raw += 2;
98           break;
99 #endif
100
101         case FFI_TYPE_POINTER:
102           *args = (void*) &(raw++)->ptr;
103           break;
104           
105         default:
106           *args = raw;
107           raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
108         }
109     }
110
111 #else /* WORDS_BIGENDIAN */
112
113 #if !PDP
114
115   /* then assume little endian */
116   for (i = 0; i < cif->nargs; i++, tp++, args++)
117     {
118 #if SIZEOF_ARG == 8
119       switch((*tp)->type) {
120         case FFI_TYPE_UINT64:
121         case FFI_TYPE_SINT64:
122         case FFI_TYPE_DOUBLE:
123           *args = (void*) raw;
124           raw += 2;
125           break;
126         default:
127           *args = (void*) raw++;
128       }
129 #else /* SIZEOF_ARG != 8 */
130         *args = (void*) raw;
131         raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
132 #endif /* SIZEOF_ARG == 8 */
133     }
134
135 #else
136 #error "pdp endian not supported"
137 #endif /* ! PDP */
138
139 #endif /* WORDS_BIGENDIAN */
140 }
141
142 void
143 ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
144 {
145   unsigned i;
146   ffi_type **tp = cif->arg_types;
147
148   for (i = 0; i < cif->nargs; i++, tp++, args++)
149     {     
150       switch ((*tp)->type)
151         {
152         case FFI_TYPE_UINT8:
153 #if WORDS_BIGENDIAN
154           *(UINT32*)(raw++) = *(UINT8*) (*args);
155 #else
156           (raw++)->uint = *(UINT8*) (*args);
157 #endif
158           break;
159
160         case FFI_TYPE_SINT8:
161 #if WORDS_BIGENDIAN
162           *(SINT32*)(raw++) = *(SINT8*) (*args);
163 #else
164           (raw++)->sint = *(SINT8*) (*args);
165 #endif
166           break;
167
168         case FFI_TYPE_UINT16:
169 #if WORDS_BIGENDIAN
170           *(UINT32*)(raw++) = *(UINT16*) (*args);
171 #else
172           (raw++)->uint = *(UINT16*) (*args);
173 #endif
174           break;
175
176         case FFI_TYPE_SINT16:
177 #if WORDS_BIGENDIAN
178           *(SINT32*)(raw++) = *(SINT16*) (*args);
179 #else
180           (raw++)->sint = *(SINT16*) (*args);
181 #endif
182           break;
183
184         case FFI_TYPE_UINT32:
185 #if WORDS_BIGENDIAN
186           *(UINT32*)(raw++) = *(UINT32*) (*args);
187 #else
188           (raw++)->uint = *(UINT32*) (*args);
189 #endif
190           break;
191
192         case FFI_TYPE_SINT32:
193 #if WORDS_BIGENDIAN
194           *(SINT32*)(raw++) = *(SINT32*) (*args);
195 #else
196           (raw++)->sint = *(SINT32*) (*args);
197 #endif
198           break;
199
200         case FFI_TYPE_FLOAT:
201           (raw++)->flt = *(FLOAT32*) (*args);
202           break;
203
204 #if SIZEOF_ARG == 8
205         case FFI_TYPE_UINT64:
206         case FFI_TYPE_SINT64:
207         case FFI_TYPE_DOUBLE:
208           raw->uint = *(UINT64*) (*args);
209           raw += 2;
210           break;
211 #endif
212
213         case FFI_TYPE_POINTER:
214           (raw++)->ptr = **(void***) args;
215           break;
216
217         default:
218 #if SIZEOF_ARG == 8
219           FFI_ASSERT(FALSE);    /* Should have covered all cases */
220 #else   
221           memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
222           raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
223 #endif
224         }
225     }
226 }
227
228 #if !FFI_NATIVE_RAW_API
229
230 static void
231 ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue)
232 {
233 #if WORDS_BIGENDIAN && SIZEOF_ARG == 8
234   switch (cif->rtype->type)
235     {
236     case FFI_TYPE_UINT8:
237     case FFI_TYPE_UINT16:
238     case FFI_TYPE_UINT32:
239       *(UINT64 *)rvalue <<= 32;
240       break;
241
242     case FFI_TYPE_SINT8:
243     case FFI_TYPE_SINT16:
244     case FFI_TYPE_SINT32:
245     case FFI_TYPE_INT:
246       *(SINT64 *)rvalue <<= 32;
247       break;
248
249     default:
250       break;
251     }
252 #endif
253 }
254
255 static void
256 ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue)
257 {
258 #if WORDS_BIGENDIAN && SIZEOF_ARG == 8
259   switch (cif->rtype->type)
260     {
261     case FFI_TYPE_UINT8:
262     case FFI_TYPE_UINT16:
263     case FFI_TYPE_UINT32:
264       *(UINT64 *)rvalue >>= 32;
265       break;
266
267     case FFI_TYPE_SINT8:
268     case FFI_TYPE_SINT16:
269     case FFI_TYPE_SINT32:
270     case FFI_TYPE_INT:
271       *(SINT64 *)rvalue >>= 32;
272       break;
273
274     default:
275       break;
276     }
277 #endif
278 }
279
280 /* This is a generic definition of ffi_raw_call, to be used if the
281  * native system does not provide a machine-specific implementation.
282  * Having this, allows code to be written for the raw API, without
283  * the need for system-specific code to handle input in that format;
284  * these following couple of functions will handle the translation forth
285  * and back automatically. */
286
287 void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, 
288                    void (*fn)(), 
289                    /*@out@*/ void *rvalue, 
290                    /*@dependent@*/ ffi_raw *raw)
291 {
292   void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
293   ffi_java_raw_to_ptrarray (cif, raw, avalue);
294   ffi_call (cif, fn, rvalue, avalue);
295   ffi_java_rvalue_to_raw (cif, rvalue);
296 }
297
298 #if FFI_CLOSURES                /* base system provides closures */
299
300 static void 
301 ffi_java_translate_args (ffi_cif *cif, void *rvalue,
302                     void **avalue, void *user_data)
303 {
304   ffi_raw *raw = (ffi_raw*)alloca (ffi_java_raw_size (cif));
305   ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
306
307   ffi_java_ptrarray_to_raw (cif, avalue, raw);
308   (*cl->fun) (cif, rvalue, raw, cl->user_data);
309   ffi_java_raw_to_rvalue (cif, rvalue);
310 }
311
312 /* Again, here is the generic version of ffi_prep_raw_closure, which
313  * will install an intermediate "hub" for translation of arguments from
314  * the pointer-array format, to the raw format */
315
316 ffi_status
317 ffi_prep_java_raw_closure (ffi_raw_closure* cl,
318                       ffi_cif *cif,
319                       void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
320                       void *user_data)
321 {
322   ffi_status status;
323
324   status = ffi_prep_closure ((ffi_closure*) cl, 
325                              cif,
326                              &ffi_java_translate_args,
327                              (void*)cl);
328   if (status == FFI_OK)
329     {
330       cl->fun       = fun;
331       cl->user_data = user_data;
332     }
333
334   return status;
335 }
336
337 #endif /* FFI_CLOSURES */
338 #endif /* !FFI_NATIVE_RAW_API */
339 #endif /* !FFI_NO_RAW_API */