<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>