SimpleExternalLibraryFunction.st
changeset 19551 1cec0dc778a4
child 20307 678da26adf03
equal deleted inserted replaced
19550:0341c4074b6c 19551:1cec0dc778a4
       
     1 "{ Package: 'stx:libbasic' }"
       
     2 
       
     3 "{ NameSpace: Smalltalk }"
       
     4 
       
     5 ExternalLibraryFunction subclass:#SimpleExternalLibraryFunction
       
     6 	instanceVariableNames:''
       
     7 	classVariableNames:''
       
     8 	poolDictionaries:''
       
     9 	category:'System-Support'
       
    10 !
       
    11 
       
    12 !SimpleExternalLibraryFunction class methodsFor:'documentation'!
       
    13 
       
    14 documentation
       
    15 "
       
    16     instances of me are used for very simple functions, with all integer or
       
    17     equivalent arguments.
       
    18     These avoid the realively expensive ffi- arg setup, and jump directly to the
       
    19     target function.
       
    20     Can be used for a subset of all external functions and only on some machines.
       
    21     Only for tuning; the superclass must provide a fallback for all calls
       
    22 "
       
    23 ! !
       
    24 
       
    25 !SimpleExternalLibraryFunction methodsFor:'private invoking'!
       
    26 
       
    27 invokeFFIwithArguments:argumentsOrNil forCPPInstance:aReceiverOrNil
       
    28     "the caller must have already checked, if instances of me are appropriate.
       
    29      May only be used for up to 10 args, with INT-sized non-float, non-struct arguments,
       
    30      and int-sized, non-float, non-struct return value.
       
    31      Now, all I do is convert the arguments and transfer directly; without the expensive ffi..."
       
    32 
       
    33     |argTypeSymbols returnTypeSymbol failureCode failureArgNr failureInfo returnValue stClass vtOffset
       
    34      virtual objectiveC async unlimitedStack callTypeNumber returnValueClass argValueClass
       
    35      oldReturnType oldArgumentTypes|
       
    36 
       
    37     virtual := self isVirtualCPP.
       
    38     objectiveC := self isObjectiveC.
       
    39     (virtual "or:[self isNonVirtualCPP]") ifTrue:[
       
    40         aReceiverOrNil isNil ifTrue:[
       
    41             "/ must have a c++ object instance
       
    42             self primitiveFailed.
       
    43         ].
       
    44 
       
    45         "/ and it must be a kind of ExternalStructure !!
       
    46         (aReceiverOrNil isExternalStructure) ifFalse:[
       
    47             self primitiveFailed.
       
    48         ].
       
    49         virtual ifTrue:[
       
    50             vtOffset := name.
       
    51         ].
       
    52     ] ifFalse:[
       
    53         objectiveC ifTrue:[
       
    54             aReceiverOrNil isNil ifTrue:[
       
    55                 "/ must have an objective-c object instance
       
    56                 self primitiveFailed.
       
    57             ].
       
    58             (aReceiverOrNil isObjectiveCObject) ifFalse:[
       
    59                 self primitiveFailed
       
    60             ]
       
    61         ] ifFalse:[
       
    62             aReceiverOrNil notNil ifTrue:[
       
    63                 "/ must NOT have a c++/objectiveC object instance
       
    64                 self primitiveFailed.
       
    65             ]
       
    66         ].
       
    67     ].
       
    68 
       
    69 %{  /* STACK: 100000 */
       
    70 
       
    71 #define VERBOSE
       
    72 #define MAX_ARGS 10
       
    73 
       
    74     int __numArgs, __numArgsIncludingThis;
       
    75     static INT null = 0;
       
    76     INT __args[MAX_ARGS+1];
       
    77     INT retVal;
       
    78     int i = -1;
       
    79     int argIdx = 0;
       
    80     INTFUNC codeAddress = (VOIDFUNC)__INST(code_);
       
    81     int __numArgsWanted;
       
    82 
       
    83 #   define __FAIL__(fcode) \
       
    84     { \
       
    85         failureCode = fcode; failureArgNr = __mkSmallInteger(i+1); goto getOutOfHere; \
       
    86     }
       
    87 
       
    88     if (argumentsOrNil == nil) {
       
    89         __numArgs = 0;
       
    90     } else if (__isArray(argumentsOrNil)) {
       
    91         __numArgs = __arraySize(argumentsOrNil);
       
    92     } else {
       
    93         __FAIL__(@symbol(BadArgumentVector))
       
    94     }
       
    95     if (__numArgs != __numArgsWanted) {
       
    96         __FAIL__(@symbol(ArgumentCountMismatch))
       
    97     }
       
    98     if (__numArgs > MAX_ARGS) {
       
    99         __FAIL__(@symbol(TooManyArguments))
       
   100     }
       
   101 
       
   102     /*
       
   103      * validate the c++ object
       
   104      */
       
   105     if (aReceiverOrNil != nil) {
       
   106         struct cPlusPlusInstance {
       
   107             void **vTable;
       
   108         };
       
   109         struct cPlusPlusInstance *inst;
       
   110 
       
   111         if (__isExternalAddressLike(aReceiverOrNil)) {
       
   112             inst = (void *)(__externalAddressVal(aReceiverOrNil));
       
   113         } else if (__isExternalBytesLike(aReceiverOrNil)) {
       
   114             inst = (void *)(__externalBytesVal(aReceiverOrNil));
       
   115         } else {
       
   116             __FAIL__(@symbol(InvalidInstance))
       
   117         }
       
   118         __args[0] = (INT)inst;
       
   119         __numArgsIncludingThis = __numArgs + 1;
       
   120         argIdx = 1;
       
   121 
       
   122         if (virtual == true) {
       
   123             if (! __isSmallInteger(vtOffset)) {
       
   124                 __FAIL__(@symbol(InvalidVTableIndex))
       
   125             }
       
   126             codeAddress = inst->vTable[__intVal(vtOffset)];
       
   127 # ifdef VERBOSE
       
   128             if (@global(Verbose) == true) {
       
   129                 printf("virtual %d codeAddress: %"_lx_"\n", __intVal(vtOffset), (INT)codeAddress);
       
   130             }
       
   131 # endif
       
   132         }
       
   133     } else {
       
   134         __numArgsIncludingThis = __numArgs;
       
   135 # ifdef VERBOSE
       
   136         if (@global(Verbose) == true) {
       
   137             printf("codeAddress: %"_lx_"\n", (INT)codeAddress);
       
   138         }
       
   139 # endif
       
   140     }
       
   141 
       
   142     /*
       
   143      * validate all arg types, map each to an ffi_type, and setup arg-buffers
       
   144      */
       
   145     for (i=0; i<__numArgs; i++, argIdx++) {
       
   146         OBJ arg;
       
   147 
       
   148         failureInfo = __mkSmallInteger(i+1);   /* in case there is one */
       
   149 
       
   150         arg = __ArrayInstPtr(argumentsOrNil)->a_element[i];
       
   151 
       
   152         if (__isSmallInteger(arg)) {
       
   153             __args[argIdx] = __intVal(arg);
       
   154         } else {
       
   155            INT iv = __signedLongIntVal(arg);
       
   156            if (iv != 0) {
       
   157                 __args[argIdx]  = iv;
       
   158             } else {
       
   159                 unsigned INT iv = __unsignedLongIntVal(arg);
       
   160                 if (iv != 0) {
       
   161                     __args[argIdx] = iv;
       
   162                 } else {
       
   163                     if (__isStringLike(arg)) {
       
   164                         __args[argIdx] = (INT)(__stringVal(arg));
       
   165                     } else {
       
   166                         if (__isBytes(arg)) {
       
   167                             __args[argIdx] = (INT)(__byteArrayVal(arg));
       
   168                             if (arg == NULL) {
       
   169                                 __args[argIdx] = (INT)0;
       
   170                             } else {
       
   171                                 if (__isExternalAddressLike(arg)) {
       
   172                                     __args[argIdx] = (INT)(__externalAddressVal(arg));
       
   173                                 } else {
       
   174                                     if (__isExternalBytesLike(arg)) {
       
   175                                         __args[argIdx] = (INT)(__externalBytesVal(arg));
       
   176                                     } else {
       
   177                                         __FAIL__(@symbol(InvalidArgument))
       
   178                                     }
       
   179                                 }
       
   180                             }
       
   181                         }
       
   182                     }
       
   183                 }
       
   184             }
       
   185         }
       
   186     }
       
   187     failureInfo = nil;
       
   188 
       
   189     retVal = (*codeAddress)(__args[0], __args[1], __args[2], __args[3], __args[4], __args[5], __args[6],
       
   190                             __args[7], __args[8], __args[9], __args[10]);
       
   191 
       
   192 # ifdef VERBOSE
       
   193     if (@global(Verbose) == true) {
       
   194         printf("retval is %"_ld_" (0x%"_lx_")\n", retVal, retVal);
       
   195     }
       
   196 # endif
       
   197 
       
   198     if ((returnTypeSymbol == @symbol(int))
       
   199      || (returnTypeSymbol == @symbol(sint))
       
   200      || (returnTypeSymbol == @symbol(sint8))
       
   201      || (returnTypeSymbol == @symbol(sint16))
       
   202      || (returnTypeSymbol == @symbol(sint32))) {
       
   203 # ifdef VERBOSE
       
   204         if (@global(Verbose) == true) {
       
   205             printf("return int: %x\n", retVal);
       
   206         }
       
   207 # endif
       
   208         RETURN ( __MKINT(retVal) );
       
   209     }
       
   210     if ((returnTypeSymbol == @symbol(uint))
       
   211      || (returnTypeSymbol == @symbol(uint8))
       
   212      || (returnTypeSymbol == @symbol(uint16))
       
   213      || (returnTypeSymbol == @symbol(uint32))) {
       
   214 # ifdef VERBOSE
       
   215         if (@global(Verbose) == true) {
       
   216             printf("return uint: %x\n", retVal);
       
   217         }
       
   218 # endif
       
   219         RETURN ( __MKUINT(retVal) );
       
   220     }
       
   221     if (returnTypeSymbol == @symbol(bool)) {
       
   222         RETURN ( retVal ? true : false );
       
   223     }
       
   224     if (returnTypeSymbol == @symbol(void)) {
       
   225         RETURN ( nil );
       
   226     }
       
   227     if (returnTypeSymbol == @symbol(char)) {
       
   228         RETURN ( __MKCHARACTER(retVal & 0xFF) );
       
   229     }
       
   230     if (returnTypeSymbol == @symbol(wchar)) {
       
   231         RETURN ( __MKUCHARACTER(retVal & 0xFFFF) );
       
   232     }
       
   233 
       
   234 # ifdef VERBOSE
       
   235     if (@global(Verbose) == true) {
       
   236         printf("return pointer: %"_lx_"\n", (INT)(retVal));
       
   237     }
       
   238 # endif
       
   239     if (returnTypeSymbol == @symbol(handle)) {
       
   240         returnValue = __MKEXTERNALADDRESS(retVal);
       
   241     } else if (returnTypeSymbol == @symbol(pointer)) {
       
   242         returnValue = __MKEXTERNALBYTES(retVal);
       
   243     } else if (returnTypeSymbol == @symbol(bytePointer)) {
       
   244         returnValue = __MKEXTERNALBYTES(retVal);
       
   245     } else if (returnTypeSymbol == @symbol(charPointer)) {
       
   246         returnValue = __MKSTRING(retVal);
       
   247     } else if (returnTypeSymbol == @symbol(wcharPointer)) {
       
   248         returnValue = __MKU16STRING(retVal);
       
   249     } else {
       
   250         __FAIL__(@symbol(UnknownReturnType2))
       
   251     }
       
   252 getOutOfHere: ;
       
   253 %}.
       
   254     failureCode notNil ifTrue:[
       
   255         (failureCode == #UnknownReturnType or:[ failureCode == #UnknownArgumentType ]) ifTrue:[
       
   256             oldReturnType := returnType.
       
   257             oldArgumentTypes := argumentTypes.
       
   258             self adjustTypes.
       
   259             ((oldReturnType ~= returnType) or:[oldArgumentTypes ~= argumentTypes]) ifTrue:[
       
   260                 thisContext restart
       
   261             ].
       
   262         ].
       
   263         (failureCode == #BadArgForAsyncCall) ifTrue:[
       
   264             ^ self tryAgainWithAsyncSafeArguments:argumentsOrNil forCPPInstance:aReceiverOrNil
       
   265         ].
       
   266         (failureCode == #FFINotSupported) ifTrue:[
       
   267             self primitiveFailed:'FFI support missing in this build'.
       
   268         ].
       
   269 
       
   270         self primitiveFailed.   "see failureCode and failureInfo for details"
       
   271         ^ nil
       
   272     ].
       
   273 
       
   274     returnType isSymbol ifTrue:[
       
   275         returnValueClass notNil ifTrue:[
       
   276             self isConstReturnValue ifTrue:[
       
   277                 returnValue changeClassTo:returnValueClass.
       
   278                 ^ returnValue
       
   279             ].
       
   280             ^ returnValueClass fromExternalAddress:returnValue.
       
   281         ].
       
   282     ] ifFalse:[
       
   283         returnType isCPointer ifTrue:[
       
   284             returnType baseType isCStruct ifTrue:[
       
   285                 stClass := Smalltalk classNamed:returnType baseType name.
       
   286                 stClass notNil ifTrue:[
       
   287                     self isConstReturnValue ifTrue:[
       
   288                         returnValue changeClassTo:returnValueClass.
       
   289                         ^ returnValue
       
   290                     ].
       
   291                     ^ stClass fromExternalAddress:returnValue.
       
   292                 ].
       
   293             ].
       
   294             returnType baseType isCChar ifTrue:[
       
   295                 ^ returnValue stringAt:1
       
   296             ].
       
   297         ].
       
   298     ].
       
   299 
       
   300     ^ returnValue
       
   301 
       
   302     "Created: / 01-08-2006 / 13:56:23 / cg"
       
   303     "Modified: / 31-03-2016 / 00:03:03 / cg"
       
   304 ! !
       
   305 
       
   306 !SimpleExternalLibraryFunction class methodsFor:'documentation'!
       
   307 
       
   308 version
       
   309     ^ '$Header$'
       
   310 !
       
   311 
       
   312 version_CVS
       
   313     ^ '$Header$'
       
   314 ! !
       
   315