|
1 "{ Package: 'stx:libbasic' }" |
|
2 |
|
3 "{ NameSpace: Smalltalk }" |
|
4 |
|
5 ExternalLibraryFunction subclass:#SimpleExternalLibraryFunction |
|
6 instanceVariableNames:'' |
|
7 classVariableNames:'' |
|
8 poolDictionaries:'' |
|
9 category:'System-Support' |
|
10 ! |
|
11 |
|
12 !SimpleExternalLibraryFunction class methodsFor:'documentation'! |
|
13 |
|
14 documentation |
|
15 " |
|
16 instances of me are used for very simple functions, with all integer or |
|
17 equivalent arguments. |
|
18 These avoid the realively expensive ffi- arg setup, and jump directly to the |
|
19 target function. |
|
20 Can be used for a subset of all external functions and only on some machines. |
|
21 Only for tuning; the superclass must provide a fallback for all calls |
|
22 " |
|
23 ! ! |
|
24 |
|
25 !SimpleExternalLibraryFunction methodsFor:'private invoking'! |
|
26 |
|
27 invokeFFIwithArguments:argumentsOrNil forCPPInstance:aReceiverOrNil |
|
28 "the caller must have already checked, if instances of me are appropriate. |
|
29 May only be used for up to 10 args, with INT-sized non-float, non-struct arguments, |
|
30 and int-sized, non-float, non-struct return value. |
|
31 Now, all I do is convert the arguments and transfer directly; without the expensive ffi..." |
|
32 |
|
33 |argTypeSymbols returnTypeSymbol failureCode failureArgNr failureInfo returnValue stClass vtOffset |
|
34 virtual objectiveC async unlimitedStack callTypeNumber returnValueClass argValueClass |
|
35 oldReturnType oldArgumentTypes| |
|
36 |
|
37 virtual := self isVirtualCPP. |
|
38 objectiveC := self isObjectiveC. |
|
39 (virtual "or:[self isNonVirtualCPP]") ifTrue:[ |
|
40 aReceiverOrNil isNil ifTrue:[ |
|
41 "/ must have a c++ object instance |
|
42 self primitiveFailed. |
|
43 ]. |
|
44 |
|
45 "/ and it must be a kind of ExternalStructure !! |
|
46 (aReceiverOrNil isExternalStructure) ifFalse:[ |
|
47 self primitiveFailed. |
|
48 ]. |
|
49 virtual ifTrue:[ |
|
50 vtOffset := name. |
|
51 ]. |
|
52 ] ifFalse:[ |
|
53 objectiveC ifTrue:[ |
|
54 aReceiverOrNil isNil ifTrue:[ |
|
55 "/ must have an objective-c object instance |
|
56 self primitiveFailed. |
|
57 ]. |
|
58 (aReceiverOrNil isObjectiveCObject) ifFalse:[ |
|
59 self primitiveFailed |
|
60 ] |
|
61 ] ifFalse:[ |
|
62 aReceiverOrNil notNil ifTrue:[ |
|
63 "/ must NOT have a c++/objectiveC object instance |
|
64 self primitiveFailed. |
|
65 ] |
|
66 ]. |
|
67 ]. |
|
68 |
|
69 %{ /* STACK: 100000 */ |
|
70 |
|
71 #define VERBOSE |
|
72 #define MAX_ARGS 10 |
|
73 |
|
74 int __numArgs, __numArgsIncludingThis; |
|
75 static INT null = 0; |
|
76 INT __args[MAX_ARGS+1]; |
|
77 INT retVal; |
|
78 int i = -1; |
|
79 int argIdx = 0; |
|
80 INTFUNC codeAddress = (VOIDFUNC)__INST(code_); |
|
81 int __numArgsWanted; |
|
82 |
|
83 # define __FAIL__(fcode) \ |
|
84 { \ |
|
85 failureCode = fcode; failureArgNr = __mkSmallInteger(i+1); goto getOutOfHere; \ |
|
86 } |
|
87 |
|
88 if (argumentsOrNil == nil) { |
|
89 __numArgs = 0; |
|
90 } else if (__isArray(argumentsOrNil)) { |
|
91 __numArgs = __arraySize(argumentsOrNil); |
|
92 } else { |
|
93 __FAIL__(@symbol(BadArgumentVector)) |
|
94 } |
|
95 if (__numArgs != __numArgsWanted) { |
|
96 __FAIL__(@symbol(ArgumentCountMismatch)) |
|
97 } |
|
98 if (__numArgs > MAX_ARGS) { |
|
99 __FAIL__(@symbol(TooManyArguments)) |
|
100 } |
|
101 |
|
102 /* |
|
103 * validate the c++ object |
|
104 */ |
|
105 if (aReceiverOrNil != nil) { |
|
106 struct cPlusPlusInstance { |
|
107 void **vTable; |
|
108 }; |
|
109 struct cPlusPlusInstance *inst; |
|
110 |
|
111 if (__isExternalAddressLike(aReceiverOrNil)) { |
|
112 inst = (void *)(__externalAddressVal(aReceiverOrNil)); |
|
113 } else if (__isExternalBytesLike(aReceiverOrNil)) { |
|
114 inst = (void *)(__externalBytesVal(aReceiverOrNil)); |
|
115 } else { |
|
116 __FAIL__(@symbol(InvalidInstance)) |
|
117 } |
|
118 __args[0] = (INT)inst; |
|
119 __numArgsIncludingThis = __numArgs + 1; |
|
120 argIdx = 1; |
|
121 |
|
122 if (virtual == true) { |
|
123 if (! __isSmallInteger(vtOffset)) { |
|
124 __FAIL__(@symbol(InvalidVTableIndex)) |
|
125 } |
|
126 codeAddress = inst->vTable[__intVal(vtOffset)]; |
|
127 # ifdef VERBOSE |
|
128 if (@global(Verbose) == true) { |
|
129 printf("virtual %d codeAddress: %"_lx_"\n", __intVal(vtOffset), (INT)codeAddress); |
|
130 } |
|
131 # endif |
|
132 } |
|
133 } else { |
|
134 __numArgsIncludingThis = __numArgs; |
|
135 # ifdef VERBOSE |
|
136 if (@global(Verbose) == true) { |
|
137 printf("codeAddress: %"_lx_"\n", (INT)codeAddress); |
|
138 } |
|
139 # endif |
|
140 } |
|
141 |
|
142 /* |
|
143 * validate all arg types, map each to an ffi_type, and setup arg-buffers |
|
144 */ |
|
145 for (i=0; i<__numArgs; i++, argIdx++) { |
|
146 OBJ arg; |
|
147 |
|
148 failureInfo = __mkSmallInteger(i+1); /* in case there is one */ |
|
149 |
|
150 arg = __ArrayInstPtr(argumentsOrNil)->a_element[i]; |
|
151 |
|
152 if (__isSmallInteger(arg)) { |
|
153 __args[argIdx] = __intVal(arg); |
|
154 } else { |
|
155 INT iv = __signedLongIntVal(arg); |
|
156 if (iv != 0) { |
|
157 __args[argIdx] = iv; |
|
158 } else { |
|
159 unsigned INT iv = __unsignedLongIntVal(arg); |
|
160 if (iv != 0) { |
|
161 __args[argIdx] = iv; |
|
162 } else { |
|
163 if (__isStringLike(arg)) { |
|
164 __args[argIdx] = (INT)(__stringVal(arg)); |
|
165 } else { |
|
166 if (__isBytes(arg)) { |
|
167 __args[argIdx] = (INT)(__byteArrayVal(arg)); |
|
168 if (arg == NULL) { |
|
169 __args[argIdx] = (INT)0; |
|
170 } else { |
|
171 if (__isExternalAddressLike(arg)) { |
|
172 __args[argIdx] = (INT)(__externalAddressVal(arg)); |
|
173 } else { |
|
174 if (__isExternalBytesLike(arg)) { |
|
175 __args[argIdx] = (INT)(__externalBytesVal(arg)); |
|
176 } else { |
|
177 __FAIL__(@symbol(InvalidArgument)) |
|
178 } |
|
179 } |
|
180 } |
|
181 } |
|
182 } |
|
183 } |
|
184 } |
|
185 } |
|
186 } |
|
187 failureInfo = nil; |
|
188 |
|
189 retVal = (*codeAddress)(__args[0], __args[1], __args[2], __args[3], __args[4], __args[5], __args[6], |
|
190 __args[7], __args[8], __args[9], __args[10]); |
|
191 |
|
192 # ifdef VERBOSE |
|
193 if (@global(Verbose) == true) { |
|
194 printf("retval is %"_ld_" (0x%"_lx_")\n", retVal, retVal); |
|
195 } |
|
196 # endif |
|
197 |
|
198 if ((returnTypeSymbol == @symbol(int)) |
|
199 || (returnTypeSymbol == @symbol(sint)) |
|
200 || (returnTypeSymbol == @symbol(sint8)) |
|
201 || (returnTypeSymbol == @symbol(sint16)) |
|
202 || (returnTypeSymbol == @symbol(sint32))) { |
|
203 # ifdef VERBOSE |
|
204 if (@global(Verbose) == true) { |
|
205 printf("return int: %x\n", retVal); |
|
206 } |
|
207 # endif |
|
208 RETURN ( __MKINT(retVal) ); |
|
209 } |
|
210 if ((returnTypeSymbol == @symbol(uint)) |
|
211 || (returnTypeSymbol == @symbol(uint8)) |
|
212 || (returnTypeSymbol == @symbol(uint16)) |
|
213 || (returnTypeSymbol == @symbol(uint32))) { |
|
214 # ifdef VERBOSE |
|
215 if (@global(Verbose) == true) { |
|
216 printf("return uint: %x\n", retVal); |
|
217 } |
|
218 # endif |
|
219 RETURN ( __MKUINT(retVal) ); |
|
220 } |
|
221 if (returnTypeSymbol == @symbol(bool)) { |
|
222 RETURN ( retVal ? true : false ); |
|
223 } |
|
224 if (returnTypeSymbol == @symbol(void)) { |
|
225 RETURN ( nil ); |
|
226 } |
|
227 if (returnTypeSymbol == @symbol(char)) { |
|
228 RETURN ( __MKCHARACTER(retVal & 0xFF) ); |
|
229 } |
|
230 if (returnTypeSymbol == @symbol(wchar)) { |
|
231 RETURN ( __MKUCHARACTER(retVal & 0xFFFF) ); |
|
232 } |
|
233 |
|
234 # ifdef VERBOSE |
|
235 if (@global(Verbose) == true) { |
|
236 printf("return pointer: %"_lx_"\n", (INT)(retVal)); |
|
237 } |
|
238 # endif |
|
239 if (returnTypeSymbol == @symbol(handle)) { |
|
240 returnValue = __MKEXTERNALADDRESS(retVal); |
|
241 } else if (returnTypeSymbol == @symbol(pointer)) { |
|
242 returnValue = __MKEXTERNALBYTES(retVal); |
|
243 } else if (returnTypeSymbol == @symbol(bytePointer)) { |
|
244 returnValue = __MKEXTERNALBYTES(retVal); |
|
245 } else if (returnTypeSymbol == @symbol(charPointer)) { |
|
246 returnValue = __MKSTRING(retVal); |
|
247 } else if (returnTypeSymbol == @symbol(wcharPointer)) { |
|
248 returnValue = __MKU16STRING(retVal); |
|
249 } else { |
|
250 __FAIL__(@symbol(UnknownReturnType2)) |
|
251 } |
|
252 getOutOfHere: ; |
|
253 %}. |
|
254 failureCode notNil ifTrue:[ |
|
255 (failureCode == #UnknownReturnType or:[ failureCode == #UnknownArgumentType ]) ifTrue:[ |
|
256 oldReturnType := returnType. |
|
257 oldArgumentTypes := argumentTypes. |
|
258 self adjustTypes. |
|
259 ((oldReturnType ~= returnType) or:[oldArgumentTypes ~= argumentTypes]) ifTrue:[ |
|
260 thisContext restart |
|
261 ]. |
|
262 ]. |
|
263 (failureCode == #BadArgForAsyncCall) ifTrue:[ |
|
264 ^ self tryAgainWithAsyncSafeArguments:argumentsOrNil forCPPInstance:aReceiverOrNil |
|
265 ]. |
|
266 (failureCode == #FFINotSupported) ifTrue:[ |
|
267 self primitiveFailed:'FFI support missing in this build'. |
|
268 ]. |
|
269 |
|
270 self primitiveFailed. "see failureCode and failureInfo for details" |
|
271 ^ nil |
|
272 ]. |
|
273 |
|
274 returnType isSymbol ifTrue:[ |
|
275 returnValueClass notNil ifTrue:[ |
|
276 self isConstReturnValue ifTrue:[ |
|
277 returnValue changeClassTo:returnValueClass. |
|
278 ^ returnValue |
|
279 ]. |
|
280 ^ returnValueClass fromExternalAddress:returnValue. |
|
281 ]. |
|
282 ] ifFalse:[ |
|
283 returnType isCPointer ifTrue:[ |
|
284 returnType baseType isCStruct ifTrue:[ |
|
285 stClass := Smalltalk classNamed:returnType baseType name. |
|
286 stClass notNil ifTrue:[ |
|
287 self isConstReturnValue ifTrue:[ |
|
288 returnValue changeClassTo:returnValueClass. |
|
289 ^ returnValue |
|
290 ]. |
|
291 ^ stClass fromExternalAddress:returnValue. |
|
292 ]. |
|
293 ]. |
|
294 returnType baseType isCChar ifTrue:[ |
|
295 ^ returnValue stringAt:1 |
|
296 ]. |
|
297 ]. |
|
298 ]. |
|
299 |
|
300 ^ returnValue |
|
301 |
|
302 "Created: / 01-08-2006 / 13:56:23 / cg" |
|
303 "Modified: / 31-03-2016 / 00:03:03 / cg" |
|
304 ! ! |
|
305 |
|
306 !SimpleExternalLibraryFunction class methodsFor:'documentation'! |
|
307 |
|
308 version |
|
309 ^ '$Header$' |
|
310 ! |
|
311 |
|
312 version_CVS |
|
313 ^ '$Header$' |
|
314 ! ! |
|
315 |