<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
<img id="5540fe51-8bb8-4fd3-af69-e946a61d89f7" src="cid:21481d5f-7cf7-483d-b132-b78bc543f065" width="866" height="287"></img><br><div class="mb_sig"></div>
<blockquote class="history_container" type="cite" style="border-left-style: solid;border-width: 1px;margin-top: 20px;margin-left: 0px;padding-left: 10px;min-width: 500px">
<p style="color: #AAAAAA; margin-top: 10px;">Am 04.05.2021 16:51:53 schrieb commits@source.squeak.org <commits@source.squeak.org>:</p><div style="font-family:Arial,Helvetica,sans-serif">Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:<br>http://source.squeak.org/FFI/FFI-Kernel-mt.130.mcz<br><br>==================== Summary ====================<br><br>Name: FFI-Kernel-mt.130<br>Author: mt<br>Time: 4 May 2021, 4:51:43.338881 pm<br>UUID: 5c667740-5577-4541-876e-0be05657a18c<br>Ancestors: FFI-Kernel-mt.129<br><br>Adds (simple?) support for array types such as char[12] or MyStruct[5].<br><br>Note that there is no plugin support for array types, which means that:<br>1. All FFI calls denoting array types will be passed as pointer type<br>2. Return types might work with atomic arrays (e.g. char[12]) but definitely not with struct arrays because the plugin will just give you a new instance of your struct with the handle, thus omitting the size information.<br><br>Still, now you can finally embed array types in your struct definition:<br><br>typedef struct {<br> double d1;<br> int32_t[5] a5i2;<br>} FFITestSdA5i<br><br>:-)<br><br>More open tasks:<br>- Array types are not cached and created on-demand. See #arrayTypeNamed: for placing a cache.<br>- #typedef (in Tools) is not yet supported.<br><br>=============== Diff against FFI-Kernel-mt.129 ===============<br><br>Item was added:<br>+ ExternalType subclass: #ExternalArrayType<br>+ instanceVariableNames: ''<br>+ classVariableNames: ''<br>+ poolDictionaries: ''<br>+ category: 'FFI-Kernel'!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType class>>newTypeForContentType:size: (in category 'as yet unclassified') -----<br>+ newTypeForContentType: contentType size: numElements<br>+ "!!!!!! Be aware that only the pointer type can be used in calls. As of SqueakFFIPrims VMMaker.oscog-eem.2950, there is no actual support for array types in the FFI plugin !!!!!!"<br>+ <br>+ | type pointerType headerWord byteSize |<br>+ contentType ifNil: [^ nil].<br>+ numElements < 0 ifTrue: [^ nil].<br>+ <br>+ self<br>+ assert: [contentType isPointerType not]<br>+ description: 'No support for pointers as content type yet!!'.<br>+ <br>+ type := self basicNew.<br>+ pointerType := ExternalType basicNew.<br>+ <br>+ "1) Regular type"<br>+ byteSize := numElements * contentType byteSize.<br>+ self assert: [byteSize <= FFIStructSizeMask].<br>+ headerWord := contentType headerWord copy.<br>+ headerWord := headerWord bitClear: FFIStructSizeMask.<br>+ headerWord := headerWord bitOr: byteSize.<br>+ type<br>+ setReferencedType: pointerType;<br>+ compiledSpec: (WordArray with: headerWord);<br>+ byteAlignment: contentType byteAlignment;<br>+ setReferentClass: contentType referentClass. <br>+ <br>+ "2) Pointer type. Reuse the compiledSpec of the content-type's pointer type."<br>+ pointerType<br>+ setReferencedType: type;<br>+ compiledSpec: contentType asPointerType compiledSpec copy;<br>+ byteAlignment: contentType asPointerType byteAlignment;<br>+ setReferentClass: contentType asPointerType referentClass.<br>+ <br>+ ^ type!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>checkType (in category 'external structure') -----<br>+ checkType<br>+ <br>+ self class extraTypeChecks ifFalse: [^ self].<br>+ <br>+ self<br>+ assert: [self isPointerType not]<br>+ description: 'Convert to ExternalType to use this feature'.!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>contentType (in category 'accessing') -----<br>+ contentType<br>+ <br>+ ^ ExternalType typeNamed: super typeName!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>handle:at: (in category 'external data') -----<br>+ handle: handle at: byteOffset<br>+ "Read the receiver's external type using the given handle and the byteOffset. This is the dynamic version of #readFieldAt:."<br>+ <br>+ self checkType.<br>+ <br>+ ^ (ExternalData<br>+ fromHandle: (handle structAt: byteOffset length: self byteSize)<br>+ type: self contentType) size: self size; yourself!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>handle:at:put: (in category 'external data') -----<br>+ handle: handle at: byteOffset put: value<br>+ "Write a value using the receiver's external type at the given handle and byteOffset. This is the dynamic version of #writeFieldAt:with:."<br>+ <br>+ self checkType.<br>+ <br>+ handle<br>+ structAt: byteOffset<br>+ put: value getHandle<br>+ length: self byteSize.!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>isArrayType (in category 'testing') -----<br>+ isArrayType<br>+ <br>+ ^ true!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>readFieldAt: (in category 'external structure') -----<br>+ readFieldAt: byteOffset<br>+ "Answer a string defining the accessor to an entity of the receiver type starting at the given byte offset. <br>+ Private. Used for field definition only."<br>+ <br>+ self checkType.<br>+ <br>+ ^ String streamContents:[:s |<br>+ s nextPutAll:'^ (ExternalData fromHandle: (handle structAt: ';<br>+ print: byteOffset;<br>+ nextPutAll: ' length: ';<br>+ print: self byteSize;<br>+ nextPutAll: ') type: '.<br>+ <br>+ self contentType isAtomic<br>+ ifTrue: [s nextPutAll: 'ExternalType ', self contentType typeName]<br>+ ifFalse: [s nextPutAll: self contentType typeName, ' externalType'].<br>+ <br>+ s nextPutAll: ') size: '; print: self size; nextPutAll: '; yourself']!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>size (in category 'accessing') -----<br>+ size<br>+ "Answers the number of elements for this array type."<br>+ <br>+ ^ self byteSize / self contentType byteSize!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>storeOn: (in category 'printing') -----<br>+ storeOn: aStream<br>+ <br>+ aStream<br>+ nextPut: $(;<br>+ nextPutAll: ExternalType name; space;<br>+ nextPutAll: #arrayTypeNamed:; space;<br>+ store: self typeName;<br>+ nextPut: $).!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>typeName (in category 'accessing') -----<br>+ typeName<br>+ <br>+ ^ String streamContents: [:stream |<br>+ stream<br>+ nextPutAll: super typeName;<br>+ nextPut: $[;<br>+ nextPutAll: self size asString;<br>+ nextPut: $]]!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>writeFieldArgName (in category 'external structure') -----<br>+ writeFieldArgName<br>+ <br>+ ^ 'anExternalData_', self contentType typeName, self size!<br><br>Item was added:<br>+ ----- Method: ExternalArrayType>>writeFieldAt:with: (in category 'external structure') -----<br>+ writeFieldAt: byteOffset with: valueName<br>+ <br>+ self checkType.<br>+ <br>+ ^ String streamContents:[:s |<br>+ s nextPutAll:'handle structAt: ';<br>+ print: byteOffset;<br>+ nextPutAll: ' put: ';<br>+ nextPutAll: valueName;<br>+ nextPutAll: ' getHandle length: ';<br>+ print: self byteSize]!<br><br>Item was added:<br>+ ----- Method: ExternalType class>>arrayTypeNamed: (in category 'instance lookup') -----<br>+ arrayTypeNamed: typeName<br>+ "Lookup fails if content type is not present."<br>+ <br>+ | contentType |<br>+ self flag: #todo. "mt: Cache array types?"<br>+ <br>+ (contentType := self typeNamed: (typeName copyFrom: 1 to: (typeName indexOf: $[) - 1))<br>+ ifNil: [^ nil].<br>+ <br>+ ^ self newTypeNamed: typeName!<br><br>Item was added:<br>+ ----- Method: ExternalType class>>newTypeForContentType:size: (in category 'instance creation') -----<br>+ newTypeForContentType: contentType size: numElements<br>+ <br>+ ^ ExternalArrayType newTypeForContentType: contentType size: numElements!<br><br>Item was changed:<br> ----- Method: ExternalType class>>newTypeNamed: (in category 'instance creation') -----<br> newTypeNamed: aTypeName<br>+ "Create a new struct type or array type. Not needed for atomic types; see #initializeDefaultTypes."<br>+ <br>+ | structClass contentType contentTypeName numElements |<br>- <br>- | structClass |<br> self<br> assert: [aTypeName last ~~ $*]<br> description: 'Pointer type will be created automatically'.<br>+ <br>+ aTypeName last == $] ifTrue: [<br>+ "array type, e.g., char[50]"<br>+ contentTypeName:= aTypeName copyFrom: 1 to: (aTypeName indexOf: $[) - 1.<br>+ contentType := (self typeNamed: contentTypeName) "Create new if not already there."<br>+ ifNil: [self newTypeNamed: contentTypeName]. <br>+ numElements := ((aTypeName copyFrom: (aTypeName indexOf: $[) + 1 to: aTypeName size - 1) asInteger)<br>+ ifNil: [0].<br>+ ^ self<br>+ newTypeForContentType: contentType<br>+ size: numElements].<br> <br> structClass := (self environment classNamed: aTypeName)<br> ifNotNil: [:class | (class includesBehavior: ExternalStructure) ifTrue: [class]].<br> <br> ^ structClass<br> ifNil: [self newTypeForUnknownNamed: aTypeName]<br> ifNotNil: [self newTypeForStructureClass: structClass]!<br><br>Item was changed:<br> ----- Method: ExternalType class>>typeNamed: (in category 'instance lookup') -----<br> typeNamed: typeName<br> "Supports pointer-type lookup for both atomic and structure types.<br> Examples: 'long', 'long*', 'long *' or 'MyStruct', 'MyStruct*', 'MyStruct *'"<br> <br>+ | isPointerType isArrayType actualTypeName type |<br>+ isArrayType := false.<br>- | isPointerType actualTypeName type |<br> (isPointerType := typeName last == $*)<br> ifTrue: [actualTypeName := typeName allButLast withoutTrailingBlanks]<br>+ ifFalse: [(isArrayType := typeName last == $])<br>+ ifFalse: [actualTypeName := typeName]].<br>- ifFalse: [actualTypeName := typeName].<br> <br>+ isArrayType<br>+ ifTrue: [^ self arrayTypeNamed: typeName].<br>+ <br> (Symbol lookup: actualTypeName)<br> ifNotNil: [:sym | actualTypeName := sym].<br> <br> type := (self atomicTypeNamed: actualTypeName)<br> ifNil: [self structTypeNamed: actualTypeName].<br> <br> ^ type ifNotNil: [isPointerType ifTrue: [type asPointerType] ifFalse: [type]]!<br><br>Item was added:<br>+ ----- Method: ExternalType>>isArrayType (in category 'testing') -----<br>+ isArrayType<br>+ <br>+ ^ false!<br><br>Item was changed:<br> ----- Method: Parser>>externalType: (in category '*FFI-Kernel') -----<br> externalType: descriptorClass<br> "Parse and return an external type"<br>+ | xType typeName isArrayType |<br>- | xType typeName |<br> typeName := here. "Note that pointer token is not yet parsed!!"<br>+ self advance.<br>+ (isArrayType := self matchToken: $[)<br>+ ifTrue: [<br>+ typeName := typeName, '[', here, ']'.<br>+ self advance.<br>+ self matchToken: $]].<br> (xType := descriptorClass typeNamed: typeName)<br> ifNil: [<br> "Raise an error if user is there"<br> self interactive ifTrue: [^nil].<br> "otherwise go over it silently -- use an unknown struct type"<br>+ xType := descriptorClass newTypeNamed: typeName].<br>+ isArrayType ifTrue: [<br>+ self flag: #todo. "mt: We must send arrays as pointers."<br>+ xType := xType asPointerType].<br>- xType := descriptorClass newTypeNamed: here].<br>- self advance.<br> ^ (self matchToken: #*)<br> ifTrue:[xType asPointerType]<br> ifFalse:[(self matchToken: #**)<br> ifTrue: [xType asPointerToPointerType]<br> ifFalse: [xType]]!<br><br><br></div></blockquote></div>