[Vm-dev] VM Maker: VMMaker.oscog-eem.1686.mcz

commits at source.squeak.org commits at source.squeak.org
Sat Feb 20 18:52:07 UTC 2016


Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1686.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.1686
Author: eem
Time: 20 February 2016, 10:50:20.57672 am
UUID: 52f4115e-2108-421a-b31c-12d08603a073
Ancestors: VMMaker.oscog-eem.1685

Rename VMMaker-Plugins-Alien to VMMaker-Plugins-FFI and put all the FFI plugins there-in.

Get ThreadedFFICalloutState's variable names right.

Better define PLATFORM_API_USES_CALLEE_POPS_CONVENTION in ThreadedFFIPlugin's preambleCCode.  Only WIN32 needs this as yet.

Implement structure return for X64SysV and X64WIN64.

=============== Diff against VMMaker.oscog-eem.1685 ===============

Item was changed:
  SystemOrganization addCategory: #VMMaker!
  SystemOrganization addCategory: #'VMMaker-Building'!
  SystemOrganization addCategory: #'VMMaker-Interpreter'!
  SystemOrganization addCategory: #'VMMaker-InterpreterSimulation'!
  SystemOrganization addCategory: #'VMMaker-InterpreterSimulation-Morphic'!
  SystemOrganization addCategory: #'VMMaker-JIT'!
  SystemOrganization addCategory: #'VMMaker-JITSimulation'!
  SystemOrganization addCategory: #'VMMaker-Multithreading'!
  SystemOrganization addCategory: #'VMMaker-Plugins'!
+ SystemOrganization addCategory: #'VMMaker-Plugins-FFI'!
- SystemOrganization addCategory: #'VMMaker-Plugins-Alien'!
  SystemOrganization addCategory: #'VMMaker-Plugins-IOS'!
  SystemOrganization addCategory: #'VMMaker-PostProcessing'!
  SystemOrganization addCategory: #'VMMaker-SmartSyntaxPlugins'!
  SystemOrganization addCategory: #'VMMaker-SpurMemoryManager'!
  SystemOrganization addCategory: #'VMMaker-SpurMemoryManagerSimulation'!
  SystemOrganization addCategory: #'VMMaker-Support'!
  SystemOrganization addCategory: #'VMMaker-Tests'!
  SystemOrganization addCategory: #'VMMaker-Translation to C'!

Item was changed:
  InterpreterPlugin subclass: #FFIPlugin
  	instanceVariableNames: 'ffiLastError ffiArgSpec ffiArgSpecSize ffiArgHeader ffiRetOop ffiRetClass ffiRetSpec ffiRetSpecSize ffiRetHeader ffiLogEnabled externalFunctionInstSize'
  	classVariableNames: ''
  	poolDictionaries: 'FFIConstants'
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !FFIPlugin commentStamp: 'eem 11/24/2014 11:00' prior: 0!
  This plugin provides access to foreign function interfaces on those platforms that provide such. For example Windows DLLs and unix .so's.  It is obsolete, having been superceded by the ThreadedFFIPlugin.!

Item was changed:
  InterpreterPlugin subclass: #IA32ABIPlugin
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: 'VMBasicConstants'
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins-Alien'!
  
  !IA32ABIPlugin commentStamp: 'eem 1/25/2016 11:59' prior: 0!
  This plugin implements the Alien foreign-function interface, a small elaboration on the Strongtalk FFI.
  
  Call-outs are performed by a small number of primitives, one each for the four different kinds of return linkage on x86.  The primitives are var-args.  Each primitive has a signature something like:
  primFFICall: functionAddress <Alien> result: result <Alien> with: firstArg <Alien> ... with: lastArg <Alien>
  	<primitive: 'primCallOutIntegralReturn' module: 'IA32ABI'>
  which arranges to call-out supplying the arguments to the function pointed to by functionAddress, copying its return value into result.  The call-out primitives are as follows:
  
  primCallOutIntegralReturn call a function which returns up to 8 bytes in %eax & %edx, taking up to the first 4 bytes from %eax.  i.e. if the sizeof(result) is 4 or less only bytes from %eax will be returned, but if more then the first 4 bytes of result will be assigned with %eax and subsequent bytes with %edx, up to a total of 8 bytes.
  
  primCallOutPointerReturn call a function which returns a pointer in %eax.  Assign sizeof(result) bytes from this pointer into the result.
  
  primCallOutFloatReturn call a function which returns a 4 byte single-precision float in %f0, assigning the 4 bytes of %f0 into result.
  
  primCallOutDoubleReturn call a function which returns an 8 byte double-precision float in %f0, assigning the 8 bytes of %f0 into result.
  
  !

