FFI: FFI-Kernel-mt.181.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

FFI: FFI-Kernel-mt.181.mcz

commits-2
Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel-mt.181.mcz

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

Name: FFI-Kernel-mt.181
Author: mt
Time: 8 June 2021, 11:53:52.533752 am
UUID: d7c02d46-f7b6-4d41-a63a-dd327d60367a
Ancestors: FFI-Kernel-mt.180

Fixes and clean-up in array types. No need for #isPointerTypeForArray because #referentClass is used only for alias-to-array types as in other types. The #contentType has its own instVar.

=============== Diff against FFI-Kernel-mt.180 ===============

Item was changed:
  ----- Method: ExternalArrayType class>>newTypeForContentType:size: (in category 'instance creation') -----
  newTypeForContentType: contentType size: numElements
  "!!!!!! 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 !!!!!!"
 
  | type pointerType headerWord byteSize |
  self
  flag: #contentVsContainer;
  assert: [contentType isTypeAlias or: [contentType isArrayType not]]
  description: 'No support for direct multi-dimensional containers yet. Use type aliases.'.
 
  self
  assert: [contentType isVoid not]
  description: 'No array types for void type!!'.
 
  self
  assert: [
  (ArrayTypes at: contentType typeName
  ifPresent: [:sizes | sizes at: numElements ifAbsent: [nil]]
  ifAbsent: [nil] ) isNil]
  description: 'Array type already exists. Use #typeNamed: to access it.'.
 
  type := ExternalArrayType basicNew.
  pointerType := ExternalPointerType basicNew.
 
  "1) Regular type"
  byteSize := numElements
  ifNil: [0] ifNotNil: [numElements * contentType byteSize].
  headerWord := contentType headerWord.
  headerWord := headerWord bitClear: FFIStructSizeMask.
  headerWord := headerWord bitOr: (byteSize min: FFIStructSizeMask).
  type
  setReferencedType: pointerType;
  compiledSpec: (WordArray with: headerWord);
  byteAlignment: (numElements ifNil: [0] ifNotNil: [contentType byteAlignment]);
+ setReferentClass: nil; "Like atomics and pointers-to-atomics, no dedicated class exists."
- setReferentClass: contentType referentClass;
  setContentType: contentType;
  setSize: numElements;
  setByteSize: byteSize.
 
  "2) Pointer type. Reuse the compiledSpec of the content-type's pointer type."
  pointerType
  setReferencedType: type;
  compiledSpec: (WordArray with: (self pointerSpec bitOr: FFIFlagAtomic "HACK!! To deceive the FFI plugin :)"));
  byteAlignment: self pointerAlignment;
  setReferentClass: nil.
 
  "3) Remember this new array type."
  (ArrayTypes at: contentType typeName ifAbsentPut: [WeakValueDictionary new])
  at: numElements put: type.
 
  ^ type!

Item was changed:
  ----- Method: ExternalArrayType>>allocate (in category 'external data') -----
  allocate
+ "Overwritten to allocate specific to contentType and size. Check referentClass to consider #isTypeAlias."
+
-
  | data |
  data := self contentType allocate: self size.
+ ^ referentClass
+ ifNil: [data "genuine arrays"]
+ ifNotNil: [referentClass fromHandle: data getHandle]!
- ^ self isTypeAlias
- ifTrue: [referentClass fromHandle: data getHandle]
- ifFalse: [data]!

Item was changed:
  ----- Method: ExternalArrayType>>allocateExternal (in category 'external data') -----
  allocateExternal
+ "Overwritten to allocate specific to contentType and size. Check referentClass to consider #isTypeAlias."
+
-
  | data |
  data := self contentType allocateExternal: self size.
+ ^ referentClass
+ ifNil: [data "genuine arrays"]
+ ifNotNil: [referentClass fromHandle: data getHandle]!
- ^ self isTypeAlias
- ifTrue: [referentClass fromHandle: data getHandle]
- ifFalse: [data]!

