|
1 'From Smalltalk/X, Version:5.3.5 on 12-06-2007 at 16:40:04' ! |
|
2 |
|
3 ExternalBytes subclass:#ExternalFunctionCallback |
|
4 instanceVariableNames:'returnType argumentTypes action' |
|
5 classVariableNames:'CallBackRegistry' |
|
6 poolDictionaries:'' |
|
7 category:'System-Support' |
|
8 ! |
|
9 |
|
10 !ExternalFunctionCallback primitiveDefinitions! |
|
11 %{ |
|
12 |
|
13 #ifdef HAVE_FFI |
|
14 # include <ffi.h> |
|
15 # define MAX_ARGS 128 |
|
16 |
|
17 extern ffi_type *__get_ffi_type_sint(); |
|
18 extern ffi_type *__get_ffi_type_sint8(); |
|
19 extern ffi_type *__get_ffi_type_sint16(); |
|
20 extern ffi_type *__get_ffi_type_sint32(); |
|
21 extern ffi_type *__get_ffi_type_sint64(); |
|
22 extern ffi_type *__get_ffi_type_uint(); |
|
23 extern ffi_type *__get_ffi_type_uint8(); |
|
24 extern ffi_type *__get_ffi_type_uint16(); |
|
25 extern ffi_type *__get_ffi_type_uint32(); |
|
26 extern ffi_type *__get_ffi_type_uint64(); |
|
27 extern ffi_type *__get_ffi_type_float(); |
|
28 extern ffi_type *__get_ffi_type_double(); |
|
29 extern ffi_type *__get_ffi_type_void(); |
|
30 extern ffi_type *__get_ffi_type_pointer(); |
|
31 |
|
32 #endif |
|
33 |
|
34 %} |
|
35 ! ! |
|
36 |
|
37 !ExternalFunctionCallback primitiveFunctions! |
|
38 %{ |
|
39 |
|
40 #define VERBOSE |
|
41 |
|
42 void |
|
43 ExternalFunctionCallback__closure_test_fn(ffi_cif* cif, void* resp, void** args, void* userdata) |
|
44 { |
|
45 int actionIndex = userdata; |
|
46 |
|
47 printf("closure_test_fn(userdata=%d resp*=%x)\n", userdata, resp); |
|
48 printf("closure_test_fn(arg[0]=%d)\n", *(int *)(args[0])); |
|
49 *(ffi_arg *)resp = 1; |
|
50 } |
|
51 |
|
52 void |
|
53 ExternalFunctionCallback__doCall_closure(INTFUNC f) |
|
54 { |
|
55 int result = 0; |
|
56 |
|
57 printf("doCall_closure: calling closure %x(123)...\n", f); |
|
58 result = (*f)(123); |
|
59 printf("doCall_closure: back; result is %x...\n", result); |
|
60 } |
|
61 |
|
62 %} |
|
63 ! ! |
|
64 |
|
65 !ExternalFunctionCallback class methodsFor:'examples'! |
|
66 |
|
67 examples |
|
68 " |
|
69 |cb| |
|
70 |
|
71 cb := ExternalFunctionCallback new. |
|
72 cb returnType:#bool argumentTypes:#(uint). |
|
73 cb generateClosure. |
|
74 |
|
75 cb action:[:arg | Transcript showCR:arg]. |
|
76 cb address. |
|
77 " |
|
78 ! ! |
|
79 |
|
80 !ExternalFunctionCallback methodsFor:'accessing'! |
|
81 |
|
82 action:something |
|
83 action := something. |
|
84 ! ! |
|
85 |
|
86 !ExternalFunctionCallback methodsFor:'generation'! |
|
87 |
|
88 address |
|
89 self isValid ifFalse:[ |
|
90 self generate |
|
91 ]. |
|
92 ^ super address |
|
93 |
|
94 "Created: / 11-06-2007 / 15:53:00 / cg" |
|
95 ! |
|
96 |
|
97 generate |
|
98 |code| |
|
99 |
|
100 code := nil |
|
101 |
|
102 "Created: / 11-06-2007 / 14:50:57 / cg" |
|
103 ! |
|
104 |
|
105 generate0 |
|
106 |code| |
|
107 |
|
108 code := #[ |
|
109 "/ mov ecx, closureIndex |
|
110 16rB9 |
|
111 16r00 16r00 16r00 16r01 |
|
112 "/ mov eax, doClosureC |
|
113 16rB8 |
|
114 16r00 16r00 16r00 16r02 |
|
115 "/ call *eax |
|
116 16rFF 16rD0 |
|
117 "/ ret |
|
118 16rC3 |
|
119 ]. |
|
120 |
|
121 self allocateBytes:(code size). |
|
122 |
|
123 "Created: / 11-06-2007 / 15:29:33 / cg" |
|
124 ! ! |
|
125 |
|
126 !ExternalFunctionCallback methodsFor:'private-accessing'! |
|
127 |
|
128 returnType:aReturnType argumentTypes:argTypes |
|
129 returnType := aReturnType. |
|
130 argumentTypes := argTypes. |
|
131 |
|
132 "Created: / 11-06-2007 / 15:52:01 / cg" |
|
133 ! ! |
|
134 |
|
135 !ExternalFunctionCallback methodsFor:'private-generation'! |
|
136 |
|
137 generateClosure |
|
138 |argTypeSymbols returnTypeSymbol failureCode failureInfo returnValue stClass vtOffset |
|
139 virtual async unlimitedStack callTypeNumber returnValueClass argValueClass| |
|
140 |
|
141 argTypeSymbols := argumentTypes. |
|
142 returnTypeSymbol := returnType. |
|
143 |
|
144 %{ /* STACK: 100000 */ |
|
145 #if 1 |
|
146 #ifdef HAVE_FFI |
|
147 ffi_cif __cif; |
|
148 ffi_type *__argTypesIncludingThis[MAX_ARGS+1]; |
|
149 ffi_type **__argTypes = __argTypesIncludingThis; |
|
150 ffi_type *__returnType = NULL; |
|
151 void *__returnValuePointer; |
|
152 static int null = 0; |
|
153 int i; |
|
154 ffi_abi __callType = FFI_DEFAULT_ABI; |
|
155 int __numArgsWanted; |
|
156 ffi_closure *pcl; |
|
157 |
|
158 #define __FAIL__(fcode) \ |
|
159 { \ |
|
160 failureCode = fcode; goto getOutOfHere; \ |
|
161 } |
|
162 |
|
163 if (argTypeSymbols == nil) { |
|
164 __numArgsWanted = 0; |
|
165 } else if (__isArray(argTypeSymbols)) { |
|
166 __numArgsWanted = __arraySize(argTypeSymbols); |
|
167 } else { |
|
168 __FAIL__(@symbol(BadArgumentTypeVector)) |
|
169 } |
|
170 |
|
171 if (__numArgsWanted > MAX_ARGS) { |
|
172 __FAIL__(@symbol(TooManyArguments)) |
|
173 } |
|
174 |
|
175 /* |
|
176 * validate the return type |
|
177 */ |
|
178 if (returnTypeSymbol == @symbol(voidPointer)) { |
|
179 returnTypeSymbol = @symbol(handle); |
|
180 } |
|
181 |
|
182 if (returnTypeSymbol == @symbol(int)) { |
|
183 __returnType = __get_ffi_type_sint(); |
|
184 } else if (returnTypeSymbol == @symbol(uint)) { |
|
185 __returnType = __get_ffi_type_uint(); |
|
186 } else if (returnTypeSymbol == @symbol(uint8)) { |
|
187 __returnType = __get_ffi_type_uint8(); |
|
188 } else if (returnTypeSymbol == @symbol(uint16)) { |
|
189 __returnType = __get_ffi_type_uint16(); |
|
190 } else if (returnTypeSymbol == @symbol(uint32)) { |
|
191 __returnType = __get_ffi_type_uint32(); |
|
192 } else if (returnTypeSymbol == @symbol(uint64)) { |
|
193 __returnType = __get_ffi_type_uint64(); |
|
194 |
|
195 } else if (returnTypeSymbol == @symbol(sint)) { |
|
196 __returnType = __get_ffi_type_sint(); |
|
197 } else if (returnTypeSymbol == @symbol(sint8)) { |
|
198 __returnType = __get_ffi_type_sint8(); |
|
199 } else if (returnTypeSymbol == @symbol(sint16)) { |
|
200 __returnType = __get_ffi_type_sint16(); |
|
201 } else if (returnTypeSymbol == @symbol(sint32)) { |
|
202 __returnType = __get_ffi_type_sint32(); |
|
203 } else if (returnTypeSymbol == @symbol(sint64)) { |
|
204 __returnType = __get_ffi_type_sint64(); |
|
205 |
|
206 } else if (returnTypeSymbol == @symbol(long)) { |
|
207 if (sizeof(long) == 4) { |
|
208 returnTypeSymbol = @symbol(sint32); |
|
209 __returnType = __get_ffi_type_sint32(); |
|
210 } else if (sizeof(long) == 8) { |
|
211 returnTypeSymbol = @symbol(sint64); |
|
212 __returnType = __get_ffi_type_sint64(); |
|
213 } else { |
|
214 __FAIL__(@symbol(UnknownReturnType)) |
|
215 } |
|
216 |
|
217 } else if (returnTypeSymbol == @symbol(ulong)) { |
|
218 if (sizeof(long) == 4) { |
|
219 returnTypeSymbol = @symbol(uint32); |
|
220 __returnType = __get_ffi_type_uint32(); |
|
221 }else if (sizeof(long) == 8) { |
|
222 returnTypeSymbol = @symbol(uint64); |
|
223 __returnType = __get_ffi_type_uint64(); |
|
224 } else { |
|
225 __FAIL__(@symbol(UnknownReturnType)) |
|
226 } |
|
227 |
|
228 } else if (returnTypeSymbol == @symbol(bool)) { |
|
229 __returnType = __get_ffi_type_uint(); |
|
230 |
|
231 } else if (returnTypeSymbol == @symbol(float)) { |
|
232 __returnType = __get_ffi_type_float(); |
|
233 } else if (returnTypeSymbol == @symbol(double)) { |
|
234 __returnType = __get_ffi_type_double(); |
|
235 |
|
236 } else if (returnTypeSymbol == @symbol(void)) { |
|
237 __returnType = __get_ffi_type_void(); |
|
238 } else if ((returnTypeSymbol == @symbol(pointer)) |
|
239 || (returnTypeSymbol == @symbol(handle)) |
|
240 || (returnTypeSymbol == @symbol(charPointer)) |
|
241 || (returnTypeSymbol == @symbol(bytePointer)) |
|
242 || (returnTypeSymbol == @symbol(floatPointer)) |
|
243 || (returnTypeSymbol == @symbol(doublePointer)) |
|
244 || (returnTypeSymbol == @symbol(intPointer)) |
|
245 || (returnTypeSymbol == @symbol(shortPointer)) |
|
246 || (returnTypeSymbol == @symbol(wcharPointer))) { |
|
247 __returnType = __get_ffi_type_pointer(); |
|
248 } else { |
|
249 if (__isSymbol(returnTypeSymbol) |
|
250 && ((returnValueClass = __GLOBAL_GET(returnTypeSymbol)) != nil)) { |
|
251 if (! __isBehaviorLike(returnValueClass)) { |
|
252 __FAIL__(@symbol(NonBehaviorReturnType)) |
|
253 } |
|
254 if (! __qIsSubclassOfExternalAddress(returnValueClass)) { |
|
255 __FAIL__(@symbol(NonExternalAddressReturnType)) |
|
256 } |
|
257 __returnType = __get_ffi_type_pointer(); |
|
258 returnTypeSymbol = @symbol(pointer); |
|
259 } else { |
|
260 __FAIL__(@symbol(UnknownReturnType)) |
|
261 } |
|
262 } |
|
263 |
|
264 /* |
|
265 * setup arg-buffers |
|
266 */ |
|
267 for (i=0; i<__numArgsWanted; i++) { |
|
268 ffi_type *thisType; |
|
269 void *argValuePtr; |
|
270 OBJ typeSymbol; |
|
271 |
|
272 failureInfo = __mkSmallInteger(i+1); /* in case there is one */ |
|
273 |
|
274 typeSymbol = __ArrayInstPtr(argTypeSymbols)->a_element[i]; |
|
275 |
|
276 if (typeSymbol == @symbol(handle)) { |
|
277 typeSymbol = @symbol(pointer); |
|
278 } else if (typeSymbol == @symbol(voidPointer)) { |
|
279 typeSymbol = @symbol(pointer); |
|
280 } |
|
281 |
|
282 if (typeSymbol == @symbol(long)) { |
|
283 if (sizeof(long) == sizeof(int)) { |
|
284 typeSymbol = @symbol(sint); |
|
285 } else { |
|
286 if (sizeof(long) == 4) { |
|
287 typeSymbol = @symbol(sint32); |
|
288 } else if (sizeof(long) == 8) { |
|
289 typeSymbol = @symbol(sint64); |
|
290 } |
|
291 } |
|
292 } |
|
293 if (typeSymbol == @symbol(ulong)) { |
|
294 if (sizeof(unsigned long) == sizeof(unsigned int)) { |
|
295 typeSymbol = @symbol(uint); |
|
296 } else { |
|
297 if (sizeof(long) == 4) { |
|
298 typeSymbol = @symbol(uint32); |
|
299 } else if (sizeof(long) == 8) { |
|
300 typeSymbol = @symbol(uint64); |
|
301 } |
|
302 } |
|
303 } |
|
304 |
|
305 if (typeSymbol == @symbol(int)) { |
|
306 thisType = __get_ffi_type_sint(); |
|
307 } else if (typeSymbol == @symbol(uint)) { |
|
308 thisType = __get_ffi_type_uint(); |
|
309 } else if (typeSymbol == @symbol(uint8)) { |
|
310 thisType = __get_ffi_type_uint8(); |
|
311 } else if (typeSymbol == @symbol(sint8)) { |
|
312 thisType = __get_ffi_type_sint8(); |
|
313 } else if (typeSymbol == @symbol(uint16)) { |
|
314 thisType = __get_ffi_type_uint16(); |
|
315 } else if (typeSymbol == @symbol(sint16)) { |
|
316 thisType = __get_ffi_type_sint16(); |
|
317 } else if ((typeSymbol == @symbol(uint32)) || (typeSymbol == @symbol(sint32))) { |
|
318 thisType = __get_ffi_type_uint32(); |
|
319 } else if (typeSymbol == @symbol(float)) { |
|
320 thisType = __get_ffi_type_float(); |
|
321 } else if (typeSymbol == @symbol(double)) { |
|
322 thisType = __get_ffi_type_double(); |
|
323 } else if (typeSymbol == @symbol(void)) { |
|
324 thisType = __get_ffi_type_void(); |
|
325 } else if (typeSymbol == @symbol(charPointer)) { |
|
326 thisType = __get_ffi_type_pointer(); |
|
327 } else if (typeSymbol == @symbol(floatPointer)) { |
|
328 thisType = __get_ffi_type_pointer(); |
|
329 } else if (typeSymbol == @symbol(doublePointer)) { |
|
330 thisType = __get_ffi_type_pointer(); |
|
331 } else if (typeSymbol == @symbol(pointer)) { |
|
332 commonPointerTypeArg: ; |
|
333 thisType = __get_ffi_type_pointer(); |
|
334 } else if (typeSymbol == @symbol(bool)) { |
|
335 thisType = __get_ffi_type_uint(); |
|
336 } else if (__isSymbol(typeSymbol) |
|
337 && ((argValueClass = __GLOBAL_GET(typeSymbol)) != nil)) { |
|
338 if (! __isBehaviorLike(argValueClass)) { |
|
339 __FAIL__(@symbol(NonBehaviorArgumentType)) |
|
340 } |
|
341 if (! __qIsSubclassOfExternalAddress(argValueClass)) { |
|
342 __FAIL__(@symbol(NonExternalAddressArgumentType)) |
|
343 } |
|
344 goto commonPointerTypeArg; /* sorry */ |
|
345 } else { |
|
346 __FAIL__(@symbol(UnknownArgumentType)) |
|
347 } |
|
348 |
|
349 __argTypes[i] = thisType; |
|
350 } |
|
351 failureInfo = nil; |
|
352 |
|
353 __callType = FFI_DEFAULT_ABI; |
|
354 |
|
355 if (callTypeNumber != nil) { |
|
356 #ifdef CALLTYPE_FFI_STDCALL |
|
357 if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_API)) { |
|
358 __callType = CALLTYPE_FFI_STDCALL; |
|
359 } |
|
360 #endif |
|
361 #ifdef CALLTYPE_FFI_V8 |
|
362 if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_V8)) { |
|
363 __callType = CALLTYPE_FFI_V8; |
|
364 } |
|
365 #endif |
|
366 #ifdef CALLTYPE_FFI_V9 |
|
367 if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_V9)) { |
|
368 __callType = CALLTYPE_FFI_V9; |
|
369 } |
|
370 #endif |
|
371 #ifdef CALLTYPE_FFI_UNIX64 |
|
372 if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_UNIX64)) { |
|
373 __callType = CALLTYPE_FFI_UNIX64; |
|
374 } |
|
375 #endif |
|
376 } |
|
377 |
|
378 # ifdef VERBOSE |
|
379 printf("prep_cif cif-ptr=%x\n", &__cif); |
|
380 # endif |
|
381 if (ffi_prep_cif(&__cif, __callType, __numArgsWanted, __returnType, __argTypesIncludingThis) != FFI_OK) { |
|
382 __FAIL__(@symbol(FFIPrepareFailed)) |
|
383 } |
|
384 pcl = (ffi_closure *) malloc(sizeof(ffi_closure)); |
|
385 # ifdef VERBOSE |
|
386 printf("closure is 0x%x (%d bytes)\n", pcl, sizeof(ffi_closure)); |
|
387 # endif |
|
388 if (ffi_prep_closure(pcl, &__cif, ExternalFunctionCallback__closure_test_fn, (void *) 3 /* userdata */) != FFI_OK) { |
|
389 __FAIL__(@symbol(FFIPrepareClosureFailed)) |
|
390 } |
|
391 # ifdef VERBOSE |
|
392 printf("pcl->cif is 0x%x\n", pcl->cif); |
|
393 printf("pcl->fun is 0x%x\n", pcl->fun); |
|
394 printf("pcl code is %02x %02x %02x %02x\n", ((char *)pcl)[0],((char *)pcl)[1],((char *)pcl)[2],((char *)pcl)[3]); |
|
395 printf(" %02x %02x %02x %02x\n", ((char *)pcl)[4],((char *)pcl)[5],((char *)pcl)[6],((char *)pcl)[7]); |
|
396 printf(" %02x %02x %02x %02x\n", ((char *)pcl)[8],((char *)pcl)[9],((char *)pcl)[10],((char *)pcl)[11]); |
|
397 printf(" %02x %02x %02x %02x\n", ((char *)pcl)[12],((char *)pcl)[13],((char *)pcl)[14],((char *)pcl)[15]); |
|
398 #endif |
|
399 ExternalFunctionCallback__doCall_closure((INTFUNC)pcl); |
|
400 free(pcl); |
|
401 |
|
402 #else /* no FFI support */ |
|
403 __FAIL__(@symbol(FFINotSupported)); |
|
404 #endif /* HAVE_FFI */ |
|
405 #endif /* 0 */ |
|
406 getOutOfHere: ; |
|
407 %}. |
|
408 failureCode notNil ifTrue:[ |
|
409 self primitiveFailed:(failureCode->failureInfo). "see failureCode and failureInfo for details" |
|
410 ^ nil |
|
411 ]. |
|
412 |
|
413 "Created: / 11-06-2007 / 21:53:02 / cg" |
|
414 ! ! |