Item was changed:
  IA32ABIPlugin subclass: #IA32ABIPluginSimulator
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins-Alien'!

Item was changed:
  ThreadedFFIPlugin subclass: #ThreadedARMFFIPlugin
  	instanceVariableNames: ''
  	classVariableNames: 'NumFloatRegArgs NumIntRegArgs'
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedARMFFIPlugin commentStamp: '<historical>' prior: 0!
  This subclass is for the 32-bit ARM ABI.  It typically has 4 integer registers.!

Item was removed:
- ----- Method: ThreadedARMFFIPlugin>>dispatchFunctionPointer:with:with:with:with: (in category 'callout support') -----
- dispatchFunctionPointer: aFunctionPointer with: int1 with: int2 with: int3 with: int4
- 	"In C aFunctionPointer is void (*aFunctionPointer)(int, int, int, int)"
- 	<cmacro: '(aFunctionPointer, int1, int2, int3, int4) (aFunctionPointer)(int1, int2, int3, int4)'>
- 	^self 
- 		perform: aFunctionPointer
- 		with: int1
- 		with: int2
- 		with: int3
- 		with: int4!

Item was changed:
  ----- Method: ThreadedARMFFIPlugin>>ffiReturnStruct:ofType:in: (in category 'callout support') -----
  ffiReturnStruct: longLongRet ofType: ffiRetType in: calloutState
  	<var: #longLongRet type: #usqLong>
  	<var: #calloutState type: #'CalloutState *'>
+ 	"Create a structure return value from an external function call.  The value has been stored in
+ 	 alloca'ed space pointed to by the calloutState or in the return value."
- 	"Create a structure return value from an external function call.  The value as been stored in
- 	 alloca'ed space pointed to by the calloutState."
  	| retOop retClass oop |
  	<inline: true>
  	retClass := interpreterProxy fetchPointer: 1 ofObject: ffiRetType.
  	retOop := interpreterProxy instantiateClass: retClass indexableSize: 0.
  	self remapOop: retOop
  		in: [oop := interpreterProxy 
  					instantiateClass: interpreterProxy classByteArray 
  					indexableSize: calloutState structReturnSize].
+ 	self mem: (interpreterProxy firstIndexableField: oop)
+ 		cp: ((self returnStructInRegisters: calloutState structReturnSize)
+ 				ifTrue: [self addressOf: longLongRet]
+ 				ifFalse: [calloutState limit])
+ 		 y: calloutState structReturnSize.
- 	(self returnStructInRegisters: calloutState structReturnSize)
- 		ifTrue:
- 			[self mem: (interpreterProxy firstIndexableField: oop) cp: (self addressOf: longLongRet) y: calloutState structReturnSize]
- 		ifFalse:
- 			[self mem: (interpreterProxy firstIndexableField: oop) cp: calloutState limit y: calloutState structReturnSize].
  	interpreterProxy storePointer: 0 ofObject: retOop withValue: oop.
  	^interpreterProxy methodReturnValue: retOop!

Item was changed:
  VMStructType subclass: #ThreadedFFICalloutState
  	instanceVariableNames: 'argVector currentArg limit structReturnSize callFlags ffiArgSpec ffiArgSpecSize ffiArgHeader ffiRetHeader stringArgIndex stringArgs'
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedFFICalloutState commentStamp: '<historical>' prior: 0!
  Instances of the receiver hold the per-thread state of a call-out.
  
  long *argVector		pointer to the start of the alloca'ed argument marshalling area
  long *currentArg		pointer to the position in argVector to write the current argument
  long *limit			the limit of the argument marshalling area (for bounds checking)
  structReturnSize		the size of the space allocated for the structure return, if any
  callFlags			the value of the ExternalFunctionFlagsIndex field in the ExternalFunction being called
  ffiArgSpec et al		type information for the current argument being marshalled
  stringArgIndex		the count of temporary strings used for marshalling Smalltalk strings to character strings.
  stringArgs			pointers to the temporary strings used for marshalling Smalltalk strings to character strings.!

