ExternalLibraryFunction.st
author Claus Gittinger <cg@exept.de>
Tue, 25 Apr 2006 12:33:27 +0200
changeset 9322 41c391bfbf03
parent 9321 734c7c432461
child 9324 96279896d95f
permissions -rw-r--r--
*** empty log message ***

"
 COPYRIGHT (c) 2004 by eXept Software AG
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

"{ Package: 'stx:libbasic' }"

ExternalFunction subclass:#ExternalLibraryFunction
	instanceVariableNames:'flags moduleName callType returnType argumentTypes'
	classVariableNames:''
	poolDictionaries:''
	category:'System-Support'
!

!ExternalLibraryFunction primitiveDefinitions!
%{
# include <ffi.h>

# define MAX_ARGS    128

# define STX_FFI_TYPE_VOID              0
# define STX_FFI_TYPE_INT               1
# define STX_FFI_TYPE_FLOAT             2
# define STX_FFI_TYPE_DOUBLE            3
# define STX_FFI_TYPE_LONGDOUBLE        4
# define STX_FFI_TYPE_UINT8             5
# define STX_FFI_TYPE_SINT8             6
# define STX_FFI_TYPE_UINT16            7
# define STX_FFI_TYPE_SINT16            8
# define STX_FFI_TYPE_UINT32            9
# define STX_FFI_TYPE_SINT32            10
# define STX_FFI_TYPE_UINT64            11
# define STX_FFI_TYPE_SINT64            12
# define STX_FFI_TYPE_STRUCT            0x10000        /* + size */
# define STX_FFI_TYPE_STRUCT_SIZE_MASK  0x0FFFF        /* size mask */
# define STX_FFI_TYPE_POINTER           13

%}
! !

!ExternalLibraryFunction class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2004 by eXept Software AG
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

example
"
        |f|

        f := ExternalLibraryFunction new.
        f name:'MessageBeep'
          module:'user32.dll'
          callType:#WINAPI
          returnType:#boolean
          argumentTypes:#(uint).

        f invokeWith:1.
"
! !

!ExternalLibraryFunction class methodsFor:'instance creation'!

name:functionName module:moduleName callType:callType
		  returnType:returnType argumentTypes:argTypes
    ^ self new
	name:functionName module:moduleName callType:callType
	returnType:returnType argumentTypes:argTypes
! !

!ExternalLibraryFunction class methodsFor:'constants'!

callTypeAPI
    ^ #callTypeAPI
!

callTypeC
    ^ #callTypeC
!

callTypeCDecl
    ^ #callTypeCDecl
!

callTypeOLE
    ^ #callTypeOLE
! !

!ExternalLibraryFunction methodsFor:'accessing'!

argumentTypes
    ^ argumentTypes
! !

!ExternalLibraryFunction methodsFor:'invoking'!

invoke
    self hasCode ifFalse:[
	self prepareInvoke.
    ].
    ^ self invokeFFIWithArguments:#()
!

invokeWith:arg
    self hasCode ifFalse:[
	self prepareInvoke.
    ].
    ^ self invokeFFIWithArguments:(Array with:arg)
!

invokeWith:arg1 with:arg2
    self hasCode ifFalse:[
	self prepareInvoke.
    ].
    ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2)
!

invokeWith:arg1 with:arg2 with:arg3
    self hasCode ifFalse:[
	self prepareInvoke.
    ].
    ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3)
!

invokeWith:arg1 with:arg2 with:arg3 with:arg4
    self hasCode ifFalse:[
	self prepareInvoke.
    ].
    ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3 with:arg4)
!

invokeWithArguments:argArray
    self hasCode ifFalse:[
	self prepareInvoke.
    ].
    ^ self invokeFFIWithArguments:argArray
! !

!ExternalLibraryFunction methodsFor:'printing'!

printOn:aStream
    aStream nextPutAll:'<'.
    callType printOn:aStream.
    aStream nextPutAll:' '.
    name printOn:aStream.
    aStream nextPutAll:' module:'.
    moduleName printOn:aStream.
    aStream nextPutAll:'>'.
! !

!ExternalLibraryFunction methodsFor:'private'!

