Marcel Taeumel uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-mt.3181.mcz
==================== Summary ====================
Name: VMMaker.oscog-mt.3181 Author: mt Time: 13 April 2022, 10:53:52.645201 am UUID: 85dd23b6-7723-a548-811e-6356bd6d5095 Ancestors: VMMaker.oscog-mt.3179
In the FFI plugin, fixes a regression in int64_t support on 32-bit builds, which was due to a mix-up between int64_t and intptr_t.
Note that the current design only supports up to 64-bit integer types. If we want to support, for example, 128-bit integer types on a 64-bit machine, we would have to think about a replacement for 'usqLong'. Or even better, we find a way to specialize #ffiArgByValue:in: in subclasses of ThreadedFFIPlugin to use the stack more efficiently.
=============== Diff against VMMaker.oscog-mt.3179 ===============
Item was changed: ----- Method: ThreadedFFIPlugin>>ffiArgByValue:in: (in category 'callout support') ----- ffiArgByValue: oop in: calloutState "Support for generic callout. Prepare an argument by value for a callout." <var: #calloutState type: #'CalloutState *'> | atomicType intValue floatValue | <inline: true> + <var: #intValue type: #'usqLong'> "Support up to int64_t or uint64_t" atomicType := self atomicTypeOf: calloutState ffiArgHeader. (self isFloatAtomicType: atomicType) ifFalse: [intValue := self ffiIntegerValueOf: oop. interpreterProxy failed ifTrue: [^FFIErrorCoercionFailed]. "N.B. Slang inlines the functions within the dispatchOn:in:with:with: here-in" self cppIf: BytesPerWord = 8 ifTrue: [^self dispatchOn: atomicType in: #( ffiPushVoid:in: "FFITypeVoid" ffiPushUnsigned64:in: "FFITypeBool" ffiPushUnsigned8:in: "FFITypeUnsignedInt8" ffiPushSigned8:in: "FFITypeSignedInt8" ffiPushUnsigned16:in: "FFITypeUnsignedInt16" ffiPushSigned16:in: "FFITypeSignedInt16" ffiPushUnsigned32:in: "FFITypeUnsignedInt32" ffiPushSigned32:in: "FFITypeSignedInt32" ffiPushUnsigned64:in: "FFITypeUnsignedInt64" ffiPushSigned64:in: "FFITypeSignedInt64" ffiPushUnsigned8:in: "FFITypeUnsignedChar8" ffiPushSigned8:in: "FFITypeSignedChar8" ffiPushVoid:in: "ffiPushFloat32:" "FFITypeSingleFloat" ffiPushVoid:in: "ffiPushFloat64:" "FFITypeDoubleFloat" ffiPushUnsigned16:in: "FFITypeUnsignedChar16" ffiPushUnsigned32:in:) "FFITypeUnsignedChar32" with: intValue with: calloutState] ifFalse: [^self dispatchOn: atomicType in: #( ffiPushVoid:in: "FFITypeVoid" ffiPushUnsigned32:in: "FFITypeBool" ffiPushUnsigned8:in: "FFITypeUnsignedInt8" ffiPushSigned8:in: "FFITypeSignedInt8" ffiPushUnsigned16:in: "FFITypeUnsignedInt16" ffiPushSigned16:in: "FFITypeSignedInt16" ffiPushUnsigned32:in: "FFITypeUnsignedInt32" ffiPushSigned32:in: "FFITypeSignedInt32" ffiPushUnsigned64:in: "FFITypeUnsignedInt64" ffiPushSigned64:in: "FFITypeSignedInt64" ffiPushUnsigned8:in: "FFITypeUnsignedChar8" ffiPushSigned8:in: "FFITypeSignedChar8" ffiPushVoid:in: "ffiPushFloat32:" "FFITypeSingleFloat" ffiPushVoid:in: "ffiPushFloat64:" "FFITypeDoubleFloat" ffiPushUnsigned16:in: "FFITypeUnsignedChar16" ffiPushUnsigned32:in:) "FFITypeUnsignedChar32" with: intValue with: calloutState]].
floatValue := self ffiFloatValueOf: oop. interpreterProxy failed ifTrue: [^FFIErrorCoercionFailed]. atomicType = FFITypeSingleFloat ifTrue: [^self ffiPushFloat32: floatValue in: calloutState] ifFalse:[^self ffiPushFloat64: floatValue in: calloutState]!
Item was changed: ----- Method: ThreadedFFIPlugin>>ffiCreateIntegralResultOop:ofAtomicType:in: (in category 'callout support') ----- ffiCreateIntegralResultOop: retVal ofAtomicType: atomicType in: calloutState <inline: #always> <var: 'calloutState' type: #'CalloutState *'> + <var: 'retVal' type: #usqLong> "Support up to int64_t or uint64_t" - <var: 'retVal' type: #usqLong> "Callout support. Return the appropriate oop for the given atomic type" | shift value mask byteSize | <var: 'value' type: #usqLong> <var: 'mask' type: #usqLong>
self deny: (self isFloatAtomicType: atomicType).
atomicType = FFITypeBool ifTrue: ["Make sure bool honors the byte size requested" byteSize := calloutState ffiRetHeader bitAnd: FFIStructSizeMask. value := byteSize = (self sizeof: retVal) ifTrue: [retVal] ifFalse: [retVal bitAnd: 1 asUnsignedLongLong << (byteSize * 8) - 1]. ^value = 0 ifTrue: [interpreterProxy falseObject] ifFalse: [interpreterProxy trueObject]]. atomicType <= FFITypeSignedInt32 ifTrue: ["these are all generall integer returns" atomicType <= (BytesPerWord = 8 ifTrue: [FFITypeSignedInt32] ifFalse: [FFITypeSignedInt16]) ifTrue: ["byte/short(/int). first extract partial word, then sign extend" shift := (BytesPerWord = 8 and: [atomicType >= FFITypeUnsignedInt32]) ifTrue: [32] ifFalse: [(atomicType >> 1) * 8]. "# of significant bits" value := retVal bitAnd: (1 asUnsignedLongLong << shift - 1). (atomicType anyMask: 1) ifTrue: ["make the guy signed" mask := 1 asUnsignedLongLong << (shift-1). value := (value bitAnd: mask-1) - (value bitAnd: mask)]. ^interpreterProxy integerObjectOf: value]. "Word sized integer return" ^(atomicType anyMask: 1) ifTrue: [interpreterProxy signedMachineIntegerFor: retVal] "signed return" ifFalse: [interpreterProxy positiveMachineIntegerFor: retVal]]. "unsigned return"
+ "int64_6, uint64_t" - "longlong, char" (atomicType >> 1) = (FFITypeSignedInt64 >> 1) ifTrue: [^(atomicType anyMask: 1) ifTrue: [interpreterProxy signed64BitIntegerFor: retVal] "signed return" ifFalse: [interpreterProxy positive64BitIntegerFor: retVal]]. "unsigned return"
+ "char" self assert: (self isCharacterAtomicType: atomicType).
^atomicType caseOf: { [FFITypeUnsignedChar8] -> [interpreterProxy characterObjectOf: (retVal bitAnd: 16rFF)]. [FFITypeSignedChar8] -> [interpreterProxy characterObjectOf: (retVal bitAnd: 16rFF)]. [FFITypeUnsignedChar16] -> [interpreterProxy characterObjectOf: (retVal bitAnd: 16rFFFF)]. [FFITypeUnsignedChar32] -> [interpreterProxy characterObjectOf: (self cCoerce: retVal to: #'unsigned int')] }!
Item was changed: ----- Method: ThreadedFFIPlugin>>ffiIntegerValueOf: (in category 'callout support') ----- ffiIntegerValueOf: oop "Support for generic callout. Answer an integer value that is coerced as C would do." <inline: true> + <returnTypeC: #'usqLong'> "Support up to int64_t or uint64_t, at least intptr_t" "Cheat with a tag test" (oop anyMask: BytesPerWord - 1) ifTrue: [(interpreterProxy isIntegerObject: oop) ifTrue: [^interpreterProxy integerValueOf: oop]. self cppIf: SPURVM ifTrue: [(interpreterProxy isCharacterObject: oop) ifTrue: "Immediate in Spur" [^interpreterProxy characterValueOf: oop]. (interpreterProxy isFloatObject: oop) ifTrue: "Immediate in 64-bit Spur" [^interpreterProxy floatValueOf: oop]]] ifFalse: [self cppIf: SPURVM ifTrue: "No non-immediate characters in Spur" [] ifFalse: [(interpreterProxy isCharacterObject: oop) ifTrue: [^interpreterProxy characterValueOf: oop]]. (interpreterProxy isFloatObject: oop) ifTrue: [^interpreterProxy floatValueOf: oop]. oop = interpreterProxy nilObject ifTrue: [^0]. "@@: should we really allow this????" oop = interpreterProxy falseObject ifTrue: [^0]. oop = interpreterProxy trueObject ifTrue: [^1]. (interpreterProxy isLargePositiveIntegerObject: oop) ifTrue: + [^interpreterProxy positive64BitValueOf: oop]. + (interpreterProxy isLargeNegativeIntegerObject: oop) ifTrue: + [^interpreterProxy signed64BitValueOf: oop]]. - [self cppIf: BytesPerWord = 8 "Use cppIf: to get the return type of the function right. Should be sqInt on 32-bits." - ifTrue: [^interpreterProxy positive64BitValueOf: oop] - ifFalse: [^interpreterProxy positive32BitValueOf: oop]]]. ^interpreterProxy signedMachineIntegerValueOf: oop "<- will fail if not integer"!
Item was changed: ----- Method: ThreadedFFIPlugin>>isFloatAtomicType: (in category 'primitive support') ----- isFloatAtomicType: atomicTypeCode <inline: true> + "(atomicTypeCode >> 1) = (FFITypeSingleFloat >> 1)" + ^atomicTypeCode >> 1 = 6 ! - ^atomicTypeCode >> 1 = 6!
Item was changed: ----- Method: ThreadedIA32FFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') ----- ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState <var: #procAddr type: #'void *'> <var: #calloutState type: #'CalloutState *'> "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 | <var: #floatRet type: #double> + <var: #intRet type: #usqLong> "Support up to int64_t or uint64_t" - <var: #intRet type: #usqLong> <inline: #always> myThreadIndex := interpreterProxy disownVM: (self disownFlagsFor: calloutState).
(self allocaLiesSoSetSpBeforeCall or: [self mustAlignStack]) ifTrue: [self setsp: calloutState argVector].
atomicType := self atomicTypeOf: calloutState ffiRetHeader. (atomicType >> 1) = (FFITypeSingleFloat >> 1) ifTrue: [floatRet := self dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)()').
"undo any callee argument pops because it may confuse stack management with the alloca." (self isCalleePopsConvention: calloutState callFlags) ifTrue: [self setsp: calloutState argVector]. interpreterProxy ownVM: myThreadIndex.
^interpreterProxy floatObjectOf: floatRet].
intRet := self dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'usqLong (*)()').
"undo any callee argument pops because it may confuse stack management with the alloca." (self isCalleePopsConvention: calloutState callFlags) ifTrue: [self setsp: calloutState argVector]. 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: [^self ffiReturnPointer: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]. ^self ffiReturnStruct: (self addressOf: intRet) ofType: (self ffiReturnType: specOnStack) in: calloutState]. ^self ffiCreateIntegralResultOop: intRet ofAtomicType: atomicType in: calloutState!
Item was changed: ----- Method: ThreadedIA32FFIPlugin>>ffiPushSigned32:in: (in category 'marshalling') ----- ffiPushSigned32: value in: calloutState + <var: #value type: #sqInt> <var: #calloutState type: #'CalloutState *'> <inline: #always> calloutState currentArg + 4 > calloutState limit ifTrue: [^FFIErrorCallFrameTooBig]. + interpreterProxy longAt: calloutState currentArg put: (self cCoerceSimple: value to: #'signed int'). - interpreterProxy longAt: calloutState currentArg put: value. calloutState currentArg: calloutState currentArg + 4. ^0!
Item was changed: ----- Method: ThreadedIA32FFIPlugin>>ffiPushSigned64:in: (in category 'marshalling') ----- ffiPushSigned64: value in: calloutState + <var: #value type: #sqLong> - <var: #value type: #usqLong> <var: #calloutState type: #'CalloutState *'> <inline: #always> calloutState currentArg + 8 > calloutState limit ifTrue: [^FFIErrorCallFrameTooBig]. interpreterProxy longAt: calloutState currentArg put: (self cCoerceSimple: value to: #usqInt); longAt: calloutState currentArg + 4 put: (self cCoerceSimple: value >> 32 to: #usqInt). calloutState currentArg: calloutState currentArg + 8. ^0!
Item was changed: ----- Method: ThreadedIA32FFIPlugin>>ffiPushUnsigned32:in: (in category 'marshalling') ----- ffiPushUnsigned32: value in: calloutState + <var: #value type: #usqInt> <var: #calloutState type: #'CalloutState *'> <inline: #always> calloutState currentArg + 4 > calloutState limit ifTrue: [^FFIErrorCallFrameTooBig]. + interpreterProxy longAt: calloutState currentArg put: (self cCoerceSimple: value to: #'unsigned int'). - interpreterProxy longAt: calloutState currentArg put: value. calloutState currentArg: calloutState currentArg + 4. ^0!
vm-dev@lists.squeakfoundation.org