--- a/ExternalLibraryFunction.st Tue May 02 19:34:14 2006 +0200
+++ b/ExternalLibraryFunction.st Wed May 03 00:13:59 2006 +0200
@@ -128,6 +128,41 @@
^ self invokeFFIWithArguments:#()
!
+invokeVirtualOn:anInstance
+ self hasCode ifFalse:[
+ self prepareInvoke.
+ ].
+ ^ self invokeVirtualFFIOn:anInstance withArguments:#()
+!
+
+invokeVirtualOn:instance with:arg
+ self hasCode ifFalse:[
+ self prepareInvoke.
+ ].
+ ^ self invokeVirtualFFIOn:instance withArguments:(Array with:arg)
+!
+
+invokeVirtualOn:instance with:arg1 with:arg2
+ self hasCode ifFalse:[
+ self prepareInvoke.
+ ].
+ ^ self invokeVirtualFFIOn:instance withArguments:(Array with:arg1 with:arg2)
+!
+
+invokeVirtualOn:instance with:arg1 with:arg2 with:arg3
+ self hasCode ifFalse:[
+ self prepareInvoke.
+ ].
+ ^ self invokeVirtualFFIOn:instance withArguments:(Array with:arg1 with:arg2 with:arg3)
+!
+
+invokeVirtualOn:instance with:arg1 with:arg2 with:arg3 with:arg4
+ self hasCode ifFalse:[
+ self prepareInvoke.
+ ].
+ ^ self invokeVirtualFFIOn:instance withArguments:(Array with:arg1 with:arg2 with:arg3 with:arg4)
+!
+
invokeWith:arg
self hasCode ifFalse:[
self prepareInvoke.
@@ -531,6 +566,361 @@
].
!
+invokeVirtualFFIOn:instance withArguments:arguments
+ |argTypeSymbols returnTypeSymbol failureCode|
+
+ argumentTypes notNil ifTrue:[
+ argTypeSymbols := argumentTypes collect:[:argType | self ffiTypeSymbolForType:argType].
+ ].
+ returnTypeSymbol := self ffiTypeSymbolForType:returnType.
+self halt:'unfinished'.
+
+%{ /* UNLIMITEDSTACK */
+#ifdef HAVE_FFI
+ ffi_cif __cif;
+ ffi_type *__argTypes[MAX_ARGS];
+ ffi_type *__returnType = NULL;
+ union u {
+ int iVal;
+ float fVal;
+ double dVal;
+ void *pointerVal;
+ };
+ union u __argValues[MAX_ARGS];
+ union u __returnValue;
+ void *__argValuePointers[MAX_ARGS];
+ void *__returnValuePointer;
+ int __numArgs;
+ static int null = 0;
+ int i;
+ ffi_abi __callType = FFI_DEFAULT_ABI;
+
+ if (arguments == nil) {
+ __numArgs = 0;
+ if (argTypeSymbols != nil) {
+ if (! __isArray(argTypeSymbols)
+ || (__arraySize(argTypeSymbols) != __numArgs)) {
+ failureCode = @symbol(ArgumentCountMismatch);
+ goto error;
+ }
+ }
+ } else {
+ if (! __isArray(arguments)
+ || ! __isArray(argTypeSymbols)
+ || (__arraySize(argTypeSymbols) != (__numArgs = __arraySize(arguments)))) {
+ failureCode = @symbol(ArgumentCountMismatch);
+ goto error;
+ }
+ }
+ if (__numArgs > MAX_ARGS) {
+ failureCode = @symbol(TooManyArguments);
+ goto error;
+ }
+
+ /*
+ * validate the return type
+ */
+ __returnValuePointer = &__returnValue;
+ if (returnTypeSymbol == @symbol(int)) {
+ __returnType = __get_ffi_type_sint();
+ } else if (returnTypeSymbol == @symbol(uint)) {
+ __returnType = __get_ffi_type_uint();
+ } else if (returnTypeSymbol == @symbol(long)) {
+ if (sizeof(long) == 4) {
+ __returnType = __get_ffi_type_sint32();
+ } else if (sizeof(long) == 8) {
+ __returnType = __get_ffi_type_sint64();
+ } else {
+ failureCode = @symbol(UnknownReturnType);
+ goto error;
+ }
+ } else if (returnTypeSymbol == @symbol(ulong)) {
+ if (sizeof(long) == 4) {
+ __returnType = __get_ffi_type_uint32();
+ }else if (sizeof(long) == 8) {
+ __returnType = __get_ffi_type_uint64();
+ } else {
+ failureCode = @symbol(UnknownReturnType);
+ goto error;
+ }
+ } else if (returnTypeSymbol == @symbol(boolean)) {
+ __returnType = __get_ffi_type_uint();
+ } else if (returnTypeSymbol == @symbol(uint8)) {
+ __returnType = __get_ffi_type_uint8();
+ } else if (returnTypeSymbol == @symbol(sint8)) {
+ __returnType = __get_ffi_type_sint8();
+ } else if (returnTypeSymbol == @symbol(uint16)) {
+ __returnType = __get_ffi_type_uint16();
+ } else if (returnTypeSymbol == @symbol(sint16)) {
+ __returnType = __get_ffi_type_sint16();
+ } else if (returnTypeSymbol == @symbol(float)) {
+ __returnType = __get_ffi_type_float();
+ } else if (returnTypeSymbol == @symbol(double)) {
+ __returnType = __get_ffi_type_double();
+ } else if (returnTypeSymbol == @symbol(void)) {
+ __returnType = __get_ffi_type_void();
+ __returnValuePointer = NULL;
+ } else if (returnTypeSymbol == @symbol(pointer)) {
+ __returnType = __get_ffi_type_pointer();
+ } else {
+ failureCode = @symbol(UnknownReturnType);
+ goto error;
+ }
+
+ /*
+ * validate all arg types and setup arg-buffers
+ */
+ for (i=0; i<__numArgs; i++) {
+ ffi_type *thisType;
+ void *argValuePtr;
+ OBJ typeSymbol;
+ OBJ arg;
+
+ typeSymbol = __ArrayInstPtr(argTypeSymbols)->a_element[i];
+ arg = __ArrayInstPtr(arguments)->a_element[i];
+
+ if (typeSymbol == @symbol(long)) {
+ if (sizeof(long) == sizeof(int)) {
+ typeSymbol = @symbol(sint);
+ } else {
+ if (sizeof(long) == 4) {
+ typeSymbol = @symbol(sint32);
+ } else if (sizeof(long) == 8) {
+ typeSymbol = @symbol(sint64);
+ }
+ }
+ }
+ if (typeSymbol == @symbol(ulong)) {
+ if (sizeof(unsigned long) == sizeof(unsigned int)) {
+ typeSymbol = @symbol(uint);
+ } else {
+ if (sizeof(long) == 4) {
+ typeSymbol = @symbol(uint32);
+ } else if (sizeof(long) == 8) {
+ typeSymbol = @symbol(uint64);
+ }
+ }
+ }
+
+ if (typeSymbol == @symbol(int)) {
+ thisType = __get_ffi_type_sint();
+ if (__isSmallInteger(arg)) {
+ __argValues[i].iVal = __intVal(arg);
+ } else {
+ __argValues[i].iVal = __signedLongIntVal(arg);
+ if (__argValues[i].iVal == 0) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ }
+ argValuePtr = &(__argValues[i].iVal);
+ } else if (typeSymbol == @symbol(uint)) {
+ thisType = __get_ffi_type_uint();
+
+ if (__isSmallInteger(arg)) {
+ __argValues[i].iVal = __intVal(arg);
+ } else {
+ __argValues[i].iVal = __unsignedLongIntVal(arg);
+ if (__argValues[i].iVal == 0) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ }
+ argValuePtr = &(__argValues[i].iVal);
+ } else if (typeSymbol == @symbol(uint8)) {
+ thisType = __get_ffi_type_uint8();
+ if (! __isSmallInteger(arg)) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ __argValues[i].iVal = __intVal(arg);
+ if (((unsigned)(__argValues[i].iVal)) > 0xFF) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ argValuePtr = &(__argValues[i].iVal);
+ } else if (typeSymbol == @symbol(sint8)) {
+ thisType = __get_ffi_type_sint8();
+ if (! __isSmallInteger(arg)) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ __argValues[i].iVal = __intVal(arg);
+ if (((__argValues[i].iVal) < -0x80) || ((__argValues[i].iVal) > 0x7F)) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ argValuePtr = &(__argValues[i].iVal);
+ } else if (typeSymbol == @symbol(uint16)) {
+ thisType = __get_ffi_type_uint16();
+ if (! __isSmallInteger(arg)) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ __argValues[i].iVal = __intVal(arg);
+ if (((unsigned)(__argValues[i].iVal)) > 0xFFFF) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ argValuePtr = &(__argValues[i].iVal);
+ } else if (typeSymbol == @symbol(sint16)) {
+ thisType = __get_ffi_type_sint16();
+ if (! __isSmallInteger(arg)) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ __argValues[i].iVal = __intVal(arg);
+ if (((__argValues[i].iVal) < -0x8000) || ((__argValues[i].iVal) > 0x7FFF)) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ argValuePtr = &(__argValues[i].iVal);
+ } else if (typeSymbol == @symbol(float)) {
+ thisType = __get_ffi_type_float();
+ if (__isSmallInteger(arg)) {
+ __argValues[i].fVal = (float)(__intVal(arg));
+ } else if (__isFloat(arg)) {
+ __argValues[i].fVal = (float)(__floatVal(arg));
+ } else if (__isShortFloat(arg)) {
+ __argValues[i].fVal = (float)(__shortFloatVal(arg));
+ } else {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ argValuePtr = &(__argValues[i].fVal);
+ } else if (typeSymbol == @symbol(double)) {
+ thisType = __get_ffi_type_double();
+ if (__isSmallInteger(arg)) {
+ __argValues[i].dVal = (double)(__intVal(arg));
+ } else if (__isFloat(arg)) {
+ __argValues[i].dVal = (double)(__floatVal(arg));
+ } else if (__isShortFloat(arg)) {
+ __argValues[i].dVal = (double)(__shortFloatVal(arg));
+ } else {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ argValuePtr = &(__argValues[i].dVal);
+ } else if (typeSymbol == @symbol(void)) {
+ thisType = __get_ffi_type_void();
+ argValuePtr = &null;
+ } else if (typeSymbol == @symbol(pointer)) {
+ thisType = __get_ffi_type_pointer();
+ if (__isExternalAddressLike(arg)) {
+ __argValues[i].pointerVal = (void *)(__externalAddressVal(arg));
+ } else if (__isExternalBytesLike(arg)) {
+ __argValues[i].pointerVal = (void *)(__externalBytesVal(arg));
+ } else if (__isByteArray(arg)) {
+ __argValues[i].pointerVal = (void *)(__byteArrayVal(arg));
+ } else if (__isFloatArray(arg)) {
+ __argValues[i].pointerVal = (void *)(__FloatArrayInstPtr(arg)->f_element);
+ } else if (__isDoubleArray(arg)) {
+ __argValues[i].pointerVal = (void *)(__DoubleArrayInstPtr(arg)->d_element);
+ } else if (__isString(arg) || __isSymbol(arg)) {
+ __argValues[i].pointerVal = (void *)(__stringVal(arg));
+ } else {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ argValuePtr = &(__argValues[i].pointerVal);;
+ } else if (typeSymbol == @symbol(boolean)) {
+ thisType = __get_ffi_type_uint();
+
+ if (arg == true) {
+ __argValues[i].iVal = 1;
+ } else if (arg == false) {
+ __argValues[i].iVal = 0;
+ } else if (__isSmallInteger(arg)) {
+ __argValues[i].iVal = __intVal(arg);
+ } else {
+ __argValues[i].iVal = __unsignedLongIntVal(arg);
+ if (__argValues[i].iVal == 0) {
+ failureCode = @symbol(InvalidArgument);
+ goto error;
+ }
+ }
+ argValuePtr = &(__argValues[i].iVal);
+ } else {
+ failureCode = @symbol(UnknownArgumentType);
+ goto error;
+ }
+
+ __argTypes[i] = thisType;
+ __argValuePointers[i] = argValuePtr;
+ }
+
+ __callType = FFI_DEFAULT_ABI;
+
+#ifdef CALLTYPE_FFI_STDCALL
+ if ((__INST(callType) == @symbol(callTypeAPI))
+ || (__INST(callType) == @symbol(WINAPI))
+ || (__INST(callType) == @symbol(STDCALL))) {
+ __callType = CALLTYPE_FFI_STDCALL;
+ }
+#endif
+#ifdef CALLTYPE_FFI_V8
+ if ((__INST(callType) == @symbol(callTypeV8))
+ || (__INST(callType) == @symbol(V8))) {
+ __callType = CALLTYPE_FFI_V8;
+ }
+#endif
+#ifdef CALLTYPE_FFI_V9
+ if ((__INST(callType) == @symbol(callTypeV9))
+ || (__INST(callType) == @symbol(V9))) {
+ __callType = CALLTYPE_FFI_V9;
+ }
+#endif
+#ifdef CALLTYPE_FFI_UNIX64
+ if ((__INST(callType) == @symbol(callTypeUnix64))
+ || (__INST(callType) == @symbol(UNIX64))) {
+ __callType = CALLTYPE_FFI_UNIX64;
+ }
+#endif
+
+ if (ffi_prep_cif(&__cif, __callType, __numArgs, __returnType, __argTypes) != FFI_OK) {
+ failureCode = @symbol(FFIPrepareFailed);
+ goto error;
+ }
+ ffi_call(&__cif, (VOIDFUNC)__INST(code_), __returnValuePointer, __argValuePointers);
+
+ if ((returnTypeSymbol == @symbol(int))
+ || (returnTypeSymbol == @symbol(int8))
+ || (returnTypeSymbol == @symbol(int16))) {
+ RETURN ( __MKINT(__returnValue.iVal) );
+ }
+ if ((returnTypeSymbol == @symbol(uint))
+ || (returnTypeSymbol == @symbol(uint8))
+ || (returnTypeSymbol == @symbol(uint16))) {
+ RETURN ( __MKUINT(__returnValue.iVal) );
+ }
+ if (returnTypeSymbol == @symbol(boolean)) {
+ RETURN ( __returnValue.iVal ? true : false );
+ }
+ if (returnTypeSymbol == @symbol(float)) {
+ RETURN ( __MKFLOAT(__returnValue.fVal ));
+ }
+ if (returnTypeSymbol == @symbol(double)) {
+ RETURN ( __MKFLOAT(__returnValue.dVal ));
+ }
+ if (returnTypeSymbol == @symbol(void)) {
+ RETURN ( nil );
+ }
+ if (returnTypeSymbol == @symbol(pointer)) {
+printf("returnvalue: %x\n", __returnValue.pointerVal);
+ RETURN ( __MKEXTERNALADDRESS(__returnValue.pointerVal) );
+ }
+ failureCode = @symbol(UnknownReturnType2);
+error: ;
+
+#else /* no FFI support */
+ failureCode = @symbol(FFINotSupported);
+#endif /* HAVE_FFI */
+%}.
+ failureCode notNil ifTrue:[
+ self primitiveFailed
+ ].
+!
+
linkToModule
"link this function to the external module.
I.e. retrieve the module handle and the code pointer."
@@ -551,8 +941,10 @@
].
moduleHandle := handle.
].
- (moduleHandle getFunctionAddress:name into:self) isNil ifTrue:[
- self error:'Missing function: ', name, ' in module: ', moduleName.
+ name isNumber ifFalse:[
+ (moduleHandle getFunctionAddress:name into:self) isNil ifTrue:[
+ self error:'Missing function: ', name, ' in module: ', moduleName.
+ ]
].
!
@@ -600,5 +992,5 @@
!ExternalLibraryFunction class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.16 2006-05-02 17:34:14 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.17 2006-05-02 22:13:59 cg Exp $'
! !