Item was changed:
  ----- Method: ExternalArrayType>>handle:at: (in category 'external data') -----
  handle: handle at: byteOffset
 
  | resultHandle |
  resultHandle := handle structAt: byteOffset length: self byteSize.
+ ^ referentClass
+ ifNotNil: [referentClass fromHandle: resultHandle]
+ ifNil: [ExternalData fromHandle: resultHandle type: self]!
- ^ self isTypeAlias
- ifTrue: [referentClass fromHandle: resultHandle]
- ifFalse: [ExternalData fromHandle: resultHandle type: self]!

Item was added:
+ ----- Method: ExternalArrayType>>newContentType: (in category 'private') -----
+ newContentType: typeOrNil
+ "My content type has changed. Update my byteSize."
+
+ | newByteSize newHeaderWord |
+ (contentType := typeOrNil)
+ ifNil: [ "my class has been removed - make me empty"
+ compiledSpec := WordArray with: self class structureSpec.
+ byteAlignment := 1]
+ ifNotNil: [ "my class has been changed - update my compiledSpec"
+ newHeaderWord := contentType headerWord.
+ newByteSize := size ifNil: [0] ifNotNil: [size * (newHeaderWord bitAnd: FFIStructSizeMask)].
+ newHeaderWord := newHeaderWord bitClear: FFIStructSizeMask.
+ newHeaderWord := newHeaderWord bitOr: (newByteSize min: FFIStructSizeMask).
+ compiledSpec := WordArray with: newHeaderWord.
+ byteAlignment := contentType byteAlignment.
+ byteSize := newByteSize]!

Item was changed:
  ----- Method: ExternalArrayType>>newReferentClass: (in category 'private') -----
  newReferentClass: classOrNil
  "The class I'm referencing has changed, which affects arrays of structs. Update my byteSize."
 
- | newByteSize newHeaderWord |
  (referentClass := classOrNil)
+ ifNil: [ "my class has been removed - make me 'struct { void }'"
- ifNil: [ "my class has been removed - make me empty"
  compiledSpec := WordArray with: self class structureSpec.
+ byteAlignment := 1.
+ contentType := size := byteSize := nil]
+ ifNotNil: [ "I am an alias-to-array type. Update my specs."
+ | originalType |
+ originalType := referentClass originalType.
+ self assert: [originalType isArrayType].
+
+ compiledSpec := originalType compiledSpec.
+ byteAlignment := originalType byteAlignment.
+
+ contentType := originalType contentType.
+ size := originalType size.
+ byteSize := originalType byteSize]!
- byteAlignment := 1]
- ifNotNil: [ "my class has been changed - update my compiledSpec"
- newHeaderWord := referentClass compiledSpec first.
- newByteSize := size ifNil: [0] ifNotNil: [size * (newHeaderWord bitAnd: FFIStructSizeMask)].
- newHeaderWord := newHeaderWord bitClear: FFIStructSizeMask.
- newHeaderWord := newHeaderWord bitOr: (newByteSize min: FFIStructSizeMask).
- compiledSpec := WordArray with: newHeaderWord.
- byteAlignment := referentClass byteAlignment.
- byteSize := newByteSize]!

Item was changed:
  ----- Method: ExternalArrayType>>readFieldAt: (in category 'external structure') -----
  readFieldAt: byteOffset
 
