1 /* -----------------------------------------------------------------------
2    java_raw_api.c - Copyright (c) 1999, 2007, 2008  Red Hat, Inc.
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,
23    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29    DEALINGS IN THE SOFTWARE.
30    ----------------------------------------------------------------------- */
31 
32 /* This defines a Java- and 64-bit specific variant of the raw API.	*/
33 /* It assumes that "raw" argument blocks look like Java stacks on a	*/
34 /* 64-bit machine.  Arguments that can be stored in a single stack	*/
35 /* stack slots (longs, doubles) occupy 128 bits, but only the first	*/
36 /* 64 bits are actually used.						*/
37 
38 #include <ffi.h>
39 #include <ffi_common.h>
40 #include <stdlib.h>
41 
42 #if !defined(NO_JAVA_RAW_API) && !defined(FFI_NO_RAW_API)
43 
44 size_t
ffi_java_raw_size(ffi_cif * cif)45 ffi_java_raw_size (ffi_cif *cif)
46 {
47   size_t result = 0;
48   int i;
49 
50   ffi_type **at = cif->arg_types;
51 
52   for (i = cif->nargs-1; i >= 0; i--, at++)
53     {
54       switch((*at) -> type) {
55 	case FFI_TYPE_UINT64:
56 	case FFI_TYPE_SINT64:
57 	case FFI_TYPE_DOUBLE:
58 	  result += 2 * FFI_SIZEOF_JAVA_RAW;
59 	  break;
60 	case FFI_TYPE_STRUCT:
61 	  /* No structure parameters in Java.	*/
62 	  abort();
63 	default:
64 	  result += FFI_SIZEOF_JAVA_RAW;
65       }
66     }
67 
68   return result;
69 }
70 
71 
72 void
ffi_java_raw_to_ptrarray(ffi_cif * cif,ffi_java_raw * raw,void ** args)73 ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args)
74 {
75   unsigned i;
76   ffi_type **tp = cif->arg_types;
77 
78 #if WORDS_BIGENDIAN
79 
80   for (i = 0; i < cif->nargs; i++, tp++, args++)
81     {
82       switch ((*tp)->type)
83 	{
84 	case FFI_TYPE_UINT8:
85 	case FFI_TYPE_SINT8:
86 	  *args = (void*) ((char*)(raw++) + 3);
87 	  break;
88 
89 	case FFI_TYPE_UINT16:
90 	case FFI_TYPE_SINT16:
91 	  *args = (void*) ((char*)(raw++) + 2);
92 	  break;
93 
94 #if FFI_SIZEOF_JAVA_RAW == 8
95 	case FFI_TYPE_UINT64:
96 	case FFI_TYPE_SINT64:
97 	case FFI_TYPE_DOUBLE:
98 	  *args = (void *)raw;
99 	  raw += 2;
100 	  break;
101 #endif
102 
103 	case FFI_TYPE_POINTER:
104 	  *args = (void*) &(raw++)->ptr;
105 	  break;
106 
107 	default:
108 	  *args = raw;
109 	  raw +=
110 	    ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
111 	}
112     }
113 
114 #else /* WORDS_BIGENDIAN */
115 
116 #if !PDP
117 
118   /* then assume little endian */
119   for (i = 0; i < cif->nargs; i++, tp++, args++)
120     {
121 #if FFI_SIZEOF_JAVA_RAW == 8
122       switch((*tp)->type) {
123 	case FFI_TYPE_UINT64:
124 	case FFI_TYPE_SINT64:
125 	case FFI_TYPE_DOUBLE:
126 	  *args = (void*) raw;
127 	  raw += 2;
128 	  break;
129 	default:
130 	  *args = (void*) raw++;
131       }
132 #else /* FFI_SIZEOF_JAVA_RAW != 8 */
133 	*args = (void*) raw;
134 	raw +=
135 	  ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
136 #endif /* FFI_SIZEOF_JAVA_RAW == 8 */
137     }
138 
139 #else
140 #error "pdp endian not supported"
141 #endif /* ! PDP */
142 
143 #endif /* WORDS_BIGENDIAN */
144 }
145 
146 void
ffi_java_ptrarray_to_raw(ffi_cif * cif,void ** args,ffi_java_raw * raw)147 ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw)
148 {
149   unsigned i;
150   ffi_type **tp = cif->arg_types;
151 
152   for (i = 0; i < cif->nargs; i++, tp++, args++)
153     {
154       switch ((*tp)->type)
155 	{
156 	case FFI_TYPE_UINT8:
157 #if WORDS_BIGENDIAN
158 	  *(UINT32*)(raw++) = *(UINT8*) (*args);
159 #else
160 	  (raw++)->uint = *(UINT8*) (*args);
161 #endif
162 	  break;
163 
164 	case FFI_TYPE_SINT8:
165 #if WORDS_BIGENDIAN
166 	  *(SINT32*)(raw++) = *(SINT8*) (*args);
167 #else
168 	  (raw++)->sint = *(SINT8*) (*args);
169 #endif
170 	  break;
171 
172 	case FFI_TYPE_UINT16:
173 #if WORDS_BIGENDIAN
174 	  *(UINT32*)(raw++) = *(UINT16*) (*args);
175 #else
176 	  (raw++)->uint = *(UINT16*) (*args);
177 #endif
178 	  break;
179 
180 	case FFI_TYPE_SINT16:
181 #if WORDS_BIGENDIAN
182 	  *(SINT32*)(raw++) = *(SINT16*) (*args);
183 #else
184 	  (raw++)->sint = *(SINT16*) (*args);
185 #endif
186 	  break;
187 
188 	case FFI_TYPE_UINT32:
189 #if WORDS_BIGENDIAN
190 	  *(UINT32*)(raw++) = *(UINT32*) (*args);
191 #else
192 	  (raw++)->uint = *(UINT32*) (*args);
193 #endif
194 	  break;
195 
196 	case FFI_TYPE_SINT32:
197 #if WORDS_BIGENDIAN
198 	  *(SINT32*)(raw++) = *(SINT32*) (*args);
199 #else
200 	  (raw++)->sint = *(SINT32*) (*args);
201 #endif
202 	  break;
203 
204 	case FFI_TYPE_FLOAT:
205 	  (raw++)->flt = *(FLOAT32*) (*args);
206 	  break;
207 
208 #if FFI_SIZEOF_JAVA_RAW == 8
209 	case FFI_TYPE_UINT64:
210 	case FFI_TYPE_SINT64:
211 	case FFI_TYPE_DOUBLE:
212 	  raw->uint = *(UINT64*) (*args);
213 	  raw += 2;
214 	  break;
215 #endif
216 
217 	case FFI_TYPE_POINTER:
218 	  (raw++)->ptr = **(void***) args;
219 	  break;
220 
221 	default:
222 #if FFI_SIZEOF_JAVA_RAW == 8
223 	  FFI_ASSERT(0);	/* Should have covered all cases */
224 #else
225 	  memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
226 	  raw +=
227 	    ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
228 #endif
229 	}
230     }
231 }
232 
233 #if !FFI_NATIVE_RAW_API
234 
235 static void
ffi_java_rvalue_to_raw(ffi_cif * cif,void * rvalue)236 ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue)
237 {
238 #if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8
239   switch (cif->rtype->type)
240     {
241     case FFI_TYPE_UINT8:
242     case FFI_TYPE_UINT16:
243     case FFI_TYPE_UINT32:
244       *(UINT64 *)rvalue <<= 32;
245       break;
246 
247     case FFI_TYPE_SINT8:
248     case FFI_TYPE_SINT16:
249     case FFI_TYPE_SINT32:
250     case FFI_TYPE_INT:
251 #if FFI_SIZEOF_JAVA_RAW == 4
252     case FFI_TYPE_POINTER:
253 #endif
254       *(SINT64 *)rvalue <<= 32;
255       break;
256 
257     default:
258       break;
259     }
260 #endif
261 }
262 
263 static void
ffi_java_raw_to_rvalue(ffi_cif * cif,void * rvalue)264 ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue)
265 {
266 #if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8
267   switch (cif->rtype->type)
268     {
269     case FFI_TYPE_UINT8:
270     case FFI_TYPE_UINT16:
271     case FFI_TYPE_UINT32:
272       *(UINT64 *)rvalue >>= 32;
273       break;
274 
275     case FFI_TYPE_SINT8:
276     case FFI_TYPE_SINT16:
277     case FFI_TYPE_SINT32:
278     case FFI_TYPE_INT:
279       *(SINT64 *)rvalue >>= 32;
280       break;
281 
282     default:
283       break;
284     }
285 #endif
286 }
287 
288 /* This is a generic definition of ffi_raw_call, to be used if the
289  * native system does not provide a machine-specific implementation.
290  * Having this, allows code to be written for the raw API, without
291  * the need for system-specific code to handle input in that format;
292  * these following couple of functions will handle the translation forth
293  * and back automatically. */
294 
ffi_java_raw_call(ffi_cif * cif,void (* fn)(void),void * rvalue,ffi_java_raw * raw)295 void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue,
296 			ffi_java_raw *raw)
297 {
298   void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
299   ffi_java_raw_to_ptrarray (cif, raw, avalue);
300   ffi_call (cif, fn, rvalue, avalue);
301   ffi_java_rvalue_to_raw (cif, rvalue);
302 }
303 
304 #if FFI_CLOSURES		/* base system provides closures */
305 
306 static void
ffi_java_translate_args(ffi_cif * cif,void * rvalue,void ** avalue,void * user_data)307 ffi_java_translate_args (ffi_cif *cif, void *rvalue,
308 		    void **avalue, void *user_data)
309 {
310   ffi_java_raw *raw = (ffi_java_raw*)alloca (ffi_java_raw_size (cif));
311   ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
312 
313   ffi_java_ptrarray_to_raw (cif, avalue, raw);
314   (*cl->fun) (cif, rvalue, (ffi_raw*)raw, cl->user_data);
315   ffi_java_raw_to_rvalue (cif, rvalue);
316 }
317 
318 ffi_status
ffi_prep_java_raw_closure_loc(ffi_java_raw_closure * cl,ffi_cif * cif,void (* fun)(ffi_cif *,void *,ffi_java_raw *,void *),void * user_data,void * codeloc)319 ffi_prep_java_raw_closure_loc (ffi_java_raw_closure* cl,
320 			       ffi_cif *cif,
321 			       void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
322 			       void *user_data,
323 			       void *codeloc)
324 {
325   ffi_status status;
326 
327   status = ffi_prep_closure_loc ((ffi_closure*) cl,
328 				 cif,
329 				 &ffi_java_translate_args,
330 				 codeloc,
331 				 codeloc);
332   if (status == FFI_OK)
333     {
334       cl->fun       = fun;
335       cl->user_data = user_data;
336     }
337 
338   return status;
339 }
340 
341 /* Again, here is the generic version of ffi_prep_raw_closure, which
342  * will install an intermediate "hub" for translation of arguments from
343  * the pointer-array format, to the raw format */
344 
345 ffi_status
ffi_prep_java_raw_closure(ffi_java_raw_closure * cl,ffi_cif * cif,void (* fun)(ffi_cif *,void *,ffi_java_raw *,void *),void * user_data)346 ffi_prep_java_raw_closure (ffi_java_raw_closure* cl,
347 			   ffi_cif *cif,
348 			   void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
349 			   void *user_data)
350 {
351   return ffi_prep_java_raw_closure_loc (cl, cif, fun, user_data, cl);
352 }
353 
354 #endif /* FFI_CLOSURES */
355 #endif /* !FFI_NATIVE_RAW_API */
356 #endif /* !FFI_NO_RAW_API */
357