Item was changed:
  ThreadedFFICalloutState subclass: #ThreadedFFICalloutStateForARM
  	instanceVariableNames: 'integerRegisterIndex integerRegisters floatRegisterIndex backfillFloatRegisterIndex floatRegisters'
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!

Item was changed:
  ThreadedFFICalloutState subclass: #ThreadedFFICalloutStateForPPC
  	instanceVariableNames: 'registerIndex integerRegisters floatRegisters'
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!

Item was changed:
  ThreadedFFICalloutState subclass: #ThreadedFFICalloutStateForX64
+ 	instanceVariableNames: 'integerRegisterIndex floatRegisterIndex integerRegisters floatRegisters'
- 	instanceVariableNames: 'registerIndex integerRegisters floatRegisters'
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedFFICalloutStateForX64 commentStamp: 'eem 2/16/2016 19:13' prior: 0!
  A ThreadedFFICalloutStateForX64 is a holder for the callout state maintained while marshalling an FFI call on an X64 (x86-64) system.!

Item was added:
+ ----- Method: ThreadedFFICalloutStateForX64>>floatRegisterIndex (in category 'accessing') -----
+ floatRegisterIndex
+ 
+ 	^ floatRegisterIndex!

Item was added:
+ ----- Method: ThreadedFFICalloutStateForX64>>floatRegisterIndex: (in category 'accessing') -----
+ floatRegisterIndex: anObject
+ 
+ 	^floatRegisterIndex := anObject!

Item was added:
+ ----- Method: ThreadedFFICalloutStateForX64>>integerRegisterIndex (in category 'accessing') -----
+ integerRegisterIndex
+ 
+ 	^ integerRegisterIndex!

Item was added:
+ ----- Method: ThreadedFFICalloutStateForX64>>integerRegisterIndex: (in category 'accessing') -----
+ integerRegisterIndex: anObject
+ 
+ 	^integerRegisterIndex := anObject!

Item was removed:
- ----- Method: ThreadedFFICalloutStateForX64>>registerIndex (in category 'accessing') -----
- registerIndex
- 
- 	^ registerIndex!

Item was removed:
- ----- Method: ThreadedFFICalloutStateForX64>>registerIndex: (in category 'accessing') -----
- registerIndex: anObject
- 
- 	^registerIndex := anObject!

Item was changed:
  ThreadedFFICalloutStateForX64 subclass: #ThreadedFFICalloutStateForX64SysV
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!

Item was changed:
  ThreadedFFICalloutStateForX64 subclass: #ThreadedFFICalloutStateForX64Win64
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!

Item was changed:
  InterpreterPlugin subclass: #ThreadedFFIPlugin
  	instanceVariableNames: 'ffiLogEnabled externalFunctionInstSize ffiLastError'
  	classVariableNames: 'DefaultMaxStackSize ExternalFunctionAddressIndex ExternalFunctionArgTypesIndex ExternalFunctionFlagsIndex ExternalFunctionStackSizeIndex MaxNumArgs'
  	poolDictionaries: 'FFIConstants'
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedFFIPlugin commentStamp: 'eem 7/21/2011 11:38' prior: 0!
  This plugin provides access to foreign function interfaces on those platforms that provide such. For example Windows DLLs and unix .so's.  This version is designed to support reentrancy and threading, and so uses alloca to stack allocate all memory needed for a given callout.  Specific platforms are implemented by concrete subclasses.  Threaded calls can only be provided within the context of the threaded VM; othewise calls must be blocking.  So code specific to threading is guarded with a
  	self cppIf: COGMTVM
  		ifTrue: [...]
  form to arrange that it is only compiled in the threaded VM context.!

