42 ^ self new |
42 ^ self new |
43 name:functionName module:moduleName callType:callType |
43 name:functionName module:moduleName callType:callType |
44 returnType:returnType argumentTypes:argTypes |
44 returnType:returnType argumentTypes:argTypes |
45 ! ! |
45 ! ! |
46 |
46 |
|
47 !ExternalLibraryFunction class methodsFor:'constants'! |
|
48 |
|
49 callTypeAPI |
|
50 ^ #callTypeAPI |
|
51 ! |
|
52 |
|
53 callTypeC |
|
54 ^ #callTypeC |
|
55 ! |
|
56 |
|
57 callTypeCDecl |
|
58 ^ #callTypeCDecl |
|
59 ! |
|
60 |
|
61 callTypeOLE |
|
62 ^ #callTypeOLE |
|
63 ! ! |
|
64 |
|
65 !ExternalLibraryFunction methodsFor:'accessing'! |
|
66 |
|
67 argumentTypes |
|
68 ^ argumentTypes |
|
69 ! ! |
|
70 |
47 !ExternalLibraryFunction methodsFor:'invoking'! |
71 !ExternalLibraryFunction methodsFor:'invoking'! |
48 |
72 |
49 invoke |
73 invoke |
50 |
74 self hasCode ifFalse:[ |
51 moduleHandle isNil ifTrue:[ |
75 self prepareInvoke. |
52 self linkToModule. |
76 ]. |
53 self setupFFI. |
77 ^ self invokeFFIWithArguments:#() |
54 ]. |
|
55 |
|
56 ^ self invokeFFI |
|
57 ! |
78 ! |
58 |
79 |
59 invokeWith:arg |
80 invokeWith:arg |
60 |
81 self hasCode ifFalse:[ |
61 moduleHandle isNil ifTrue:[ |
82 self prepareInvoke. |
62 self linkToModule. |
83 ]. |
63 self setupFFI. |
84 ^ self invokeFFIWithArguments:(Array with:arg) |
64 ]. |
85 ! |
65 |
86 |
66 ^ self invokeFFI |
87 invokeWith:arg1 with:arg2 |
67 |
88 self hasCode ifFalse:[ |
68 " |
89 self prepareInvoke. |
69 self new test:'abc' |
90 ]. |
70 " |
91 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2) |
|
92 ! |
|
93 |
|
94 invokeWith:arg1 with:arg2 with:arg3 |
|
95 self hasCode ifFalse:[ |
|
96 self prepareInvoke. |
|
97 ]. |
|
98 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3) |
|
99 ! |
|
100 |
|
101 invokeWith:arg1 with:arg2 with:arg3 with:arg4 |
|
102 self hasCode ifFalse:[ |
|
103 self prepareInvoke. |
|
104 ]. |
|
105 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3 with:arg4) |
|
106 ! |
|
107 |
|
108 invokeWithArguments:argArray |
|
109 self hasCode ifFalse:[ |
|
110 self prepareInvoke. |
|
111 ]. |
|
112 ^ self invokeFFIWithArguments:argArray |
|
113 ! ! |
|
114 |
|
115 !ExternalLibraryFunction methodsFor:'printing'! |
|
116 |
|
117 printOn:aStream |
|
118 aStream nextPutAll:'<'. |
|
119 callType printOn:aStream. |
|
120 aStream nextPutAll:' '. |
|
121 name printOn:aStream. |
|
122 aStream nextPutAll:' module:'. |
|
123 moduleName printOn:aStream. |
|
124 aStream nextPutAll:'>'. |
71 ! ! |
125 ! ! |
72 |
126 |
73 !ExternalLibraryFunction methodsFor:'private'! |
127 !ExternalLibraryFunction methodsFor:'private'! |
74 |
128 |
75 invokeFFI |
129 invokeFFIWithArguments:arguments |
76 "invoke foreign function interface" |
130 |ffiArgTypes failureCode| |
|
131 |
|
132 argumentTypes notNil ifTrue:[ |
|
133 ffiArgTypes := argumentTypes collect:[:argType | self ffiArgTypeForType:argType]. |
|
134 ]. |
|
135 %{ |
|
136 #if defined(i386) |
|
137 # ifndef STX_FFI_TYPE_VOID |
|
138 # define STX_FFI_TYPE_VOID 0 |
|
139 # define STX_FFI_TYPE_INT 1 |
|
140 # define STX_FFI_TYPE_FLOAT 2 |
|
141 # define STX_FFI_TYPE_DOUBLE 3 |
|
142 # define STX_FFI_TYPE_LONGDOUBLE 4 |
|
143 # define STX_FFI_TYPE_UINT8 5 |
|
144 # define STX_FFI_TYPE_SINT8 6 |
|
145 # define STX_FFI_TYPE_UINT16 7 |
|
146 # define STX_FFI_TYPE_SINT16 8 |
|
147 # define STX_FFI_TYPE_UINT32 9 |
|
148 # define STX_FFI_TYPE_SINT32 10 |
|
149 # define STX_FFI_TYPE_UINT64 11 |
|
150 # define STX_FFI_TYPE_SINT64 12 |
|
151 # define STX_FFI_TYPE_STRUCT 13 |
|
152 # define STX_FFI_TYPE_POINTER 14 |
|
153 |
|
154 # define MAX_NUMARGS 128 |
|
155 typedef void * ffi_type; |
|
156 # endif |
|
157 |
|
158 void *argValues[MAX_NUMARGS]; |
|
159 ffi_type *argtypes[MAX_NUMARGS]; |
|
160 int numArgs; |
|
161 int i; |
|
162 |
|
163 if (arguments == nil) { |
|
164 numArgs = 0; |
|
165 if (ffiArgTypes != nil) { |
|
166 if (! __isArray(ffiArgTypes)) goto error; |
|
167 if (__arraySize(ffiArgTypes) != numArgs) goto error; |
|
168 } |
|
169 } else { |
|
170 if (! __isArray(arguments)) goto error; |
|
171 numArgs = __arraySize(arguments); |
|
172 if (! __isArray(ffiArgTypes)) goto error; |
|
173 if (__arraySize(ffiArgTypes) != numArgs) goto error; |
|
174 } |
|
175 if (numArgs > MAX_NUMARGS) { |
|
176 failureCode = @symbol(TooManyArguments); |
|
177 goto error; |
|
178 } |
|
179 for (i=0; i<numArgs; i++) { |
|
180 switch (__intVal( __ArrayInstPtr(ffiArgTypes)->a_element[i]) ) { |
|
181 case STX_FFI_TYPE_VOID: |
|
182 case STX_FFI_TYPE_INT: |
|
183 case STX_FFI_TYPE_FLOAT: |
|
184 case STX_FFI_TYPE_DOUBLE: |
|
185 case STX_FFI_TYPE_LONGDOUBLE: |
|
186 case STX_FFI_TYPE_UINT8: |
|
187 case STX_FFI_TYPE_SINT8: |
|
188 case STX_FFI_TYPE_UINT16: |
|
189 case STX_FFI_TYPE_SINT16: |
|
190 case STX_FFI_TYPE_UINT32: |
|
191 case STX_FFI_TYPE_SINT32: |
|
192 case STX_FFI_TYPE_UINT64: |
|
193 case STX_FFI_TYPE_SINT64: |
|
194 case STX_FFI_TYPE_STRUCT: |
|
195 case STX_FFI_TYPE_POINTER: |
|
196 default: |
|
197 failureCode = @symbol(UnknownArgumentType); |
|
198 goto error; |
|
199 } |
|
200 } |
|
201 |
|
202 #else |
|
203 argtypes = (ffi_type **)C_alloca(sizeof(ffi_type *) * (n + 3)); |
|
204 argvalues = (void **)C_alloca(sizeof(void *) * (n + 3)); |
|
205 argtypes[ 0 ] = &ffi_type_pointer; |
|
206 argtypes[ 1 ] = &ffi_type_pointer; |
|
207 argtypes[ 2 ] = &ffi_type_pointer; |
|
208 c = n + 2; |
|
209 argvalues[ 0 ] = &c; |
|
210 argvalues[ 1 ] = &fn; |
|
211 argvalues[ 2 ] = &k; |
|
212 |
|
213 for(i = 0; i < n; ++i) { |
|
214 argtypes[ i + 3 ] = &ffi_type_pointer; |
|
215 argvalues[ i + 3 ] = C_temporary_stack_bottom - (i + 1); |
|
216 } |
|
217 |
|
218 C_temporary_stack = C_temporary_stack_bottom; |
|
219 status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, n + 3, &ffi_type_void, argtypes); |
|
220 assert(status == FFI_OK); |
|
221 ffi_call(&cif, (void *)C_block_item(fn, 0), NULL, argvalues); |
|
222 #endif |
|
223 error: ; |
|
224 %} |
77 ! |
225 ! |
78 |
226 |
79 linkToModule |
227 linkToModule |
80 "link this function to the external module. |
228 "link this function to the external module. |
81 I.e. retrieve the module handle and the code pointer." |
229 I.e. retrieve the module handle and the code pointer." |
82 |
230 |
83 |handle code| |
231 |handle code| |
84 |
232 |
85 handle := ObjectFileLoader moduleNamed:moduleName. |
233 moduleName isNil ifTrue:[ |
|
234 self error:'Missing moduleName'. |
|
235 ]. |
|
236 |
|
237 handle := ObjectFileLoader loadDynamicObject:moduleName. |
86 handle isNil ifTrue:[ |
238 handle isNil ifTrue:[ |
87 self error:'cannot load: ', moduleName. |
239 self error:'Cannot load module: ', moduleName. |
88 ]. |
240 ]. |
89 moduleHandle := handle. |
241 moduleHandle := handle. |
90 code := moduleHandle getFunctionAddress:name into:self. |
242 code := moduleHandle getFunctionAddress:name into:self. |
91 code isNil ifTrue:[ |
243 code isNil ifTrue:[ |
92 self error:'cannot load function: ', name, ' in module: ', moduleName. |
244 self error:'Missing function: ', name, ' in module: ', moduleName. |
|
245 ]. |
|
246 ! |
|
247 |
|
248 prepareInvoke |
|
249 self hasCode ifFalse:[ |
|
250 moduleHandle isNil ifTrue:[ |
|
251 self linkToModule. |
|
252 self setupFFI. |
|
253 ]. |
93 ]. |
254 ]. |
94 ! |
255 ! |
95 |
256 |
96 setupFFI |
257 setupFFI |
97 "setup foreign function interface" |
258 "setup foreign function interface" |
98 |
259 |
99 " |
260 "/ %{ |
100 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, |
261 "/ #if defined(WIN32) && defined(i386) |
101 &ffi_type_uint, args) == FFI_OK |
262 "/ /* Have special code for this case - no need to use of ffi code. */ |
102 |
263 "/ #else |
103 " |
264 "/ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args)) != FFI_OK) |
|
265 "/ #endif |
|
266 "/ %} |
104 ! ! |
267 ! ! |
105 |
268 |
106 !ExternalLibraryFunction methodsFor:'private-accessing'! |
269 !ExternalLibraryFunction methodsFor:'private-accessing'! |
107 |
270 |
108 name:functionName module:aModuleName callType:aCallType returnType:aReturnType argumentTypes:argTypes |
271 name:functionName module:aModuleName callType:aCallType returnType:aReturnType argumentTypes:argTypes |