1 /* ppc-darwin.c -- FFI support for PowerPC on Mach-O (Darwin)
2  *
3  * Author: Ian.Piumarta@INRIA.Fr
4  *
5  * Last edited: 2009-08-19 04:23:48 by piumarta on emilia-2.local
6  *
7  *   Copyright (C) 1996-2004 by Ian Piumarta and other authors/contributors
8  *                              listed elsewhere in this file.
9  *   All rights reserved.
10  *
11  *   This file is part of Unix Squeak.
12  *
13  *   Permission is hereby granted, free of charge, to any person obtaining a copy
14  *   of this software and associated documentation files (the "Software"), to deal
15  *   in the Software without restriction, including without limitation the rights
16  *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  *   copies of the Software, and to permit persons to whom the Software is
18  *   furnished to do so, subject to the following conditions:
19  *
20  *   The above copyright notice and this permission notice shall be included in
21  *   all copies or substantial portions of the Software.
22  *
23  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26  *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  *   LIABILITY, 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 DEALINGS IN THE
29  *   SOFTWARE.
30  *
31  * Notes:
32  *
33  *  This is a complete rewrite of the version for MacPPC.  (The latter
34  *  is hopelessly broken when passing long longs or structs containing
35  *  an element of alignment less strict than int.)
36  *
37  * Bugs:
38  *
39  *   Because of the way strings are handled, this implementation is
40  *   neither reentrant nor thread safe.
41  *
42  * References:
43  *
44  *   Mach-O Runtime Architecture, Apple Computer Inc., July 2002.
45  */
46 
47 #include "sq.h"
48 #include "sqFFI.h"
49 
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 
54 #ifndef LONGLONG
55 # define LONGLONG long long
56 #endif
57 
58 #if 0
59 # define debugf(ARGS)	printf ARGS; fflush(stdout)
60 #else
61 # define debugf(ARGS)
62 #endif
63 
64 extern struct VirtualMachine *interpreterProxy;
65 
66 #if defined(FFI_TEST)
primitiveFail(void)67   static int primitiveFail(void) { puts("primitive fail"); exit(1); return 0; }
68 #else
69 # define primitiveFail() interpreterProxy->primitiveFail();
70 #endif
71 
72 #define GPR_MAX	   8
73 #define FPR_MAX	  13
74 #define ARG_MAX	 512
75 
76 static char	*strings[ARG_MAX];
77 static int	 stringCount= 0;
78 
79 #if 0
80 static char	 structs[ARG_MAX * sizeof(int)];
81 static int	 structCount= 0;
82 #endif
83 
84 /* the following avoids an awful lot of _very_ inefficient junk in the asm */
85 
86 static struct
87 {
88   int	   _gprCount;		//  0
89   int	   _fprCount;		//  4
90   int	   _stackIndex;		//  8
91   int	  *_structReturnValue;	// 12	(everything below is 8-byte aligned)
92   LONGLONG _longReturnValue;	// 16
93   double   _floatReturnValue;	// 24
94   int	   _gprs[GPR_MAX];	// 32
95   double   _fprs[FPR_MAX];	// 32 + 4*GPR_MAX
96   int	   _stack[ARG_MAX];	// 32 + 4*GPR_MAX + 8*FPR_MAX
97 } global;
98 
99 #define gprCount		global._gprCount
100 #define fprCount		global._fprCount
101 #define stackIndex		global._stackIndex
102 #define structReturnValue	global._structReturnValue
103 #define longReturnValue		global._longReturnValue
104 #define floatReturnValue	global._floatReturnValue
105 #define gprs			global._gprs
106 #define fprs			global._fprs
107 #define stack			global._stack
108 
109 
110 extern int ffiCallAddressOf(void *addr, void *globals);
111 
112 
ffiInitialize(void)113 int ffiInitialize(void)
114 {
115   debugf(("ffiInitialize\n"));
116   stackIndex= gprCount= fprCount= 0;
117 #if 0
118   structCount= 0;
119 #endif
120   floatReturnValue= 0.0;
121   return 1;
122 }
123 
124 
ffiSupportsCallingConvention(int callType)125 int ffiSupportsCallingConvention(int callType)
126 {
127   return (callType == FFICallTypeCDecl)
128     ||   (callType == FFICallTypeApi);
129 }
130 
131 
ffiAlloc(int byteSize)132 int ffiAlloc(int byteSize)
133 {
134   int ptr= (int)malloc(byteSize);
135   debugf(("ffiAlloc(%d) => %08x\n", byteSize, ptr));
136   return ptr;
137 }
138 
139 
ffiFree(int ptr)140 int ffiFree(int ptr)
141 {
142   debugf(("ffiFree(%08x)\n", ptr));
143   if (ptr) free((void *)ptr);
144   return 1;
145 }
146 
147 
148 #define checkStack()				\
149   if (stackIndex >= ARG_MAX)			\
150     return primitiveFail()
151 
152 #define checkGPR()					\
153   if ((gprCount >= GPR_MAX) && (stackIndex >= ARG_MAX))	\
154     return primitiveFail()
155 
156 #define qalignStack()	stackIndex += (stackIndex & 1)
157 
158 #define pushGPR(value)				\
159   checkGPR();					\
160   if (gprCount < GPR_MAX)			\
161     gprs[gprCount++]= value;			\
162   stack[stackIndex++]= value
163 
164 #define qalignGPR()	gprCount += (gprCount & 1)
165 
166 
ffiPushSignedChar(int value)167 int ffiPushSignedChar(int value)
168 {
169   debugf(("ffiPushSignedChar %d\n", value));
170   pushGPR(value);
171   return 1;
172 }
173 
174 
ffiPushUnsignedChar(int value)175 int ffiPushUnsignedChar(int value)
176 {
177   debugf(("ffiPushUnsignedChar %d\n", value));
178   pushGPR(value);
179   return 1;
180 }
181 
182 
ffiPushSignedByte(int value)183 int ffiPushSignedByte(int value)
184 {
185   debugf(("ffiPushSignedByte %d\n", value));
186   pushGPR(value);
187   return 1;
188 }
189 
190 
ffiPushUnsignedByte(int value)191 int ffiPushUnsignedByte(int value)
192 {
193   debugf(("ffiPushUnsignedByte %d\n", value));
194   pushGPR(value);
195   return 1;
196 }
197 
198 
ffiPushSignedShort(int value)199 int ffiPushSignedShort(int value)
200 {
201   debugf(("ffiPushSignedShort %d\n", value));
202   pushGPR(value);
203   return 1;
204 }
205 
206 
ffiPushUnsignedShort(int value)207 int ffiPushUnsignedShort(int value)
208 {
209   debugf(("ffiPushUnsignedShort %d\n", value));
210   pushGPR(value);
211   return 1;
212 }
213 
214 
ffiPushSignedInt(int value)215 int ffiPushSignedInt(int value)
216 {
217   debugf(("ffiPushSignedInt %d\n", value));
218   pushGPR(value);
219   return 1;
220 }
221 
222 
ffiPushUnsignedInt(int value)223 int ffiPushUnsignedInt(int value)
224 {
225   debugf(("ffiPushUnsignedInt %d\n", value));
226   pushGPR(value);
227   return 1;
228 }
229 
230 
ffiPushSignedLongLong(int low,int high)231 int ffiPushSignedLongLong(int low, int high)
232 {
233   debugf(("ffiPushSignedLongLong %d %d\n", low, high));
234   qalignGPR();
235   qalignStack();
236   pushGPR(high);
237   pushGPR(low);
238   return 1;
239 }
240 
241 
ffiPushUnsignedLongLong(int low,int high)242 int ffiPushUnsignedLongLong(int low, int high)
243 {
244   debugf(("ffiPushUnsignedLongLong %d %d\n", low, high));
245   qalignGPR();
246   qalignStack();
247   pushGPR(high);
248   pushGPR(low);
249   return 1;
250 }
251 
252 
ffiPushPointer(int pointer)253 int ffiPushPointer(int pointer)
254 {
255   debugf(("ffiPushPointer %08x\n", pointer));
256   pushGPR(pointer);
257   return 1;
258 }
259 
260 
ffiPushSingleFloat(double value)261 int ffiPushSingleFloat(double value)
262 {
263   debugf(("ffiPushSingleFloat %f\n", (float)value));
264   if (fprCount < FPR_MAX)
265     fprs[fprCount++]= value;
266   {
267     float floatValue= (float)value;
268     pushGPR(*(int *)&floatValue);
269   }
270   return 1;
271 }
272 
273 
ffiPushDoubleFloat(double value)274 int ffiPushDoubleFloat(double value)
275 {
276   debugf(("ffiPushDoubleFloat %f\n", (float)value));
277   if (fprCount < FPR_MAX)
278     fprs[fprCount++]= value;
279   pushGPR(((int *)&value)[0]);
280   pushGPR(((int *)&value)[1]);
281   return 1;
282 }
283 
284 
ffiPushStringOfLength(int srcIndex,int length)285 int ffiPushStringOfLength(int srcIndex, int length)
286 {
287   char *ptr;
288   debugf(("ffiPushStringOfLength %d\n", length));
289   checkGPR();
290   ptr= (char *)malloc(length + 1);
291   if (!ptr)
292     return primitiveFail();
293   memcpy(ptr, (void *)srcIndex, length);
294   ptr[length]= '\0';
295   strings[stringCount++]= ptr;
296   pushGPR((int)ptr);
297   return 1;
298 }
299 
300 
min(int x,int y)301 static inline int min(int x, int y) { return (x < y) ? x : y; }
302 
303 
ffiPushStructureOfLength(int pointer,int * structSpec,int specSize)304 int ffiPushStructureOfLength(int pointer, int *structSpec, int specSize)
305 {
306   int i;
307   char *data	= (char *)pointer;
308   char *argp	= (char *)&stack[stackIndex];
309 #define argl	  (char *)&stack[ARG_MAX]
310   int   argSize	= *structSpec & FFIStructSizeMask;
311   char *gprp	= (char *)&gprs[gprCount];
312 #define gprl	  (char *)&gprs[GPR_MAX]
313   int   gprSize	= min(argSize, gprl - gprp);
314 
315   debugf(("ffiPush %08x Structure %p OfLength %d\n", pointer, structSpec, specSize));
316 
317   if (gprSize < 4) gprp += (4 - gprSize);
318   if (argSize < 4) argp += (4 - gprSize);
319   if (argp + argSize > argl)
320     return primitiveFail();
321 
322   memcpy((void *)gprp, (void *)data, gprSize);
323   memcpy((void *)argp, (void *)data, argSize);
324   gprCount   += (gprSize + sizeof(int) - 1) / sizeof(int);
325   stackIndex += (argSize + sizeof(int) - 1) / sizeof(int);
326 
327 #undef argl
328 #undef gprl
329 
330   for (i= 0;  i < specSize;  ++i)
331     {
332       int typeSpec= structSpec[i];
333       if (typeSpec & FFIFlagPointer)
334 	continue;
335       else if (typeSpec & FFIFlagStructure)
336 	continue;
337       else
338 	{
339 	  int atomicType= (typeSpec & FFIAtomicTypeMask) >> FFIAtomicTypeShift;
340 	  switch (atomicType)
341 	    {
342 	    case FFITypeSingleFloat:
343 	      if (fprCount < FPR_MAX)
344 		fprs[fprCount++]= *(float *)data;
345 	      break;
346 	    case FFITypeDoubleFloat:
347 	      if (fprCount < FPR_MAX)
348 		fprs[fprCount++]= *(double *)data;
349 	      break;
350 	    default:
351 	      break;
352 	    }
353 	  data += typeSpec & FFIStructSizeMask;
354 	}
355     }
356   return 1;
357 }
358 
359 
ffiCanReturn(int * structSpec,int specSize)360 int ffiCanReturn(int *structSpec, int specSize)
361 {
362   int header= *structSpec;
363   debugf(("ffiCanReturn %p %d\n", structSpec, specSize));
364   if (header & FFIFlagPointer)
365     return 1;
366   if (header & FFIFlagStructure)
367     {
368       /* structs are always returned as pointers to hidden structures */
369       int structSize= header & FFIStructSizeMask;
370       structReturnValue= malloc(structSize);
371       if (!structReturnValue)
372 	return 0;
373       pushGPR((int)structReturnValue);
374     }
375   return 1;
376 }
377 
378 
ffiReturnFloatValue(void)379 double ffiReturnFloatValue(void)	{ return floatReturnValue; }
ffiLongLongResultLow(void)380 int    ffiLongLongResultLow(void)	{ return ((int *)&longReturnValue)[1]; }
ffiLongLongResultHigh(void)381 int    ffiLongLongResultHigh(void)	{ return ((int *)&longReturnValue)[0]; }
382 
383 
ffiStoreStructure(int address,int structSize)384 int ffiStoreStructure(int address, int structSize)
385 {
386   debugf(("ffiStoreStructure %08x %d\n", address, structSize));
387   memcpy((void *)address,
388 	 structReturnValue ? (void *)structReturnValue : (void *)&longReturnValue,
389 	 structSize);
390   return 1;
391 }
392 
393 
ffiCleanup(void)394 int ffiCleanup(void)
395 {
396   int i;
397   debugf(("ffiCleanup\n"));
398   for (i= 0;  i < stringCount;  ++i)
399     free(strings[i]);
400   stringCount= 0;
401   if (structReturnValue)
402     {
403       free(structReturnValue);
404       structReturnValue= 0;
405     }
406   return 1;
407 }
408 
409 
ffiCallAddressOfWithPointerReturn(int fn,int callType)410 int ffiCallAddressOfWithPointerReturn(int fn, int callType)
411 {
412   debugf(("ffiCallAddressOfWithPointerReturn %08x %d\n", fn, callType));
413   return ffiCallAddressOf((void *)fn, (void *)&global);
414 }
415 
416 
ffiCallAddressOfWithStructReturn(int fn,int callType,int * structSpec,int specSize)417 int ffiCallAddressOfWithStructReturn(int fn, int callType, int* structSpec, int specSize)
418 {
419   debugf(("ffiCallAddressOfWithStructReturn %08x %d %p %d\n",
420 	   fn, callType, structSpec, specSize));
421   return ffiCallAddressOf((void *)fn, (void *)&global);
422 }
423 
424 
ffiCallAddressOfWithReturnType(int fn,int callType,int typeSpec)425 int ffiCallAddressOfWithReturnType(int fn, int callType, int typeSpec)
426 {
427   debugf(("ffiCallAddressOfWithReturnType %08x %d %d\n", fn, callType, typeSpec));
428   return ffiCallAddressOf((void *)fn, (void *)&global);
429 }
430 
431 
432 #if !defined(NO_FFI_TEST)
433 
434 #undef gprCount
435 #undef fprCount
436 #undef stackIndex
437 #undef structReturnValue
438 #undef longReturnValue
439 #undef floatReturnValue
440 #undef gprs
441 #undef fprs
442 #undef stack
443 
444 #include "ppc-global.h"
445 
446 #define offset(field)	((char *)&global._##field - (char *)&global._gprCount)
447 
448 #include <assert.h>
449 
ffiDoAssertions(void)450 void ffiDoAssertions(void)
451 {
452   assert(gprCount		== offset(gprCount));
453   assert(fprCount		== offset(fprCount));
454   assert(stackIndex		== offset(stackIndex));
455   assert(structReturnValue	== offset(structReturnValue));
456   assert(longReturnValue	== offset(longReturnValue));
457   assert(floatReturnValue	== offset(floatReturnValue));
458   assert(gprs			== offset(gprs));
459   assert(fprs			== offset(fprs));
460   assert(stack			== offset(stack));
461 
462   assert(stack + (ARG_MAX * sizeof(int)) == sizeof(global));
463 }
464 
465 #endif
466