Item was changed:
  ----- Method: ThreadedFFIPlugin class>>preambleCCode (in category 'translation') -----
  preambleCCode
  	"For a source of builtin defines grep for builtin_define in a gcc release config directory."
  	^'
  #include "sqAssert.h" /* for assert */
  
  #ifdef _MSC_VER
  # define alloca _alloca
  #endif
  #if defined(__GNUC__) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__))
  # define setsp(sp) asm volatile ("movl %0,%%esp" : : "m"(sp))
  # define getsp() ({ void *esp; asm volatile ("movl %%esp,%0" : "=r"(esp) : ); esp;})
  # elif defined(__GNUC__) && (defined(__arm__))
  # define setsp(sp) asm volatile ("ldr %%sp, %0" : : "m"(sp))
  # define getsp() ({ void *sp; asm volatile ("mov %0, %%sp" : "=r"(sp) : ); sp;})
  #endif
  #if !!defined(getsp)
  # define getsp() 0
  #endif 
  #if !!defined(setsp)
  # define setsp(ignored) 0
  #endif 
  
  #if !!defined(STACK_ALIGN_BYTES)
  # if __APPLE__ && __MACH__ && __i386__
  #  define STACK_ALIGN_BYTES 16
  # elif __linux__ && __i386__
  #  define STACK_ALIGN_BYTES 16
  # elif defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64)
  #  define STACK_ALIGN_BYTES 16
  # elif defined(powerpc) || defined(__powerpc__) || defined(_POWER) || defined(__POWERPC__) || defined(__PPC__)
  #  define STACK_ALIGN_BYTES 16
  # elif defined(__sparc64__) || defined(__sparcv9__) || defined(__sparc_v9__) /* must precede 32-bit sparc defs */
  #  define STACK_ALIGN_BYTES 16
  # elif defined(sparc) || defined(__sparc__) || defined(__sparclite__)
  #  define STACK_ALIGN_BYTES 8
  # elif defined(__arm__) 
  #  define STACK_ALIGN_BYTES 8
  # else
  #  define STACK_ALIGN_BYTES 0
  # endif
  #endif /* !!defined(STACK_ALIGN_BYTES) */
  
  #if !!defined(STACK_OFFSET_BYTES)
  # define STACK_OFFSET_BYTES 0
  #endif
  
  #if defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__)
  /* Both Mac OS X x86 and Win32 x86 return structs of a power of two in size
   * less than or equal to eight bytes in length in registers. Linux never does so.
   */
  # if __linux__
  #	define WIN32_X86_STRUCT_RETURN 0
  # else
  #	define WIN32_X86_STRUCT_RETURN 1
  # endif
  # if WIN32
  #	define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 1
- # else
- #	define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0
  # endif
  #endif /* defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) */
  
- #if defined(__arm__)
- #	define WIN32_X86_STRUCT_RETURN 0
- #	define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0
- #endif /* defined(__arm__) */
- 
  #if !!defined(ALLOCA_LIES_SO_USE_GETSP)
  # if defined(__MINGW32__) && (__GNUC__ >= 3)
      /*
       * cygwin -mno-cygwin (MinGW) gcc 3.4.x''s alloca is a library routine that answers
       * %esp + 4, so the outgoing stack is offset by one word if uncorrected.
       * Grab the actual stack pointer to correct.
       */
  #	define ALLOCA_LIES_SO_USE_GETSP 1
  # else
  #	define ALLOCA_LIES_SO_USE_GETSP 0
  # endif
  #endif /* !!defined(ALLOCA_LIES_SO_USE_GETSP) */
  
+ #if !!defined(PLATFORM_API_USES_CALLEE_POPS_CONVENTION)
+ # define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0
+ #endif
+ 
  /* The dispatchOn:in:with:with: generates an unwanted call on error.  Just squash it. */
  #define error(foo) 0
  #ifndef SQUEAK_BUILTIN_PLUGIN
  /* but print assert failures. */
  void
  warning(char *s) { /* Print an error message but don''t exit. */
  	printf("\n%s\n", s);
  }
  #endif
  
  /* sanitize */
  #ifdef SQUEAK_BUILTIN_PLUGIN
  # define EXTERN 
  #else
  # define EXTERN extern
  #endif
  int ffiLogCallOfLength(void *, int);               			/* sqFFIPlugin.c */
  int ffiLogFileNameOfLength(void *, int);             		/* sqFFIPlugin.c */
  EXTERN void initSurfacePluginFunctionPointers();				/* sqManualSurface.c */
  EXTERN int createManualSurface(int, int, int, int, int); 	/* sqManualSurface.c */
  EXTERN int destroyManualSurface(int);							/* sqManualSurface.c */
  EXTERN int setManualSurfacePointer(int, void*);				/* sqManualSurface.c */
  '!