invokeFFIWithArguments:arguments
    |argTypeSymbols returnTypeSymbol failureCode|

    argumentTypes notNil ifTrue:[
        argTypeSymbols := argumentTypes collect:[:argType | self ffiTypeSymbolForType:argType].
    ].
    returnTypeSymbol := self ffiTypeSymbolForType:returnType.

%{
    ffi_type *argTypes[MAX_ARGS];
    union {
        int iVal;
    } argValues[MAX_ARGS];
    void *argValuePointers[MAX_ARGS];
    int numArgs;
    int i;
    static int null = 0;

    if (arguments == nil) {
        numArgs = 0;
        if (argTypeSymbols != nil) {
            if (! __isArray(argTypeSymbols)) goto error;
            if (__arraySize(argTypeSymbols) != numArgs) goto error;
        }
    } else {
        if (! __isArray(arguments)) goto error;
        numArgs = __arraySize(arguments);
        if (! __isArray(argTypeSymbols)) goto error;
        if (__arraySize(argTypeSymbols) != numArgs) goto error;
    }
    if (numArgs > MAX_ARGS) {
        failureCode = @symbol(TooManyArguments);
        goto error;
    }

    for (i=0; i<numArgs; i++) {
        ffi_type *argType;
        void *argValuePtr;
        OBJ typeSymbol;

        typeSymbol = __ArrayInstPtr(argTypeSymbols)->a_element[i];
        if (typeSymbol == @symbol(int)) {
        } else if (typeSymbol == @symbol(void)) {
#if 0
            argType = &ffi_type_void;
#endif
            argValuePtr = &null;
        } else {
            failureCode = @symbol(UnknownArgumentType);
            goto error;
        }

        argTypes[i] = argType;
        argValuePointers[i] = argValuePtr;
    }

# if 0
    /* Initialize the cif */
    CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
                       &ffi_type_sint64, args) == FFI_OK);

    argtypes = (ffi_type **)C_alloca(sizeof(ffi_type *) * (n + 3));
    argvalues = (void **)C_alloca(sizeof(void *) * (n + 3));
    argtypes[ 0 ] = &ffi_type_pointer;
    argtypes[ 1 ] = &ffi_type_pointer;
    argtypes[ 2 ] = &ffi_type_pointer;
    c = n + 2;
    argvalues[ 0 ] = &c;
    argvalues[ 1 ] = &fn;
    argvalues[ 2 ] = &k;

    for(i = 0; i < n; ++i) {
      argtypes[ i + 3 ] = &ffi_type_pointer;
      argvalues[ i + 3 ] = C_temporary_stack_bottom - (i + 1);
    }

    C_temporary_stack = C_temporary_stack_bottom;
    status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, n + 3, &ffi_type_void, argtypes);
    assert(status == FFI_OK);
    ffi_call(&cif, (void *)C_block_item(fn, 0), NULL, argvalues);
# endif

error: ;
%}
!

linkToModule
    "link this function to the external module.
     I.e. retrieve the module handle and the code pointer."

    |handle code|

    moduleName isNil ifTrue:[
	self error:'Missing moduleName'.
    ].

    handle := ObjectFileLoader loadDynamicObject:moduleName.
    handle isNil ifTrue:[
	self error:'Cannot load module: ', moduleName.
    ].
    moduleHandle := handle.
    code := moduleHandle getFunctionAddress:name into:self.
    code isNil ifTrue:[
	self error:'Missing function: ', name, ' in module: ', moduleName.
    ].
!

prepareInvoke
    self hasCode ifFalse:[
	moduleHandle isNil ifTrue:[
	    self linkToModule.
	    self setupFFI.
	].
    ].
!

setupFFI
    "setup foreign function interface"

"/    %{
"/    #if defined(WIN32) && defined(i386)
"/        /* Have special code for this case - no need to use of ffi code. */
"/    #else
"/        if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args)) 
! !

!ExternalLibraryFunction methodsFor:'private-accessing'!

STX_FFI_TYPE_DOUBLE
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_DOUBLE));
%}.

    "
     self new STX_FFI_TYPE_DOUBLE
    "
!

STX_FFI_TYPE_FLOAT
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_FLOAT));
%}.

    "
     self new STX_FFI_TYPE_FLOAT
    "
