Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel-mt.114.mcz ==================== Summary ==================== Name: FFI-Kernel-mt.114 Author: mt Time: 18 June 2020, 4:18:55.256595 pm UUID: 46d8eb84-cb7b-1643-8d64-1c3191e8393f Ancestors: FFI-Kernel-mt.113 Fixes reading of external structs through external addresses ... which was off by 1 byte. Of course. ;-) Since structs are now read correctly from external addresses using pointer arithmetic, fixes related conversion/access methods in ExternalData. Adds a simple way to access sub-arrays in external data. Inspired by Collection protocol. Adds quick exit when trying to do pointer arithmetic with 0 offset. Adds size checks to ExternalData. =============== Diff against FFI-Kernel-mt.113 =============== Item was changed: ----- Method: ExternalAddress>>+ (in category 'arithmetic') ----- + offset "Create an address that is offset by the given number of bytes. More tricky than one would think due to the FFI's handling of ExternalAddress as pointer to an object so that 'self unsignedLongAt: ' would dereference." | bytes | + offset = 0 ifTrue: [^ self]. "Convert xaddr -> bytes" bytes := self asByteArrayPointer. "Update bytes using platform dependent accessors" self size = 4 ifTrue: [bytes unsignedLongAt: 1 put: (bytes unsignedLongAt: 1) + offset] ifFalse: [bytes unsignedLongLongAt: 1 put: (bytes unsignedLongLongAt: 1) + offset]. "Convert bytes -> xaddr" ^bytes asExternalPointer! Item was changed: ----- Method: ExternalAddress>>structAt:length: (in category 'accessing') ----- structAt: byteOffset length: length "Return the external address of the struct's first field. Ignore length." + ^ self + (byteOffset-1)! - ^ self + byteOffset! Item was changed: ----- Method: ExternalAddress>>structAt:put:length: (in category 'accessing') ----- structAt: byteOffset put: externalAddress length: length "Read length bytes from externalAddress and write it at this external address (plus byteOffset)." | start | + start := self + (byteOffset-1). - start := self + byteOffset. 1 to: length do: [:targetOffset | start byteAt: targetOffset put: (externalAddress byteAt: targetOffset)].! Item was changed: ----- Method: ExternalData>>at: (in category 'accessing') ----- at: index self - flag: #externalDataArray; assert: [index = 1 or: [type isAtomic]] description: 'Should not read non-atomic pointer as array'. + ((1 > index) or: [size notNil and: [index > size]]) + ifTrue: [^ self errorSubscriptBounds: index]. + ^ type asNonPointerType handle: handle at: ((index-1) * type asNonPointerType byteSize) + 1! Item was changed: ----- Method: ExternalData>>at:put: (in category 'accessing') ----- at: index put: value self - flag: #externalDataArray; assert: [index = 1 or: [type isAtomic]] description: 'Should not read non-atomic pointer as array'. + ((1 > index) or: [size notNil and: [index > size]]) + ifTrue: [^ self errorSubscriptBounds: index]. + ^ type asNonPointerType handle: handle at: ((index-1) * type asNonPointerType byteSize) + 1 put: value! Item was added: + ----- Method: ExternalData>>copyFrom:to: (in category 'accessing') ----- + copyFrom: firstIndex to: lastIndex + + ^ (self from: firstIndex to: lastIndex) getExternalData! Item was added: + ----- Method: ExternalData>>from:to: (in category 'accessing') ----- + from: firstIndex to: lastIndex + "Only copy data if already in object memory, that is, as byte array." + + | byteOffset numElements byteSize | + lastIndex < firstIndex ifTrue: [ + ^ (ExternalData fromHandle: #[] type: type) + size: 0; yourself]. + + ((1 > firstIndex) or: [size notNil and: [lastIndex > size]]) + ifTrue: [^ self errorSubscriptBounds: lastIndex]. + + byteOffset := ((firstIndex-1) * type asNonPointerType byteSize)+1. + numElements := lastIndex - firstIndex + 1. + byteSize := size * type asNonPointerType byteSize. + + ^ handle isExternalAddress + ifTrue: [(ExternalData + fromHandle: handle + byteOffset - 1 + type: type) size: numElements; yourself] + ifFalse: [(ExternalData + fromHandle: (handle copyFrom: byteOffset to: byteOffset+byteSize) + type: type) size: numElements; yourself]! Item was added: + ----- Method: ExternalData>>getExternalData (in category 'accessing - external structures') ----- + getExternalData + "Reads all bytes into object memory." + + | data | + handle isExternalAddress ifFalse: [^ self]. + self sizeCheck. + + data := ByteArray new: size * type asNonPointerType byteSize. + 1 to: data size do: [:index | + data unsignedByteAt: index put: (handle unsignedByteAt: index)]. + + ^ (ExternalData + fromHandle: data + type: type asNonPointerType) + size: size! Item was changed: ----- Method: ExternalData>>getExternalStructure (in category 'accessing - external structures') ----- getExternalStructure "Reads an external structure from this external data. If the receiver's handle is an external address, the structure's fields will be copied into object memory. Use #asExternalStructure if you want to avoid this copy." self assert: [type referentClass includesBehavior: ExternalStructure] description: 'Wrong type'. + ^ handle isExternalAddress + ifTrue: [self getExternalData getExternalStructure] + ifFalse: [type referentClass fromHandle: handle]! - ^ self at: 1! Item was changed: ----- Method: ExternalData>>getExternalUnion (in category 'accessing - external structures') ----- getExternalUnion "Reads an external union from this external data. If the receiver's handle is an external address, the union's fields will be copied into object memory. Use #asExternalUnion if you want to avoid this copy." self assert: [type referentClass includesBehavior: ExternalUnion] description: 'Wrong type'. + ^ handle isExternalAddress + ifTrue: [self getExternalData getExternalUnion] + ifFalse: [type referentClass fromHandle: handle]! - ^ self at: 1! Item was changed: ----- Method: ExternalStructure>>asExternalData (in category 'converting') ----- asExternalData + ^ (ExternalData fromHandle: self getHandle type: self externalType) + size: 1; yourself! - ^ ExternalData fromHandle: self getHandle type: self externalType! |
Free forum by Nabble | Edit this page |