ExternalLibraryFunction.st
changeset 9341 719fcf48695b
parent 9340 df61c7e20801
child 9342 e548ce80ab02
--- 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 $'
 ! !