!

STX_FFI_TYPE_LONGDOUBLE
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_LONGDOUBLE));
%}.

    "
     self new STX_FFI_TYPE_LONGDOUBLE
    "
!

STX_FFI_TYPE_POINTER
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_POINTER));
%}.

    "
     self new STX_FFI_TYPE_POINTER
    "
!

STX_FFI_TYPE_SINT
%{
#if sizeof(int) == 4 
    RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT32));
#endif
#if sizeof(int) == 8 
    RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT64));
#endif
%}.
    self primitiveFailed

    "
     self new STX_FFI_TYPE_SINT
    "
!

STX_FFI_TYPE_SINT16
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT16));
%}.

    "
     self new STX_FFI_TYPE_SINT16
    "
!

STX_FFI_TYPE_SINT32
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT32));
%}.

    "
     self new STX_FFI_TYPE_SINT32
    "
!

STX_FFI_TYPE_SINT64
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT64));
%}.

    "
     self new STX_FFI_TYPE_SINT64
    "
!

STX_FFI_TYPE_SINT8
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT8));
%}.

    "
     self new STX_FFI_TYPE_SINT8
    "
!

STX_FFI_TYPE_STRUCT
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_STRUCT));
%}.

    "
     self new STX_FFI_TYPE_STRUCT
    "
!

STX_FFI_TYPE_STRUCT:size
    ^ self STX_FFI_TYPE_STRUCT + size

    "
     self new STX_FFI_TYPE_STRUCT:0
     self new STX_FFI_TYPE_STRUCT:16 
    "
!

STX_FFI_TYPE_UINT
%{
#if sizeof(int) == 4 
    RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT32));
#endif
#if sizeof(int) == 8 
    RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT64));
#endif
%}.
    self primitiveFailed

    "
     self new STX_FFI_TYPE_UINT
    "
!

STX_FFI_TYPE_UINT16
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT16));
%}.

    "
     self new STX_FFI_TYPE_UINT16
    "
!

STX_FFI_TYPE_UINT64
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT64));
%}.

    "
     self new STX_FFI_TYPE_UINT64
    "
!

STX_FFI_TYPE_UINT8
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT8));
%}.

    "
     self new STX_FFI_TYPE_UINT8
    "
!

STX_FFI_TYPE_VOID
%{
    RETURN(__MKSMALLINT(STX_FFI_TYPE_VOID));
%}

    "
     self new STX_FFI_TYPE_VOID
    "
!

ffiTypeForType:aType
    "/ kludge

    aType isSymbol ifTrue:[
        "/ for those who do not have the CType package...
        aType == #int ifTrue:[ ^ self STX_FFI_TYPE_INT ].
        aType == #uint ifTrue:[ ^ self STX_FFI_TYPE_UINT ].
        aType == #short ifTrue:[ ^ self STX_FFI_TYPE_SHORT ].
        aType == #ushort ifTrue:[ ^ self STX_FFI_TYPE_USHORT ].
        aType == #long ifTrue:[ ^ self STX_FFI_TYPE_LONG ].
        aType == #ulong ifTrue:[ ^ self STX_FFI_TYPE_ULONG ].
        aType == #float ifTrue:[ ^ self STX_FFI_TYPE_FLOAT ].
        aType == #double ifTrue:[ ^ self STX_FFI_TYPE_DOUBLE ].
        aType == #void ifTrue:[ ^ self STX_FFI_TYPE_VOID ].
        self error:'unknown type'.
    ].
    self error:'unknown type'.
!

ffiTypeSymbolForType:aType
    "/ kludge for those who do not have the CType package...
    aType isSymbol ifTrue:[ ^ aType ].
    CType isNil ifTrue:[
        self error:'unknown type'.
    ].
    ^ aType typeSymbol
!

name:functionName module:aModuleName callType:aCallType returnType:aReturnType argumentTypes:argTypes
    name := functionName.
    moduleName := aModuleName.
    callType := aCallType.
    returnType := aReturnType.
    argumentTypes := argTypes.
! !

!ExternalLibraryFunction class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.6 2006-04-25 10:33:27 cg Exp $'
! !