Item was added:
+ ----- Method: ThreadedFFIPlugin>>dispatchFunctionPointer:with:with:with:with: (in category 'callout support') -----
+ dispatchFunctionPointer: aFunctionPointer with: int1 with: int2 with: int3 with: int4
+ 	"In C aFunctionPointer is void (*aFunctionPointer)(int, int, int, int)"
+ 	<cmacro: '(aFunctionPointer, int1, int2, int3, int4) (aFunctionPointer)(int1, int2, int3, int4)'>
+ 	^self 
+ 		perform: aFunctionPointer
+ 		with: int1
+ 		with: int2
+ 		with: int3
+ 		with: int4!

Item was added:
+ ----- Method: ThreadedFFIPlugin>>dispatchFunctionPointer:with:with:with:with:with:with: (in category 'callout support') -----
+ dispatchFunctionPointer: aFunctionPointer with: int1 with: int2 with: int3 with: int4 with: int5 with: int6
+ 	"In C aFunctionPointer is void (*aFunctionPointer)(int, int, int, int)"
+ 	<cmacro: '(aFunctionPointer,a1,a2, a3, a4,a5,a6) (aFunctionPointer)(a1,a2, a3, a4,a5,a6)'>
+ 	^self 
+ 		perform: aFunctionPointer
+ 		with: int1
+ 		with: int2
+ 		with: int3
+ 		with: int4
+ 		with: int5
+ 		with: int6!

Item was added:
+ VMStructType subclass: #ThreadedFFIX64SixteenByteReturn
+ 	instanceVariableNames: 'a b'
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!

Item was added:
+ ----- Method: ThreadedFFIX64SixteenByteReturn class>>structTypeName (in category 'translation') -----
+ structTypeName
+ 	^'SixteenByteReturn'!

Item was changed:
  ThreadedFFIPlugin subclass: #ThreadedIA32FFIPlugin
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedIA32FFIPlugin commentStamp: '<historical>' prior: 0!
  This subclass is for the IA32/x86 ABI.!

Item was changed:
  ThreadedFFIPlugin subclass: #ThreadedPPCBEFFIPlugin
  	instanceVariableNames: ''
  	classVariableNames: 'NumRegArgs'
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedPPCBEFFIPlugin commentStamp: '<historical>' prior: 0!
  This subclass is for the PowerPC ABI in BigEndian mode.  It typically uses 8 integer registers and 8 single-precision floating-point registers that shadow the top 8 words on the stack.!

Item was changed:
  ThreadedFFIPlugin subclass: #ThreadedX64FFIPlugin
  	instanceVariableNames: ''
  	classVariableNames: 'NumFloatRegArgs NumIntRegArgs WordSize'
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedX64FFIPlugin commentStamp: 'eem 2/19/2016 15:03' prior: 0!
  This is an abstract superclass for the System V and WIN64 x86-64 ABIs that share a lot of code other than for structure passing.!

Item was changed:
  ThreadedX64FFIPlugin subclass: #ThreadedX64SysVFFIPlugin
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedX64SysVFFIPlugin commentStamp: 'eem 2/17/2016 20:03' prior: 0!
  This subclass is for the System V x86-64 ABI.  The System V ABI uses 6 integer registers and 8 double-precision floating-point registers.  See http://www.x86-64.org/documentation/abi.pdf.  It seems that Mac OS X and linux use draft version 0.90, http://people.freebsd.org/~obrien/amd64-elf-abi.pdf.
  
  Note that the System V x86-64 ABI decomposes structs of 2 eightbytes or smaller passed by value across available parameter registers.  double fields will be passed in an xmm register.!

Item was changed:
  ----- Method: ThreadedX64SysVFFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') -----
  ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState
  	<var: #procAddr type: #'void *'>
  	<var: #calloutState type: #'CalloutState *'>
  	<var: #loadFloatRegs declareC: 'extern void loadFloatRegs(double, double, double, double, double, double, double, double)'>
  	"Go out, call this guy and create the return value.  This *must* be inlined because of
  	 the alloca of the outgoing stack frame in ffiCall:WithFlags:NumArgs:Args:AndTypes:"
  	| myThreadIndex atomicType floatRet intRet loadFloatRegs oop |
  	<var: #floatRet type: #double>