+ ^ referentClass
+ ifNotNil: [
- ^ self isTypeAlias
- ifTrue: [
  '^ {1} fromHandle: (handle structAt: {1} length: {2})'
  format: {
  referentClass name.
  byteOffset.
  self byteSize}]
+ ifNil: [
- ifFalse: [
  '^ ExternalData fromHandle: (handle structAt: {1} length: {2}) type: {3}'
  format: {
  byteOffset.
  self byteSize.
  self storeStringForField}]!

Item was changed:
  ----- Method: ExternalArrayType>>storeOn: (in category 'printing') -----
  storeOn: aStream
 
+ referentClass ifNotNil: [
- self isTypeAlias ifTrue: [
  ^ aStream
  nextPutAll: referentClass name;
  nextPutAll: ' externalType'].
 
  aStream nextPut: $(.
  self contentType storeOn: aStream.
  aStream nextPutAll: ' asArrayType: '.
  aStream nextPutAll: self size asString.
  aStream nextPut: $).!

Item was changed:
  ----- Method: ExternalArrayType>>typeName (in category 'accessing') -----
  typeName
 
+ referentClass
+ ifNotNil: [^ super typeName].
- self isTypeAlias
- ifTrue: [^ super typeName].
 
  ^ String streamContents: [:stream | | inParentheses |
  (inParentheses := self contentType isPointerType not
  and: [self contentType asPointerType isTypeAlias])
  ifTrue: [stream nextPut: $(. "e.g. (*DoublePtr)[5]"].
 
  stream nextPutAll: self contentType typeName.
 
  inParentheses ifTrue: [stream nextPut: $)].
 
  stream nextPut: $[.
  self size ifNotNil: [stream nextPutAll: self size asString].
  stream nextPut: $]. ]!

Item was changed:
  ----- Method: ExternalPointerType>>handle:at: (in category 'external data') -----
  handle: handle at: byteOffset
 
+ ^ referentClass
- | referentClassToUse |
- referentClassToUse := self isPointerTypeForArray
- ifFalse: [referentClass]
- ifTrue: [self asNonPointerType isTypeAlias
- ifTrue: [self asNonPointerType referentClass] ifFalse: [nil]].
- ^ referentClassToUse
  ifNotNil: [
+ referentClass fromHandle: (handle pointerAt: byteOffset length: self byteSize)]
- referentClassToUse fromHandle: (handle pointerAt: byteOffset length: self byteSize)]
  ifNil: [
  ExternalData
  fromHandle: (handle pointerAt: byteOffset length: self byteSize)
  type: self asNonPointerType "content type"]!

Item was removed:
- ----- Method: ExternalPointerType>>isPointerTypeForArray (in category 'testing') -----
- isPointerTypeForArray
- "referentClass is currently nil for pointer-to-array types. All operations on referentClass should check this to then use the referentClass from the non-pointer type. Might be changed once array information are encoded in the headerWord."
-
- ^ self asNonPointerType isArrayType!

Item was removed:
- ----- Method: ExternalPointerType>>newReferentClass: (in category 'private') -----
- newReferentClass: classOrNil
- "The class I'm referencing has changed. Keep pointer types for array types free of the referentClass so that FFI calls return ExternalData."
-
- self isPointerTypeForArray
- ifTrue: [referentClass := nil]
- ifFalse: [referentClass := classOrNil].!

Item was changed:
  ----- Method: ExternalPointerType>>originalType (in category 'accessing - type alias') -----
  originalType
  "Overwritten to look into my referencedType. See #isTypeAliasReferenced."
 
- self isPointerTypeForArray ifTrue: [
- ^ self asNonPointerType originalType asPointerType].
-
  ^ self "e.g. MyStructPtr" asNonPointerType isTypeAlias "e.g. *MyStructPtr"
  ifTrue: [super originalType asPointerType "e.g. MyStruct*, not MyStruct"]
  ifFalse: [super originalType]!

Item was changed:
  ----- Method: ExternalPointerType>>readFieldAt: (in category 'external structure') -----
  readFieldAt: byteOffset
 
- | referentClassToUse |
- referentClassToUse := self isPointerTypeForArray
- ifFalse: [referentClass]
- ifTrue: [self asNonPointerType isTypeAlias
- ifTrue: [self asNonPointerType referentClass] ifFalse: [nil]].
  ^ '^ {1} fromHandle: (handle pointerAt: {2} length: {3}){4}'
  format: {
+ (referentClass ifNil: [ExternalData]) name.
- (referentClassToUse ifNil: [ExternalData]) name.
  byteOffset.
  self byteSize.
+ referentClass ifNotNil: [''] ifNil: [
- referentClassToUse ifNotNil: [''] ifNil: [
  ' type: ', self asNonPointerType "content type" storeStringForField]}!

Item was changed:
  ----- Method: ExternalType class>>noticeModificationOf: (in category 'housekeeping') -----
  noticeModificationOf: aClass
+ "A subclass of ExternalStructure has been redefined."
- "A subclass of ExternalStructure has been redefined.
- Clean out any obsolete references to its type."
 
  aClass withAllSubclassesDo: [:cls | | typeName type |
  typeName := cls name.
 
- ArrayTypes at: typeName ifPresent: [:sizes |
- sizes do: [:arrayType | arrayType ifNotNil: [
- arrayType newReferentClass: cls.
- arrayType asPointerType newReferentClass: cls]]].
-
  (type := StructTypes at: typeName ifAbsent: [])
  ifNotNil: [
  type newReferentClass: cls.
  type asPointerType newReferentClass: cls.
+ type newTypeAlias].
+
+ ArrayTypes at: typeName ifPresent: [:sizes |
+ sizes do: [:arrayType | arrayType ifNotNil: [
+ arrayType newContentType: type]]].
+
+ "Alias-to-array types, which are stored in StructTypes, will not update via #newContentType:. We scan StructTypes for #isArrayType to find such aliases to then call #newContentType:."
+ StructTypes do: [:each |
+ (each notNil and: [each isArrayType and: [each contentType == type]])
+ ifTrue: [each newContentType: type]]].!
- type newTypeAlias]]!

Item was changed:
  ----- Method: ExternalType class>>noticeRemovalOf: (in category 'housekeeping') -----
  noticeRemovalOf: aClass
  "A subclass of ExternalStructure is being removed.
  Clean out any obsolete references to its type."
+
+ | typeName type |
+ typeName := aClass name.
+
+ (type := StructTypes at: typeName ifAbsent: [])
+ ifNotNil: [
+ type newReferentClass: nil.
+ type asPointerType newReferentClass: nil].
+
- | type |
- type := StructTypes at: aClass name ifAbsent:[nil].
- type == nil ifFalse:[
- type newReferentClass: nil.
- type asPointerType newReferentClass: nil].
  ArrayTypes at: aClass name ifPresent: [:sizes |
+ sizes do: [:arrayType | arrayType ifNotNil: [
+ arrayType newContentType: nil]].
+
+ "Alias-to-array types, which are stored in StructTypes, will not update via #newContentType:. We scan StructTypes for #isArrayType to find such aliases to then call #newContentType:."
+ StructTypes do: [:each |
+ (each notNil and: [each isArrayType and: [each contentType == type]])
+ ifTrue: [each newContentType: type]]].!
- sizes do: [:arrayType |
- arrayType newReferentClass: nil.
- arrayType asPointerType newReferentClass: nil]].!

Item was changed:
  ----- Method: ExternalUnknownType>>becomeArrayType (in category 'construction') -----
  becomeArrayType
  "I am now positive on #isTypeAliasForArray :-) Make myself an array type. Not that easy because Arraytype as extra instVars #size and #contentType."
 
  | newArrayType |
  newArrayType := ExternalArrayType basicNew
  compiledSpec: self compiledSpec;
  byteAlignment: self byteAlignment;
  setReferentClass: referentClass;
  setReferencedType: referencedType;
  setContentType: referentClass originalType contentType; "Hmm..."
  setSize: referentClass originalType size; "Hmm..."
  setByteSize: referentClass originalType byteSize; "Hmm..."
  yourself.
 
- "No referentClass for pointer types of array types."
- referencedType setReferentClass: nil.
-
  self becomeForward: newArrayType.
 
  ^ newArrayType!