virtual calls
authorClaus Gittinger <cg@exept.de>
Fri, 05 May 2006 11:40:18 +0200
changeset 9342 e548ce80ab02
parent 9341 719fcf48695b
child 9343 0c2dcef80d03
virtual calls
ExternalLibraryFunction.st
--- a/ExternalLibraryFunction.st	Wed May 03 00:13:59 2006 +0200
+++ b/ExternalLibraryFunction.st	Fri May 05 11:40:18 2006 +0200
@@ -212,715 +212,6 @@
 
 !ExternalLibraryFunction methodsFor:'private'!
 
-invokeFFIWithArguments:arguments
-    |argTypeSymbols returnTypeSymbol failureCode|
-
-    argumentTypes notNil ifTrue:[
-        argTypeSymbols := argumentTypes collect:[:argType | self ffiTypeSymbolForType:argType].
-    ].
-    returnTypeSymbol := self ffiTypeSymbolForType:returnType.
-
-%{  /* 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
-    ].
-!
-
-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."
@@ -989,8 +280,431 @@
     argumentTypes := argTypes.
 ! !
 
+!ExternalLibraryFunction methodsFor:'private-invoking'!
+
+invokeFFIWithArguments:arguments
+    ^ self invokeFFIwithArguments:arguments virtualCallFor:nil
+!
+
+invokeFFIwithArguments:arguments virtualCallFor:aCPlusPlusObjectOrNil 
+    |argTypeSymbols returnTypeSymbol failureCode returnValue stClass vtOffset|
+
+    argumentTypes notNil ifTrue:[
+        argTypeSymbols := argumentTypes collect:[:argType | self ffiTypeSymbolForType:argType].
+    ].
+    returnTypeSymbol := self ffiTypeSymbolForType:returnType.
+    aCPlusPlusObjectOrNil notNil ifTrue:[
+        "/ it must be a kind of ExternalStructure !!
+        (aCPlusPlusObjectOrNil isKindOf:ExternalStructure) ifFalse:[
+            self primitiveFailed.
+        ].
+        vtOffset := name.
+        (vtOffset between:0 and:10000) ifFalse:[
+            self primitiveFailed.
+        ].
+    ].
+
+%{  /* UNLIMITEDSTACK */
+#ifdef HAVE_FFI   
+    ffi_cif __cif;
+    ffi_type *__argTypesIncludingThis[MAX_ARGS+1];
+    ffi_type **__argTypes = __argTypesIncludingThis;
+    ffi_type *__returnType = NULL;
+    union u {
+        int iVal;
+        float fVal;
+        double dVal;
+        void *pointerVal;
+    };
+    union u __argValuesIncludingThis[MAX_ARGS+1];
+    union u *__argValues = __argValuesIncludingThis;
+    union u __returnValue;
+    void *__argValuePointersIncludingThis[MAX_ARGS+1];
+    void **__argValuePointers = __argValuePointersIncludingThis;
+    void *__returnValuePointer;
+    int __numArgs, __numArgsIncludingThis;
+    static int null = 0;
+    int i;
+    ffi_abi __callType = FFI_DEFAULT_ABI;
+    VOIDFUNC codeAddress = (VOIDFUNC)__INST(code_);
+
+    if (arguments == nil) {
+        __numArgs = 0;
+        if (argTypeSymbols != nil) {
+            if (! __isArray(argTypeSymbols)
+             || (__arraySize(argTypeSymbols) != __numArgs)) {
+                failureCode = @symbol(ArgumentCountMismatch);
+                goto getOutOfHere;
+            }
+        }
+    } else {
+        if (! __isArray(arguments)
+         || ! __isArray(argTypeSymbols)
+         || (__arraySize(argTypeSymbols) != (__numArgs = __arraySize(arguments)))) {
+            failureCode = @symbol(ArgumentCountMismatch);
+            goto getOutOfHere;
+        }
+    }
+    if (__numArgs > MAX_ARGS) {
+        failureCode = @symbol(TooManyArguments);
+        goto getOutOfHere;
+    }
+
+    /*
+     * 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 getOutOfHere;
+        }
+    } 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 getOutOfHere;
+        }
+    } 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 getOutOfHere;
+    }
+
+    /*
+     * validate the c++ object
+     */
+    if (aCPlusPlusObjectOrNil != nil) {
+        struct cPlusPlusInstance {
+            void **vTable;
+        };
+        struct cPlusPlusInstance *inst;
+
+        if (__isExternalAddressLike(aCPlusPlusObjectOrNil)) {
+            inst = (void *)(__externalAddressVal(aCPlusPlusObjectOrNil));
+        } else if (__isExternalBytesLike(aCPlusPlusObjectOrNil)) {
+            inst = (void *)(__externalBytesVal(aCPlusPlusObjectOrNil));
+        } else {
+            failureCode = @symbol(InvalidInstance);
+            goto getOutOfHere;
+        }
+        __argValues[0].pointerVal = inst;
+        __argValuePointersIncludingThis[0] = &(__argValues[0]);
+        __argTypes[0] = __get_ffi_type_pointer();
+
+        codeAddress = inst->vTable[__intVal(vtOffset)];
+
+        __argValuePointers = &__argValuePointersIncludingThis[1];
+        __argTypes = &__argTypesIncludingThis[1];
+        __argValues = &__argValuesIncludingThis[1];
+        __numArgsIncludingThis = __numArgs + 1;
+    } else {
+        __numArgsIncludingThis = __numArgs;
+    }
+
+    /*
+     * 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 getOutOfHere;
+                }
+            }
+            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 getOutOfHere;
+                }
+            }
+            argValuePtr = &(__argValues[i].iVal);
+        } else if (typeSymbol == @symbol(uint8)) {
+            thisType = __get_ffi_type_uint8();
+            if (! __isSmallInteger(arg)) {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            __argValues[i].iVal = __intVal(arg);
+            if (((unsigned)(__argValues[i].iVal)) > 0xFF) {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            argValuePtr = &(__argValues[i].iVal);
+        } else if (typeSymbol == @symbol(sint8)) {
+            thisType = __get_ffi_type_sint8();
+            if (! __isSmallInteger(arg)) {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            __argValues[i].iVal = __intVal(arg);
+            if (((__argValues[i].iVal) < -0x80) || ((__argValues[i].iVal) > 0x7F))  {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            argValuePtr = &(__argValues[i].iVal);
+        } else if (typeSymbol == @symbol(uint16)) {
+            thisType = __get_ffi_type_uint16();
+            if (! __isSmallInteger(arg)) {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            __argValues[i].iVal = __intVal(arg);
+            if (((unsigned)(__argValues[i].iVal)) > 0xFFFF) {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            argValuePtr = &(__argValues[i].iVal);
+        } else if (typeSymbol == @symbol(sint16)) {
+            thisType = __get_ffi_type_sint16();
+            if (! __isSmallInteger(arg)) {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            __argValues[i].iVal = __intVal(arg);
+            if (((__argValues[i].iVal) < -0x8000) || ((__argValues[i].iVal) > 0x7FFF))  {
+                failureCode = @symbol(InvalidArgument);
+                goto getOutOfHere;
+            }
+            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 getOutOfHere;
+            }
+            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 getOutOfHere;
+            }
+            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 getOutOfHere;
+            }
+            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 getOutOfHere;
+                }
+            }
+            argValuePtr = &(__argValues[i].iVal);
+        } else {
+            failureCode = @symbol(UnknownArgumentType);
+            goto getOutOfHere;
+        }
+
+        __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, __numArgsIncludingThis, __returnType, __argTypesIncludingThis) != FFI_OK) {
+        failureCode = @symbol(FFIPrepareFailed);
+        goto getOutOfHere;
+    }
+    ffi_call(&__cif, codeAddress, __returnValuePointer, __argValuePointersIncludingThis);
+
+    if ((returnTypeSymbol == @symbol(int))
+     || (returnTypeSymbol == @symbol(int8))
+     || (returnTypeSymbol == @symbol(int16))
+     || (returnTypeSymbol == @symbol(int32))) {
+        RETURN ( __MKINT(__returnValue.iVal) );
+    }
+    if ((returnTypeSymbol == @symbol(uint))
+     || (returnTypeSymbol == @symbol(uint8))
+     || (returnTypeSymbol == @symbol(uint16))
+     || (returnTypeSymbol == @symbol(uint32))) {
+        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)) {
+        returnValue = __MKEXTERNALADDRESS(__returnValue.pointerVal);
+    } else {
+        failureCode = @symbol(UnknownReturnType2);
+    }
+getOutOfHere: ;
+
+#else /* no FFI support */
+    failureCode = @symbol(FFINotSupported);
+#endif /* HAVE_FFI */
+%}.
+    failureCode notNil ifTrue:[
+        self primitiveFailed.
+        ^ nil
+    ].
+
+    returnType isCPointer ifTrue:[
+        returnType baseType isCStruct ifTrue:[
+            stClass := Smalltalk classNamed:returnType baseType name.
+            (stClass notNil and:[stClass isSubclassOf:ExternalStructure]) ifTrue:[
+                returnValue changeClassTo:stClass.
+            ].
+        ]
+    ].
+
+    ^ returnValue
+!
+
+invokeVirtualFFIOn:instance withArguments:arguments
+    ^ self invokeFFIwithArguments:arguments virtualCallFor:instance
+! !
+
 !ExternalLibraryFunction class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.17 2006-05-02 22:13:59 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.18 2006-05-05 09:40:18 cg Exp $'
 ! !