19551
|
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:[
|
20307
|
40 |
aReceiverOrNil isNil ifTrue:[
|
|
41 |
"/ must have a c++ object instance
|
|
42 |
self primitiveFailed.
|
|
43 |
].
|
19551
|
44 |
|
20307
|
45 |
"/ and it must be a kind of ExternalStructure !!
|
|
46 |
(aReceiverOrNil isExternalStructure) ifFalse:[
|
|
47 |
self primitiveFailed.
|
|
48 |
].
|
|
49 |
virtual ifTrue:[
|
|
50 |
vtOffset := name.
|
|
51 |
].
|
19551
|
52 |
] ifFalse:[
|
20307
|
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 |
].
|
19551
|
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;
|
20307
|
80 |
INTLFUNC codeAddress = (voidFUNC)__INST(code_);
|
19551
|
81 |
int __numArgsWanted;
|
|
82 |
|
|
83 |
# define __FAIL__(fcode) \
|
|
84 |
{ \
|
20307
|
85 |
failureCode = fcode; failureArgNr = __mkSmallInteger(i+1); goto getOutOfHere; \
|
19551
|
86 |
}
|
|
87 |
|
|
88 |
if (argumentsOrNil == nil) {
|
20307
|
89 |
__numArgs = 0;
|
21623
|
90 |
} else if (__isArrayLike(argumentsOrNil)) {
|
20307
|
91 |
__numArgs = __arraySize(argumentsOrNil);
|
19551
|
92 |
} else {
|
20307
|
93 |
__FAIL__(@symbol(BadArgumentVector))
|
19551
|
94 |
}
|
|
95 |
if (__numArgs != __numArgsWanted) {
|
20307
|
96 |
__FAIL__(@symbol(ArgumentCountMismatch))
|
19551
|
97 |
}
|
|
98 |
if (__numArgs > MAX_ARGS) {
|
20307
|
99 |
__FAIL__(@symbol(TooManyArguments))
|
19551
|
100 |
}
|
|
101 |
|
|
102 |
/*
|
|
103 |
* validate the c++ object
|
|
104 |
*/
|
|
105 |
if (aReceiverOrNil != nil) {
|
20307
|
106 |
struct cPlusPlusInstance {
|
|
107 |
void **vTable;
|
|
108 |
};
|
|
109 |
struct cPlusPlusInstance *inst;
|
19551
|
110 |
|
20307
|
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;
|
19551
|
121 |
|
20307
|
122 |
if (virtual == true) {
|
|
123 |
if (! __isSmallInteger(vtOffset)) {
|
|
124 |
__FAIL__(@symbol(InvalidVTableIndex))
|
|
125 |
}
|
|
126 |
codeAddress = inst->vTable[__intVal(vtOffset)];
|
19551
|
127 |
# ifdef VERBOSE
|
20307
|
128 |
if (@global(Verbose) == true) {
|
|
129 |
printf("virtual %d codeAddress: %"_lx_"\n", __intVal(vtOffset), (INT)codeAddress);
|
|
130 |
}
|
19551
|
131 |
# endif
|
20307
|
132 |
}
|
19551
|
133 |
} else {
|
20307
|
134 |
__numArgsIncludingThis = __numArgs;
|
19551
|
135 |
# ifdef VERBOSE
|
20307
|
136 |
if (@global(Verbose) == true) {
|
|
137 |
printf("codeAddress: %"_lx_"\n", (INT)codeAddress);
|
|
138 |
}
|
19551
|
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++) {
|
20307
|
146 |
OBJ arg;
|
19551
|
147 |
|
20307
|
148 |
failureInfo = __mkSmallInteger(i+1); /* in case there is one */
|
19551
|
149 |
|
20307
|
150 |
arg = __ArrayInstPtr(argumentsOrNil)->a_element[i];
|
19551
|
151 |
|
20307
|
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 |
}
|
19551
|
186 |
}
|
|
187 |
failureInfo = nil;
|
|
188 |
|
|
189 |
retVal = (*codeAddress)(__args[0], __args[1], __args[2], __args[3], __args[4], __args[5], __args[6],
|
20307
|
190 |
__args[7], __args[8], __args[9], __args[10]);
|
19551
|
191 |
|
|
192 |
# ifdef VERBOSE
|
|
193 |
if (@global(Verbose) == true) {
|
20307
|
194 |
printf("retval is %"_ld_" (0x%"_lx_")\n", retVal, retVal);
|
19551
|
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
|
20307
|
204 |
if (@global(Verbose) == true) {
|
|
205 |
printf("return int: %x\n", retVal);
|
|
206 |
}
|
19551
|
207 |
# endif
|
20307
|
208 |
RETURN ( __MKINT(retVal) );
|
19551
|
209 |
}
|
|
210 |
if ((returnTypeSymbol == @symbol(uint))
|
|
211 |
|| (returnTypeSymbol == @symbol(uint8))
|
|
212 |
|| (returnTypeSymbol == @symbol(uint16))
|
|
213 |
|| (returnTypeSymbol == @symbol(uint32))) {
|
|
214 |
# ifdef VERBOSE
|
20307
|
215 |
if (@global(Verbose) == true) {
|
|
216 |
printf("return uint: %x\n", retVal);
|
|
217 |
}
|
19551
|
218 |
# endif
|
20307
|
219 |
RETURN ( __MKUINT(retVal) );
|
19551
|
220 |
}
|
|
221 |
if (returnTypeSymbol == @symbol(bool)) {
|
20307
|
222 |
RETURN ( retVal ? true : false );
|
19551
|
223 |
}
|
|
224 |
if (returnTypeSymbol == @symbol(void)) {
|
20307
|
225 |
RETURN ( nil );
|
19551
|
226 |
}
|
|
227 |
if (returnTypeSymbol == @symbol(char)) {
|
20307
|
228 |
RETURN ( __MKCHARACTER(retVal & 0xFF) );
|
19551
|
229 |
}
|
|
230 |
if (returnTypeSymbol == @symbol(wchar)) {
|
20307
|
231 |
RETURN ( __MKUCHARACTER(retVal & 0xFFFF) );
|
19551
|
232 |
}
|
|
233 |
|
|
234 |
# ifdef VERBOSE
|
|
235 |
if (@global(Verbose) == true) {
|
20307
|
236 |
printf("return pointer: %"_lx_"\n", (INT)(retVal));
|
19551
|
237 |
}
|
|
238 |
# endif
|
|
239 |
if (returnTypeSymbol == @symbol(handle)) {
|
20307
|
240 |
returnValue = __MKEXTERNALADDRESS(retVal);
|
19551
|
241 |
} else if (returnTypeSymbol == @symbol(pointer)) {
|
20307
|
242 |
returnValue = __MKEXTERNALBYTES(retVal);
|
19551
|
243 |
} else if (returnTypeSymbol == @symbol(bytePointer)) {
|
20307
|
244 |
returnValue = __MKEXTERNALBYTES(retVal);
|
19551
|
245 |
} else if (returnTypeSymbol == @symbol(charPointer)) {
|
20307
|
246 |
returnValue = __MKSTRING(retVal);
|
19551
|
247 |
} else if (returnTypeSymbol == @symbol(wcharPointer)) {
|
20307
|
248 |
returnValue = __MKU16STRING(retVal);
|
19551
|
249 |
} else {
|
20307
|
250 |
__FAIL__(@symbol(UnknownReturnType2))
|
19551
|
251 |
}
|
|
252 |
getOutOfHere: ;
|
|
253 |
%}.
|
|
254 |
failureCode notNil ifTrue:[
|
20307
|
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 |
].
|
19551
|
269 |
|
20307
|
270 |
self primitiveFailed. "see failureCode and failureInfo for details"
|
|
271 |
^ nil
|
19551
|
272 |
].
|
|
273 |
|
|
274 |
returnType isSymbol ifTrue:[
|
20307
|
275 |
returnValueClass notNil ifTrue:[
|
|
276 |
self isConstReturnValue ifTrue:[
|
|
277 |
returnValue changeClassTo:returnValueClass.
|
|
278 |
^ returnValue
|
|
279 |
].
|
|
280 |
^ returnValueClass fromExternalAddress:returnValue.
|
|
281 |
].
|
19551
|
282 |
] ifFalse:[
|
20307
|
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 |
].
|
19551
|
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 |
! !
|