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