+ 	<var: #intRet type: 'SixteenByteReturn'>
- 	<var: #intRet type: #usqLong>
  	<inline: true>
  	self cCode: '' inSmalltalk: [loadFloatRegs := #used. loadFloatRegs class].
  	self cppIf: COGMTVM ifTrue:
  	[(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue:
  		[myThreadIndex := interpreterProxy disownVM: 0]].
  
  	self registerArgsSlop + self cStackAlignment > 0 ifTrue:
  		[self setsp: calloutState argVector].
  
  	calloutState floatRegisterIndex > 0 ifTrue:
  		[self 
+ 			load: (calloutState floatRegisters at: 0)
+ 			Flo: (calloutState floatRegisters at: 1)
+ 			a: (calloutState floatRegisters at: 2)
+ 			t: (calloutState floatRegisters at: 3)
+ 			R: (calloutState floatRegisters at: 4)
+ 			e: (calloutState floatRegisters at: 5)
+ 			g: (calloutState floatRegisters at: 6)
+ 			s: (calloutState floatRegisters at: 7)].
- 			load: ((calloutState floatRegisters at: 0) at: 0)
- 			Flo: ((calloutState floatRegisters at: 1) at: 0)
- 			a: ((calloutState floatRegisters at: 2) at: 0)
- 			t: ((calloutState floatRegisters at: 3) at: 0)
- 			R: ((calloutState floatRegisters at: 4) at: 0)
- 			e: ((calloutState floatRegisters at: 5) at: 0)
- 			g: ((calloutState floatRegisters at: 6) at: 0)
- 			s: ((calloutState floatRegisters at: 7) at: 0)].
  
  	atomicType := self atomicTypeOf: calloutState ffiRetHeader.
  	(atomicType >> 1) = (FFITypeSingleFloat > 1)
  		ifTrue:
  			[atomicType = FFITypeSingleFloat
  				ifTrue:
  					[floatRet := self 
  						dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'float (*)(long, long, long, long, long, long)') 
  						with: (calloutState integerRegisters at: 0)
  						with: (calloutState integerRegisters at: 1)
  						with: (calloutState integerRegisters at: 2)
  						with: (calloutState integerRegisters at: 3)
  						with: (calloutState integerRegisters at: 4)
  						with: (calloutState integerRegisters at: 5)]
  				ifFalse: "atomicType = FFITypeDoubleFloat"
  					[floatRet := self 
  						dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)(long, long, long, long, long, long)') 
  						with: (calloutState integerRegisters at: 0)
  						with: (calloutState integerRegisters at: 1)
  						with: (calloutState integerRegisters at: 2)
  						with: (calloutState integerRegisters at: 3)
  						with: (calloutState integerRegisters at: 4)
  						with: (calloutState integerRegisters at: 5)]]
  		ifFalse:
  			[intRet := self 
+ 				dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'SixteenByteReturn (*)(long, long, long, long, long, long)') 
- 				dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'usqLong (*)(long, long, long, long, long, long)') 
  				with: (calloutState integerRegisters at: 0)
  				with: (calloutState integerRegisters at: 1)
  				with: (calloutState integerRegisters at: 2)
  				with: (calloutState integerRegisters at: 3)
  				with: (calloutState integerRegisters at: 4)
  				with: (calloutState integerRegisters at: 5)].
  	"undo any callee argument pops because it may confuse stack management with the alloca."
  	(self isCalleePopsConvention: calloutState callFlags) ifTrue:
  		[self setsp: calloutState argVector].
  
  	self cppIf: COGMTVM ifTrue:
  	[(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue:
  		[interpreterProxy ownVM: myThreadIndex]].
  
  	(calloutState ffiRetHeader anyMask: FFIFlagPointer+FFIFlagStructure) ifTrue:
  		["Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  		 'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct."
  		 (calloutState ffiRetHeader anyMask: FFIFlagPointer)
  			ifTrue:
  				[oop := self ffiReturnPointer: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]
  			ifFalse:
  				[oop := self ffiReturnStruct: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState].
  		 ^oop].
  	
  	(atomicType >> 1) = (FFITypeSingleFloat > 1)
  		ifTrue:
  			[oop := interpreterProxy floatObjectOf: floatRet]
  		ifFalse:
  			[oop := self ffiCreateIntegralResultOop: intRet
  						ofAtomicType: atomicType
  						in: calloutState].
  	^interpreterProxy methodReturnValue: oop!

Item was added:
+ ----- Method: ThreadedX64SysVFFIPlugin>>ffiReturnStruct:ofType:in: (in category 'callout support') -----
+ ffiReturnStruct: sixteenByteRet ofType: ffiRetType in: calloutState
+ 	<var: #sixteenByteRet type: 'SixteenByteReturn'>
+ 	<var: #calloutState type: #'CalloutState *'>
+ 	"Create a structure return value from an external function call.  The value has been stored in
+ 	 alloca'ed space pointed to by the calloutState or in the return value."
+ 	| retOop retClass oop |
+ 	<inline: true>
+ 	retClass := interpreterProxy fetchPointer: 1 ofObject: ffiRetType.
+ 	retOop := interpreterProxy instantiateClass: retClass indexableSize: 0.
+ 	self remapOop: retOop
+ 		in: [oop := interpreterProxy 
+ 					instantiateClass: interpreterProxy classByteArray 
+ 					indexableSize: calloutState structReturnSize].
+ 	self mem: (interpreterProxy firstIndexableField: oop)
+ 		cp: ((self returnStructInRegisters: calloutState structReturnSize)
+ 				ifTrue: [self addressOf: sixteenByteRet]
+ 				ifFalse: [calloutState limit])
+ 		 y: calloutState structReturnSize.
+ 	interpreterProxy storePointer: 0 ofObject: retOop withValue: oop.
+ 	^interpreterProxy methodReturnValue: retOop!

Item was changed:
  ThreadedX64FFIPlugin subclass: #ThreadedX64Win64FFIPlugin
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins'!
  
  !ThreadedX64Win64FFIPlugin commentStamp: 'eem 2/16/2016 19:39' prior: 0!
  This subclass is for the Win64 x86-64 ABI.  The System V ABI uses 4 integer registers and 4 double-precision floating-point registers.  See w.g. https://msdn.microsoft.com/en-us/library/ms235286.aspx, or google for "Overview of x64 Calling Conventions - MSDN - Microsoft".
  
  Note that unlike the System V x86-64 ABI, the Win64 ABI does /not/ decompose structs passed by value across available parameter registers.!

Item was changed:
  ----- Method: ThreadedX64Win64FFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') -----
  ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState
  	<var: #procAddr type: #'void *'>
  	<var: #calloutState type: #'CalloutState *'>
  	<var: #loadFloatRegs declareC: 'extern void loadFloatRegs(double, double, double, double)'>
  	"Go out, call this guy and create the return value.  This *must* be inlined because of
  	 the alloca of the outgoing stack frame in ffiCall:WithFlags:NumArgs:Args:AndTypes:"
  	| myThreadIndex atomicType floatRet intRet loadFloatRegs oop |
  	<var: #floatRet type: #double>
  	<var: #intRet type: #usqLong>
  	<inline: true>
  	self cCode: '' inSmalltalk: [loadFloatRegs := #used. loadFloatRegs class].
  	self cppIf: COGMTVM ifTrue:
  	[(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue:
  		[myThreadIndex := interpreterProxy disownVM: 0]].
  
  	self registerArgsSlop + self cStackAlignment > 0 ifTrue:
  		[self setsp: calloutState argVector].
  
  	calloutState floatRegisterIndex > 0 ifTrue:
  		[self 
+ 			load: (calloutState floatRegisters at: 0)
+ 			Flo: (calloutState floatRegisters at: 1)
+ 			at: (calloutState floatRegisters at: 2)
+ 			Re: (calloutState floatRegisters at: 3)
+ 			gs: (calloutState floatRegisters at: 4)].
- 			load: ((calloutState floatRegisters at: 0) at: 0)
- 			Flo: ((calloutState floatRegisters at: 1) at: 0)
- 			at: ((calloutState floatRegisters at: 2) at: 0)
- 			Re: ((calloutState floatRegisters at: 3) at: 0)
- 			gs: ((calloutState floatRegisters at: 4) at: 0)].
  
  	atomicType := self atomicTypeOf: calloutState ffiRetHeader.
  	(atomicType >> 1) = (FFITypeSingleFloat > 1)
  		ifTrue:
  			[atomicType = FFITypeSingleFloat
  				ifTrue:
  					[floatRet := self 
  						dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'float (*)(long, long, long, long)') 
  						with: (calloutState integerRegisters at: 0)
  						with: (calloutState integerRegisters at: 1)
  						with: (calloutState integerRegisters at: 2)
  						with: (calloutState integerRegisters at: 3)]
  				ifFalse: "atomicType = FFITypeDoubleFloat"
  					[floatRet := self 
  						dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)(long, long, long, long)') 
  						with: (calloutState integerRegisters at: 0)
  						with: (calloutState integerRegisters at: 1)
  						with: (calloutState integerRegisters at: 2)
  						with: (calloutState integerRegisters at: 3)]]
  		ifFalse:
  			[intRet := self 
  				dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'usqLong (*)(long, long, long, long)') 
  				with: (calloutState integerRegisters at: 0)
  				with: (calloutState integerRegisters at: 1)
  				with: (calloutState integerRegisters at: 2)
  				with: (calloutState integerRegisters at: 3)].
  	"undo any callee argument pops because it may confuse stack management with the alloca."
  	(self isCalleePopsConvention: calloutState callFlags) ifTrue:
  		[self setsp: calloutState argVector].
  
  	self cppIf: COGMTVM ifTrue:
  	[(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue:
  		[interpreterProxy ownVM: myThreadIndex]].
  
  	(calloutState ffiRetHeader anyMask: FFIFlagPointer+FFIFlagStructure) ifTrue:
  		["Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  		 'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct."
  		 (calloutState ffiRetHeader anyMask: FFIFlagPointer)
  			ifTrue:
  				[oop := self ffiReturnPointer: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]
  			ifFalse:
  				[oop := self ffiReturnStruct: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState].
  		 ^oop].
  	
  	(atomicType >> 1) = (FFITypeSingleFloat > 1)
  		ifTrue:
  			[oop := interpreterProxy floatObjectOf: floatRet]
  		ifFalse:
  			[oop := self ffiCreateIntegralResultOop: intRet
  						ofAtomicType: atomicType
  						in: calloutState].
  	^interpreterProxy methodReturnValue: oop!

Item was added:
+ ----- Method: ThreadedX64Win64FFIPlugin>>ffiReturnStruct:ofType:in: (in category 'callout support') -----
+ ffiReturnStruct: intRet ofType: ffiRetType in: calloutState
+ 	<var: #intRet type: #usqLong>
+ 	<var: #calloutState type: #'CalloutState *'>
+ 	"Create a structure return value from an external function call.  The value has been stored in
+ 	 alloca'ed space pointed to by the calloutState or in the return value."
+ 	| retOop retClass oop |
+ 	<inline: true>
+ 	retClass := interpreterProxy fetchPointer: 1 ofObject: ffiRetType.
+ 	retOop := interpreterProxy instantiateClass: retClass indexableSize: 0.
+ 	self remapOop: retOop
+ 		in: [oop := interpreterProxy 
+ 					instantiateClass: interpreterProxy classByteArray 
+ 					indexableSize: calloutState structReturnSize].
+ 	self mem: (interpreterProxy firstIndexableField: oop)
+ 		cp: ((self returnStructInRegisters: calloutState structReturnSize)
+ 				ifTrue: [self addressOf: intRet]
+ 				ifFalse: [calloutState limit])
+ 		 y: calloutState structReturnSize.
+ 	interpreterProxy storePointer: 0 ofObject: retOop withValue: oop.
+ 	^interpreterProxy methodReturnValue: retOop!

Item was changed:
  VMStructType subclass: #VMCallbackReturnValue
  	instanceVariableNames: 'type pad crvrvs'
  	classVariableNames: ''
  	poolDictionaries: ''
+ 	category: 'VMMaker-Plugins-FFI'!
- 	category: 'VMMaker-Plugins-Alien'!
  
  !VMCallbackReturnValue commentStamp: 'eem 10/14/2010 09:29' prior: 0!
  A VMCallbackReturnValue supports legacy Alien callbacks.!



More information about the Vm-dev mailing list