ExternalFunctionCallback.st
changeset 10607 9f42b83e653a
child 10609 fa629d528330
equal deleted inserted replaced
10606:c28e8e95d049 10607:9f42b83e653a
       
     1 'From Smalltalk/X, Version:5.3.5 on 12-06-2007 at 16:40:04'                     !
       
     2 
       
     3 ExternalBytes subclass:#ExternalFunctionCallback
       
     4 	instanceVariableNames:'returnType argumentTypes action'
       
     5 	classVariableNames:'CallBackRegistry'
       
     6 	poolDictionaries:''
       
     7 	category:'System-Support'
       
     8 !
       
     9 
       
    10 !ExternalFunctionCallback primitiveDefinitions!
       
    11 %{
       
    12 
       
    13 #ifdef HAVE_FFI
       
    14 # include <ffi.h>
       
    15 # define MAX_ARGS    128
       
    16 
       
    17 extern ffi_type *__get_ffi_type_sint();
       
    18 extern ffi_type *__get_ffi_type_sint8();
       
    19 extern ffi_type *__get_ffi_type_sint16();
       
    20 extern ffi_type *__get_ffi_type_sint32();
       
    21 extern ffi_type *__get_ffi_type_sint64();
       
    22 extern ffi_type *__get_ffi_type_uint();
       
    23 extern ffi_type *__get_ffi_type_uint8();
       
    24 extern ffi_type *__get_ffi_type_uint16();
       
    25 extern ffi_type *__get_ffi_type_uint32();
       
    26 extern ffi_type *__get_ffi_type_uint64();
       
    27 extern ffi_type *__get_ffi_type_float();
       
    28 extern ffi_type *__get_ffi_type_double();
       
    29 extern ffi_type *__get_ffi_type_void();
       
    30 extern ffi_type *__get_ffi_type_pointer();
       
    31 
       
    32 #endif
       
    33 
       
    34 %}
       
    35 ! !
       
    36 
       
    37 !ExternalFunctionCallback primitiveFunctions!
       
    38 %{
       
    39 
       
    40 #define VERBOSE
       
    41 
       
    42 void
       
    43 ExternalFunctionCallback__closure_test_fn(ffi_cif* cif, void* resp, void** args, void* userdata)
       
    44 {
       
    45     int actionIndex = userdata;
       
    46 
       
    47     printf("closure_test_fn(userdata=%d resp*=%x)\n", userdata, resp);
       
    48     printf("closure_test_fn(arg[0]=%d)\n", *(int *)(args[0]));
       
    49     *(ffi_arg *)resp = 1;
       
    50 }
       
    51 
       
    52 void
       
    53 ExternalFunctionCallback__doCall_closure(INTFUNC f)
       
    54 {
       
    55     int result = 0;
       
    56 
       
    57     printf("doCall_closure: calling closure %x(123)...\n", f);
       
    58     result = (*f)(123);
       
    59     printf("doCall_closure: back; result is %x...\n", result);
       
    60 }
       
    61 
       
    62 %}
       
    63 ! !
       
    64 
       
    65 !ExternalFunctionCallback class methodsFor:'examples'!
       
    66 
       
    67 examples
       
    68 "
       
    69     |cb|
       
    70 
       
    71     cb := ExternalFunctionCallback new.
       
    72     cb returnType:#bool argumentTypes:#(uint).
       
    73     cb generateClosure.
       
    74 
       
    75     cb action:[:arg | Transcript showCR:arg].
       
    76     cb address.
       
    77 "
       
    78 ! !
       
    79 
       
    80 !ExternalFunctionCallback methodsFor:'accessing'!
       
    81 
       
    82 action:something
       
    83     action := something.
       
    84 ! !
       
    85 
       
    86 !ExternalFunctionCallback methodsFor:'generation'!
       
    87 
       
    88 address
       
    89     self isValid ifFalse:[
       
    90 	self generate
       
    91     ].
       
    92     ^ super address
       
    93 
       
    94     "Created: / 11-06-2007 / 15:53:00 / cg"
       
    95 !
       
    96 
       
    97 generate
       
    98     |code|
       
    99 
       
   100     code := nil
       
   101 
       
   102     "Created: / 11-06-2007 / 14:50:57 / cg"
       
   103 !
       
   104 
       
   105 generate0
       
   106     |code|
       
   107 
       
   108     code := #[
       
   109 		"/ mov ecx, closureIndex
       
   110 		16rB9
       
   111 		    16r00  16r00  16r00  16r01
       
   112 		"/ mov eax, doClosureC
       
   113 		16rB8
       
   114 		    16r00  16r00  16r00  16r02
       
   115 		"/ call *eax
       
   116 		16rFF  16rD0
       
   117 		"/ ret
       
   118 		16rC3
       
   119 	    ].
       
   120 
       
   121     self allocateBytes:(code size).
       
   122 
       
   123     "Created: / 11-06-2007 / 15:29:33 / cg"
       
   124 ! !
       
   125 
       
   126 !ExternalFunctionCallback methodsFor:'private-accessing'!
       
   127 
       
   128 returnType:aReturnType argumentTypes:argTypes
       
   129     returnType := aReturnType.
       
   130     argumentTypes := argTypes.
       
   131 
       
   132     "Created: / 11-06-2007 / 15:52:01 / cg"
       
   133 ! !
       
   134 
       
   135 !ExternalFunctionCallback methodsFor:'private-generation'!
       
   136 
       
   137 generateClosure
       
   138     |argTypeSymbols returnTypeSymbol failureCode failureInfo returnValue stClass vtOffset
       
   139      virtual async unlimitedStack callTypeNumber returnValueClass argValueClass|
       
   140 
       
   141     argTypeSymbols := argumentTypes.
       
   142     returnTypeSymbol := returnType.
       
   143 
       
   144 %{  /* STACK: 100000 */
       
   145 #if 1
       
   146 #ifdef HAVE_FFI
       
   147     ffi_cif __cif;
       
   148     ffi_type *__argTypesIncludingThis[MAX_ARGS+1];
       
   149     ffi_type **__argTypes = __argTypesIncludingThis;
       
   150     ffi_type *__returnType = NULL;
       
   151     void *__returnValuePointer;
       
   152     static int null = 0;
       
   153     int i;
       
   154     ffi_abi __callType = FFI_DEFAULT_ABI;
       
   155     int __numArgsWanted;
       
   156     ffi_closure *pcl;
       
   157 
       
   158 #define __FAIL__(fcode) \
       
   159     { \
       
   160 	failureCode = fcode; goto getOutOfHere; \
       
   161     }
       
   162 
       
   163     if (argTypeSymbols == nil) {
       
   164 	__numArgsWanted = 0;
       
   165     } else if (__isArray(argTypeSymbols)) {
       
   166 	__numArgsWanted = __arraySize(argTypeSymbols);
       
   167     } else {
       
   168 	__FAIL__(@symbol(BadArgumentTypeVector))
       
   169     }
       
   170 
       
   171     if (__numArgsWanted > MAX_ARGS) {
       
   172 	__FAIL__(@symbol(TooManyArguments))
       
   173     }
       
   174 
       
   175     /*
       
   176      * validate the return type
       
   177      */
       
   178     if (returnTypeSymbol == @symbol(voidPointer)) {
       
   179 	returnTypeSymbol = @symbol(handle);
       
   180     }
       
   181 
       
   182     if (returnTypeSymbol == @symbol(int)) {
       
   183 	__returnType = __get_ffi_type_sint();
       
   184     } else if (returnTypeSymbol == @symbol(uint)) {
       
   185 	__returnType = __get_ffi_type_uint();
       
   186     } else if (returnTypeSymbol == @symbol(uint8)) {
       
   187 	__returnType = __get_ffi_type_uint8();
       
   188     } else if (returnTypeSymbol == @symbol(uint16)) {
       
   189 	__returnType = __get_ffi_type_uint16();
       
   190     } else if (returnTypeSymbol == @symbol(uint32)) {
       
   191 	__returnType = __get_ffi_type_uint32();
       
   192     } else if (returnTypeSymbol == @symbol(uint64)) {
       
   193 	__returnType = __get_ffi_type_uint64();
       
   194 
       
   195     } else if (returnTypeSymbol == @symbol(sint)) {
       
   196 	__returnType = __get_ffi_type_sint();
       
   197     } else if (returnTypeSymbol == @symbol(sint8)) {
       
   198 	__returnType = __get_ffi_type_sint8();
       
   199     } else if (returnTypeSymbol == @symbol(sint16)) {
       
   200 	__returnType = __get_ffi_type_sint16();
       
   201     } else if (returnTypeSymbol == @symbol(sint32)) {
       
   202 	__returnType = __get_ffi_type_sint32();
       
   203     } else if (returnTypeSymbol == @symbol(sint64)) {
       
   204 	__returnType = __get_ffi_type_sint64();
       
   205 
       
   206     } else if (returnTypeSymbol == @symbol(long)) {
       
   207 	if (sizeof(long) == 4) {
       
   208 	   returnTypeSymbol = @symbol(sint32);
       
   209 	   __returnType = __get_ffi_type_sint32();
       
   210 	} else if (sizeof(long) == 8) {
       
   211 	   returnTypeSymbol = @symbol(sint64);
       
   212 	   __returnType = __get_ffi_type_sint64();
       
   213 	} else {
       
   214 	    __FAIL__(@symbol(UnknownReturnType))
       
   215 	}
       
   216 
       
   217     } else if (returnTypeSymbol == @symbol(ulong)) {
       
   218 	if (sizeof(long) == 4) {
       
   219 	   returnTypeSymbol = @symbol(uint32);
       
   220 	   __returnType = __get_ffi_type_uint32();
       
   221 	}else if (sizeof(long) == 8) {
       
   222 	   returnTypeSymbol = @symbol(uint64);
       
   223 	   __returnType = __get_ffi_type_uint64();
       
   224 	} else {
       
   225 	    __FAIL__(@symbol(UnknownReturnType))
       
   226 	}
       
   227 
       
   228     } else if (returnTypeSymbol == @symbol(bool)) {
       
   229 	__returnType = __get_ffi_type_uint();
       
   230 
       
   231     } else if (returnTypeSymbol == @symbol(float)) {
       
   232 	__returnType = __get_ffi_type_float();
       
   233     } else if (returnTypeSymbol == @symbol(double)) {
       
   234 	__returnType = __get_ffi_type_double();
       
   235 
       
   236     } else if (returnTypeSymbol == @symbol(void)) {
       
   237 	__returnType = __get_ffi_type_void();
       
   238     } else if ((returnTypeSymbol == @symbol(pointer))
       
   239 	       || (returnTypeSymbol == @symbol(handle))
       
   240 	       || (returnTypeSymbol == @symbol(charPointer))
       
   241 	       || (returnTypeSymbol == @symbol(bytePointer))
       
   242 	       || (returnTypeSymbol == @symbol(floatPointer))
       
   243 	       || (returnTypeSymbol == @symbol(doublePointer))
       
   244 	       || (returnTypeSymbol == @symbol(intPointer))
       
   245 	       || (returnTypeSymbol == @symbol(shortPointer))
       
   246 	       || (returnTypeSymbol == @symbol(wcharPointer))) {
       
   247 	__returnType = __get_ffi_type_pointer();
       
   248     } else {
       
   249 	if (__isSymbol(returnTypeSymbol)
       
   250 	 && ((returnValueClass = __GLOBAL_GET(returnTypeSymbol)) != nil)) {
       
   251 	    if (! __isBehaviorLike(returnValueClass)) {
       
   252 		__FAIL__(@symbol(NonBehaviorReturnType))
       
   253 	    }
       
   254 	    if (! __qIsSubclassOfExternalAddress(returnValueClass)) {
       
   255 		__FAIL__(@symbol(NonExternalAddressReturnType))
       
   256 	    }
       
   257 	    __returnType = __get_ffi_type_pointer();
       
   258 	    returnTypeSymbol = @symbol(pointer);
       
   259 	} else {
       
   260 	    __FAIL__(@symbol(UnknownReturnType))
       
   261 	}
       
   262     }
       
   263 
       
   264     /*
       
   265      * setup arg-buffers
       
   266      */
       
   267     for (i=0; i<__numArgsWanted; i++) {
       
   268 	ffi_type *thisType;
       
   269 	void *argValuePtr;
       
   270 	OBJ typeSymbol;
       
   271 
       
   272 	failureInfo = __mkSmallInteger(i+1);   /* in case there is one */
       
   273 
       
   274 	typeSymbol = __ArrayInstPtr(argTypeSymbols)->a_element[i];
       
   275 
       
   276 	if (typeSymbol == @symbol(handle)) {
       
   277 	    typeSymbol = @symbol(pointer);
       
   278 	} else if (typeSymbol == @symbol(voidPointer)) {
       
   279 	    typeSymbol = @symbol(pointer);
       
   280 	}
       
   281 
       
   282 	if (typeSymbol == @symbol(long)) {
       
   283 	    if (sizeof(long) == sizeof(int)) {
       
   284 		typeSymbol = @symbol(sint);
       
   285 	    } else {
       
   286 		if (sizeof(long) == 4) {
       
   287 		    typeSymbol = @symbol(sint32);
       
   288 		} else if (sizeof(long) == 8) {
       
   289 		    typeSymbol = @symbol(sint64);
       
   290 		}
       
   291 	    }
       
   292 	}
       
   293 	if (typeSymbol == @symbol(ulong)) {
       
   294 	    if (sizeof(unsigned long) == sizeof(unsigned int)) {
       
   295 		typeSymbol = @symbol(uint);
       
   296 	    } else {
       
   297 		if (sizeof(long) == 4) {
       
   298 		    typeSymbol = @symbol(uint32);
       
   299 		} else if (sizeof(long) == 8) {
       
   300 		    typeSymbol = @symbol(uint64);
       
   301 		}
       
   302 	    }
       
   303 	}
       
   304 
       
   305 	if (typeSymbol == @symbol(int)) {
       
   306 	    thisType = __get_ffi_type_sint();
       
   307 	} else if (typeSymbol == @symbol(uint)) {
       
   308 	    thisType = __get_ffi_type_uint();
       
   309 	} else if (typeSymbol == @symbol(uint8)) {
       
   310 	    thisType = __get_ffi_type_uint8();
       
   311 	} else if (typeSymbol == @symbol(sint8)) {
       
   312 	    thisType = __get_ffi_type_sint8();
       
   313 	} else if (typeSymbol == @symbol(uint16)) {
       
   314 	    thisType = __get_ffi_type_uint16();
       
   315 	} else if (typeSymbol == @symbol(sint16)) {
       
   316 	    thisType = __get_ffi_type_sint16();
       
   317 	} else if ((typeSymbol == @symbol(uint32)) || (typeSymbol == @symbol(sint32))) {
       
   318 	    thisType = __get_ffi_type_uint32();
       
   319 	} else if (typeSymbol == @symbol(float)) {
       
   320 	    thisType = __get_ffi_type_float();
       
   321 	} else if (typeSymbol == @symbol(double)) {
       
   322 	    thisType = __get_ffi_type_double();
       
   323 	} else if (typeSymbol == @symbol(void)) {
       
   324 	    thisType = __get_ffi_type_void();
       
   325 	} else if (typeSymbol == @symbol(charPointer)) {
       
   326 	    thisType = __get_ffi_type_pointer();
       
   327 	} else if (typeSymbol == @symbol(floatPointer)) {
       
   328 	    thisType = __get_ffi_type_pointer();
       
   329 	} else if (typeSymbol == @symbol(doublePointer)) {
       
   330 	    thisType = __get_ffi_type_pointer();
       
   331 	} else if (typeSymbol == @symbol(pointer)) {
       
   332 commonPointerTypeArg: ;
       
   333 	    thisType = __get_ffi_type_pointer();
       
   334 	} else if (typeSymbol == @symbol(bool)) {
       
   335 	    thisType = __get_ffi_type_uint();
       
   336 	} else if (__isSymbol(typeSymbol)
       
   337 	     && ((argValueClass = __GLOBAL_GET(typeSymbol)) != nil)) {
       
   338 	    if (! __isBehaviorLike(argValueClass)) {
       
   339 		__FAIL__(@symbol(NonBehaviorArgumentType))
       
   340 	    }
       
   341 	    if (! __qIsSubclassOfExternalAddress(argValueClass)) {
       
   342 		__FAIL__(@symbol(NonExternalAddressArgumentType))
       
   343 	    }
       
   344 	    goto commonPointerTypeArg; /* sorry */
       
   345 	} else {
       
   346 	    __FAIL__(@symbol(UnknownArgumentType))
       
   347 	}
       
   348 
       
   349 	__argTypes[i] = thisType;
       
   350     }
       
   351     failureInfo = nil;
       
   352 
       
   353     __callType = FFI_DEFAULT_ABI;
       
   354 
       
   355     if (callTypeNumber != nil) {
       
   356 #ifdef CALLTYPE_FFI_STDCALL
       
   357 	if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_API)) {
       
   358 	    __callType = CALLTYPE_FFI_STDCALL;
       
   359 	}
       
   360 #endif
       
   361 #ifdef CALLTYPE_FFI_V8
       
   362 	if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_V8)) {
       
   363 	    __callType = CALLTYPE_FFI_V8;
       
   364 	}
       
   365 #endif
       
   366 #ifdef CALLTYPE_FFI_V9
       
   367 	if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_V9)) {
       
   368 	    __callType = CALLTYPE_FFI_V9;
       
   369 	}
       
   370 #endif
       
   371 #ifdef CALLTYPE_FFI_UNIX64
       
   372 	if (callTypeNumber == @global(ExternalLibraryFunction:CALLTYPE_UNIX64)) {
       
   373 	    __callType = CALLTYPE_FFI_UNIX64;
       
   374 	}
       
   375 #endif
       
   376     }
       
   377 
       
   378 # ifdef VERBOSE
       
   379     printf("prep_cif cif-ptr=%x\n", &__cif);
       
   380 # endif
       
   381     if (ffi_prep_cif(&__cif, __callType, __numArgsWanted, __returnType, __argTypesIncludingThis) != FFI_OK) {
       
   382 	__FAIL__(@symbol(FFIPrepareFailed))
       
   383     }
       
   384     pcl = (ffi_closure *) malloc(sizeof(ffi_closure));
       
   385 # ifdef VERBOSE
       
   386     printf("closure is 0x%x (%d bytes)\n", pcl, sizeof(ffi_closure));
       
   387 # endif
       
   388     if (ffi_prep_closure(pcl, &__cif, ExternalFunctionCallback__closure_test_fn, (void *) 3 /* userdata */) != FFI_OK) {
       
   389 	__FAIL__(@symbol(FFIPrepareClosureFailed))
       
   390     }
       
   391 # ifdef VERBOSE
       
   392     printf("pcl->cif is 0x%x\n", pcl->cif);
       
   393     printf("pcl->fun is 0x%x\n", pcl->fun);
       
   394     printf("pcl code is %02x %02x %02x %02x\n", ((char *)pcl)[0],((char *)pcl)[1],((char *)pcl)[2],((char *)pcl)[3]);
       
   395     printf("            %02x %02x %02x %02x\n", ((char *)pcl)[4],((char *)pcl)[5],((char *)pcl)[6],((char *)pcl)[7]);
       
   396     printf("            %02x %02x %02x %02x\n", ((char *)pcl)[8],((char *)pcl)[9],((char *)pcl)[10],((char *)pcl)[11]);
       
   397     printf("            %02x %02x %02x %02x\n", ((char *)pcl)[12],((char *)pcl)[13],((char *)pcl)[14],((char *)pcl)[15]);
       
   398 #endif
       
   399     ExternalFunctionCallback__doCall_closure((INTFUNC)pcl);
       
   400     free(pcl);
       
   401 
       
   402 #else /* no FFI support */
       
   403     __FAIL__(@symbol(FFINotSupported));
       
   404 #endif /* HAVE_FFI */
       
   405 #endif /* 0 */
       
   406 getOutOfHere: ;
       
   407 %}.
       
   408     failureCode notNil ifTrue:[
       
   409 	self primitiveFailed:(failureCode->failureInfo).   "see failureCode and failureInfo for details"
       
   410 	^ nil
       
   411     ].
       
   412 
       
   413     "Created: / 11-06-2007 / 21:53:02 / cg"
       
   414 ! !