Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI: http://source.squeak.org/FFI/FFI-Kernel-mt.194.mcz
==================== Summary ====================
Name: FFI-Kernel-mt.194 Author: mt Time: 11 August 2021, 10:32:43.073115 am UUID: dd919d6b-185f-ee40-9061-e47adb6fa72e Ancestors: FFI-Kernel-mt.193
Code clean-up and refactoring: - Rename ...withAccessors: to ...generateAccessors: - Rename policy #generated to #ifGenerated - Rename policy #absent to #ifAbsent - Deprecate #compileFields and #compileFields: in favor if #defineFields and #defineFields: - Add #defineChangedFields(:), which uses #hasFieldLayoutChanged: and thus distinguishes itself from #defineFields(:) - After code loading or class reshaping, call #triggerDefineAllChangedFields instead of #triggerDefineAllFields - Remove obsolete #byteSize from ExternalStructure class; see its instance side
Note that this also fixes a regression, that is, let #defineAllFields and #defineAllChangedFields work as expected.
Note that #defineFields(:) will always compile the field spec and generate (missing) field accessors #ifGenerated.
=============== Diff against FFI-Kernel-mt.193 ===============
Item was removed: - ----- Method: ExternalStructure class>>byteSize (in category 'external type') ----- - byteSize - "Return the size in bytes of this structure." - ^self compiledSpec first bitAnd: FFIStructSizeMask!
Item was changed: ----- Method: ExternalStructure class>>compileAllFields (in category 'system startup') ----- compileAllFields - " - ExternalStructure compileAllFields - " - | priorAuthorInitials fieldSpec | - priorAuthorInitials := Utilities authorInitialsPerSe. - [Utilities setAuthorInitials: 'FFI'. - - self allStructuresInCompilationOrder do: [:structClass | - fieldSpec := structClass fields. - (structClass hasFieldLayoutChanged: fieldSpec) - ifTrue: [structClass compileFields: fieldSpec]. - structClass organization removeEmptyCategories]. - "Compilation of fields only needs external types temporarily. Non-weak references to external types are only in methods with FFI calls." - ExternalType cleanupUnusedTypes.
+ self deprecated: 'Use #defineAllFields.'. + self defineAllFields.! - ] ensure: [Utilities setAuthorInitials: priorAuthorInitials]!
Item was changed: ----- Method: ExternalStructure class>>compileFields (in category 'field definition') ----- compileFields - "Public. Define all the fields in the receiver. Only re-generate changed field accessors if auto-generated in the first place."
+ self deprecated: 'Use #defineFields'. + self defineFields.! - self isSkipped ifTrue: [^ nil]. - self compileFields: self fields.!
Item was changed: ----- Method: ExternalStructure class>>compileFields: (in category 'field definition') ----- compileFields: fieldSpec + + self deprecated: 'Use #defineFields:'. + self defineFields: fieldSpec.! - "Private. Use #compileFields." - - self compileFields: fieldSpec withAccessors: #generated. - ExternalType noticeModificationOf: self.!
Item was added: + ----- Method: ExternalStructure class>>compileFields:generateAccessors: (in category 'field definition - support') ----- + compileFields: specArray generateAccessors: aSymbol + "Private. Use #compileFields or #defineFields. Compile a type specification for the FFI calls. + + Eventually generate the field accessors according to following rules: + - aSymbol = #always always generate the accessors + - aSymbol = #never never generate the accessors + - aSymbol = #ifGenerated only generate the auto-generated accessors + - aSymbol = #ifAbsent only generate the absent accessors" + + (self isTypeAlias: specArray) + ifTrue: [self compileTypeAliasSpec: specArray generateAccessors: aSymbol] + ifFalse: [self compileStructureSpec: specArray generateAccessors: aSymbol]!
Item was removed: - ----- Method: ExternalStructure class>>compileFields:withAccessors: (in category 'field definition') ----- - compileFields: specArray withAccessors: aSymbol - "Private. Use #compileFields or #defineFields. Compile a type specification for the FFI calls. - - Eventually generate the field accessors according to following rules: - - aSymbol = #always always generate the accessors - - aSymbol = #never never generate the accessors - - aSymbol = #generated only generate the auto-generated accessors - - aSymbol = #absent only generate the absent accessors" - - (self isTypeAlias: specArray) - ifTrue: [self compileTypeAliasSpec: specArray withAccessors: aSymbol] - ifFalse: [self compileStructureSpec: specArray withAccessors: aSymbol]!
Item was removed: - ----- Method: ExternalStructure class>>compileFieldsSafely (in category 'field definition') ----- - compileFieldsSafely - - [self compileFields] - ifError: [:msg | Transcript showln: '[FFI] Field compilation failed: ', msg].!
Item was added: + ----- Method: ExternalStructure class>>compileStructureSpec:generateAccessors: (in category 'field definition - support') ----- + compileStructureSpec: specArray generateAccessors: aSymbol + "Compile a type specification for the FFI calls. + Return the newly compiled spec. + + Eventually generate the field accessors according to following rules: + - aSymbol = #always always generate the accessors + - aSymbol = #never never generate the accessors + - aSymbol = #ifGenerated only generate the auto-generated accessors + - aSymbol = #ifAbsent only generate the absent accessors" + + | newByteAlignment byteOffset typeSpec newCompiledSpec | + byteOffset := 0. + newByteAlignment := self minStructureAlignment. + typeSpec := WriteStream on: (WordArray new: 10). + typeSpec nextPut: FFIFlagStructure. + specArray do: [:spec | + | fieldName fieldTypeName externalType typeSize fieldAlignment | + fieldName := spec first. + fieldTypeName := spec second. + externalType := (ExternalType typeNamed: fieldTypeName) + ifNil: [self errorTypeNotFound: spec second]. + typeSize := externalType byteSize. + fieldAlignment := (externalType byteAlignment + max: self minFieldAlignment) + min: self maxFieldAlignment. + byteOffset := byteOffset alignedTo: fieldAlignment. + newByteAlignment := newByteAlignment max: fieldAlignment. + spec size > 2 ifTrue: ["extra size" + spec third < typeSize + ifTrue: [^ self error: 'Explicit type size is less than expected']. + typeSize := spec third. + ]. + (fieldName notNil and: [self shouldGenerateAccessorsFor: fieldName policy: aSymbol]) ifTrue: [ + self generateStructureFieldAccessorsFor: fieldName startingAt: byteOffset + 1 type: externalType. + ]. + typeSpec nextPutAll: (externalType embeddedSpecWithSize: typeSize). + byteOffset := byteOffset + typeSize. + ]. + newByteAlignment := newByteAlignment min: self maxStructureAlignment. + byteOffset := byteOffset alignedTo: newByteAlignment. + newCompiledSpec := typeSpec contents. + newCompiledSpec at: 1 put: (byteOffset bitOr: FFIFlagStructure). + self + setCompiledSpec: newCompiledSpec + byteAlignment: newByteAlignment.!
Item was removed: - ----- Method: ExternalStructure class>>compileStructureSpec:withAccessors: (in category 'field definition - support') ----- - compileStructureSpec: specArray withAccessors: aSymbol - "Compile a type specification for the FFI calls. - Return the newly compiled spec. - - Eventually generate the field accessors according to following rules: - - aSymbol = #always always generate the accessors - - aSymbol = #never never generate the accessors - - aSymbol = #generated only generate the auto-generated accessors - - aSymbol = #absent only generate the absent accessors" - - | newByteAlignment byteOffset typeSpec newCompiledSpec | - byteOffset := 0. - newByteAlignment := self minStructureAlignment. - typeSpec := WriteStream on: (WordArray new: 10). - typeSpec nextPut: FFIFlagStructure. - specArray do: [:spec | - | fieldName fieldTypeName externalType typeSize fieldAlignment | - fieldName := spec first. - fieldTypeName := spec second. - externalType := (ExternalType typeNamed: fieldTypeName) - ifNil: [self errorTypeNotFound: spec second]. - typeSize := externalType byteSize. - fieldAlignment := (externalType byteAlignment - max: self minFieldAlignment) - min: self maxFieldAlignment. - byteOffset := byteOffset alignedTo: fieldAlignment. - newByteAlignment := newByteAlignment max: fieldAlignment. - spec size > 2 ifTrue: ["extra size" - spec third < typeSize - ifTrue: [^ self error: 'Explicit type size is less than expected']. - typeSize := spec third. - ]. - (fieldName notNil and: [self shouldGenerate: fieldName policy: aSymbol]) ifTrue: [ - self generateStructureFieldAccessorsFor: fieldName startingAt: byteOffset + 1 type: externalType. - ]. - typeSpec nextPutAll: (externalType embeddedSpecWithSize: typeSize). - byteOffset := byteOffset + typeSize. - ]. - newByteAlignment := newByteAlignment min: self maxStructureAlignment. - byteOffset := byteOffset alignedTo: newByteAlignment. - newCompiledSpec := typeSpec contents. - newCompiledSpec at: 1 put: (byteOffset bitOr: FFIFlagStructure). - self - setCompiledSpec: newCompiledSpec - byteAlignment: newByteAlignment.!
Item was added: + ----- Method: ExternalStructure class>>compileTypeAliasSpec:generateAccessors: (in category 'field definition - support') ----- + compileTypeAliasSpec: spec generateAccessors: aSymbol + "Define all the fields in the receiver. + Return the newly compiled spec." + | fieldName fieldTypeName externalType | + fieldName := spec first. + fieldTypeName := spec second. + externalType := (ExternalType typeNamed: fieldTypeName) + ifNil: [self errorTypeNotFound: spec second]. + (fieldName notNil and:[self shouldGenerateAccessorsFor: fieldName policy: aSymbol]) ifTrue:[ + self generateTypeAliasAccessorsFor: fieldName type: externalType]. + externalType isPointerType + ifTrue: ["Special case. Typedef for a pointer type, e.g., typedef char* LPSTR in Win32 API. Mark it as both structure and pointer. Note that #isPointerType will only answer true for the in-image pointer type, not the non-pointer alias for the pointer." + self + setCompiledSpec: (WordArray with: ExternalType pointerAliasSpec) + byteAlignment: ExternalType pointerAliasAlignment] + ifFalse: ["Usual case. Typedef for another struct type or atomic type. Just re-use compiled spec and extras from the aliased type." + self + flag: #isTypeAlias; + setCompiledSpec: externalType compiledSpec + byteAlignment: externalType byteAlignment].!
Item was removed: - ----- Method: ExternalStructure class>>compileTypeAliasSpec:withAccessors: (in category 'field definition - support') ----- - compileTypeAliasSpec: spec withAccessors: aSymbol - "Define all the fields in the receiver. - Return the newly compiled spec." - | fieldName fieldTypeName externalType | - fieldName := spec first. - fieldTypeName := spec second. - externalType := (ExternalType typeNamed: fieldTypeName) - ifNil: [self errorTypeNotFound: spec second]. - (fieldName notNil and:[self shouldGenerate: fieldName policy: aSymbol]) ifTrue:[ - self generateTypeAliasAccessorsFor: fieldName type: externalType]. - externalType isPointerType - ifTrue: ["Special case. Typedef for a pointer type, e.g., typedef char* LPSTR in Win32 API. Mark it as both structure and pointer. Note that #isPointerType will only answer true for the in-image pointer type, not the non-pointer alias for the pointer." - self - setCompiledSpec: (WordArray with: ExternalType pointerAliasSpec) - byteAlignment: ExternalType pointerAliasAlignment] - ifFalse: ["Usual case. Typedef for another struct type or atomic type. Just re-use compiled spec and extras from the aliased type." - self - flag: #isTypeAlias; - setCompiledSpec: externalType compiledSpec - byteAlignment: externalType byteAlignment].!
Item was added: + ----- Method: ExternalStructure class>>defineAllChangedFields (in category 'system startup') ----- + defineAllChangedFields + " + ExternalStructure defineAllChangedFields + " + self allStructuresInCompilationOrder do: [:structClass | + structClass defineChangedFields. + structClass organization removeEmptyCategories]. + + "Compilation of fields only needs external types temporarily. Non-weak references to external types are only in methods with FFI calls." + ExternalType cleanupUnusedTypes.!
Item was changed: ----- Method: ExternalStructure class>>defineAllFields (in category 'system startup') ----- defineAllFields " ExternalStructure defineAllFields " + self allStructuresInCompilationOrder do: [:structClass | + structClass defineFields. + structClass organization removeEmptyCategories]. - | priorAuthorInitials fieldSpec | - priorAuthorInitials := Utilities authorInitialsPerSe. - [Utilities setAuthorInitials: 'FFI'.
+ "Compilation of fields only needs external types temporarily. Non-weak references to external types are only in methods with FFI calls." + ExternalType cleanupUnusedTypes.! - self allStructuresInCompilationOrder do: [:structClass | - fieldSpec := structClass fields. - (structClass hasFieldLayoutChanged: fieldSpec) - ifTrue: [structClass defineFields: fieldSpec]. - structClass organization removeEmptyCategories]. - "Compilation of fields only needs external types temporarily. Non-weak references to external types are only in methods with FFI calls." - ExternalType cleanupUnusedTypes. - - ] ensure: [Utilities setAuthorInitials: priorAuthorInitials]!
Item was added: + ----- Method: ExternalStructure class>>defineChangedFields (in category 'field definition') ----- + defineChangedFields + "Public. Define all the fields in the receiver. Only re-generate changed field accessors if auto-generated in the first place." + + self isSkipped ifTrue: [^ nil]. + self hasFieldLayoutChanged ifTrue: [self defineFields].!
Item was added: + ----- Method: ExternalStructure class>>defineChangedFields: (in category 'field definition') ----- + defineChangedFields: fieldSpec + "Public. Define all the fields in the receiver. Only re-generate changed field accessors if auto-generated in the first place." + + self isSkipped ifTrue: [^ nil]. + (self hasFieldLayoutChanged: fieldSpec) ifTrue: [self defineFields: fieldSpec].!
Item was changed: ----- Method: ExternalStructure class>>defineFields: (in category 'field definition') ----- defineFields: fieldSpec "Private. Use #defineFields." + self compileFields: fieldSpec generateAccessors: #ifGenerated. - self compileFields: fieldSpec withAccessors: #generated. ExternalType noticeModificationOf: self.!
Item was changed: ----- Method: ExternalStructure class>>doneCompiling (in category 'class management') ----- doneCompiling + "Base class changed to something that is an external structure now. This is also the post-load hook for Monticello; see MCMethodDefinition >> #postLoad." - "Base class changed to something that is an external structure now."
self isSkipped ifTrue: [^ self]. + ExternalStructure triggerDefineAllChangedFields.! - ExternalStructure triggerDefineAllFields.!
Item was changed: + ----- Method: ExternalStructure class>>hasFieldLayoutChanged (in category 'field definition - support') ----- - ----- Method: ExternalStructure class>>hasFieldLayoutChanged (in category 'system startup') ----- hasFieldLayoutChanged "Answers whether all fields should be re-compiled (and hence accessors re-generated)." ^ self hasFieldLayoutChanged: self fields!
Item was changed: + ----- Method: ExternalStructure class>>hasFieldLayoutChanged: (in category 'field definition - support') ----- - ----- Method: ExternalStructure class>>hasFieldLayoutChanged: (in category 'system startup') ----- hasFieldLayoutChanged: fieldSpec "Answers whether all fields should be re-compiled (and hence accessors re-generated). This is useful at system startup time if a platform change was detected, which can influence alignment and size of pointers. !!!!!! Note that this method depends on all referenced types to be checked for field-layout changes first !!!!!!" | oldCompiledSpec oldByteAlignment result | (oldCompiledSpec := self compiledSpec) ifNil: [^ true]. (oldByteAlignment := self byteAlignment) ifNil: [^ true]. + self compileFields: fieldSpec generateAccessors: #never. - self compileFields: fieldSpec withAccessors: #never. self flag: #bug. "mt: Changed type aliasing for pointers not noticed unless that alias hides a pointer type." result := self isTypeAlias or: [oldCompiledSpec ~= self compiledSpec]. self setCompiledSpec: oldCompiledSpec byteAlignment: oldByteAlignment.
^ result!
Item was changed: ----- Method: ExternalStructure class>>maybeCompileAccessor:withSelector: (in category 'field definition - support') ----- maybeCompileAccessor: newSourceString withSelector: selector + "Only compile if category or source changed. Use generic author initials during compilation." - "Only compile if category or source changed." + | newCategory existingReference priorAuthorInitials | - | newCategory existingReference | newCategory := #'*autogenerated - accessing'. ((existingReference := MethodReference class: self selector: selector) isValid and: [existingReference category = newCategory] and: [existingReference sourceString = newSourceString]) ifTrue: [^ self]. + + priorAuthorInitials := Utilities authorInitialsPerSe. + [Utilities authorInitials: 'FFI'. + self compile: newSourceString classified: newCategory. + ] ensure: [Utilities authorInitials: priorAuthorInitials].! - self compile: newSourceString classified: newCategory.!
Item was changed: + ----- Method: ExternalStructure class>>setCompiledSpec:byteAlignment: (in category 'field definition - support') ----- - ----- Method: ExternalStructure class>>setCompiledSpec:byteAlignment: (in category 'external type') ----- setCompiledSpec: spec byteAlignment: alignment + "Private. Store this structure's compiled spec and extras to be used when creating external types for this structure as required. See ExternalType class >> #newTypeNamed: and ExternalType >> #newReferentClass:. Note that this should only be called from the struct compiler; see #compile*Spec:withAccessors:." - "Store this structure's compiled spec and extras to be used when creating external types for this structure as required. See ExternalType class >> #newTypeNamed: and ExternalType >> #newReferentClass:."
compiledSpec := spec. byteAlignment := alignment.!
Item was removed: - ----- Method: ExternalStructure class>>shouldGenerate:policy: (in category 'field definition - support') ----- - shouldGenerate: fieldname policy: aSymbol - "Answer true if the field accessors must be compiled. - Do so according to the following rules: - - aSymbol = #always always generate the accessors - - aSymbol = #never never generate the accessors - - aSymbol = #generated only re-generate the auto-generated accessors - - aSymbol = #absent only generate the absent accessors" - aSymbol = #never ifTrue: [^ false]. - aSymbol = #always ifTrue: [^ true]. - aSymbol = #absent ifTrue: [^ (self methodDictionary includesKey: fieldname) not]. - aSymbol = #generated "includes #absent rule" - ifTrue: [^ (self methodDictionary includesKey: fieldname) not - or: [(self methodDictionary at: fieldname) hasPragma: #generated]]. - self error: 'unknown generation policy'!
Item was added: + ----- Method: ExternalStructure class>>shouldGenerateAccessorsFor:policy: (in category 'field definition - support') ----- + shouldGenerateAccessorsFor: fieldname policy: aSymbol + "Answer true if the field accessors must be compiled. + Do so according to the following rules: + - aSymbol = #always always generate the accessors + - aSymbol = #never never generate the accessors + - aSymbol = #ifGenerated only re-generate the auto-generated accessors + - aSymbol = #ifAbsent only generate the absent accessors" + aSymbol = #never ifTrue: [^ false]. + aSymbol = #always ifTrue: [^ true]. + aSymbol = #ifAbsent ifTrue: [^ (self methodDictionary includesKey: fieldname) not]. + aSymbol = #ifGenerated "includes #ifAbsent rule" + ifTrue: [^ (self methodDictionary includesKey: fieldname) not + or: [(self methodDictionary at: fieldname) hasPragma: #generated]]. + self error: 'unknown generation policy'!
Item was added: + ----- Method: ExternalStructure class>>triggerDefineAllChangedFields (in category 'field definition - deferred') ----- + triggerDefineAllChangedFields + + self environment at: #'FFIDeferredTask_DefineAllChangedFields' put: true. + Project current addDeferredUIMessage: [self tryDefineAllChangedFields].!
Item was added: + ----- Method: ExternalStructure class>>tryDefineAllChangedFields (in category 'field definition - deferred') ----- + tryDefineAllChangedFields + + (self environment includesKey: #'FFIDeferredTask_DefineAllChangedFields') + ifTrue: [self environment removeKey: #'FFIDeferredTask_DefineAllChangedFields'] + ifFalse: [^ self]. + + self defineAllChangedFields.!
Item was added: + ----- Method: ExternalUnion class>>compileStructureSpec:generateAccessors: (in category 'field definition - support') ----- + compileStructureSpec: specArray generateAccessors: aSymbol + "Compile a type specification for the FFI machinery. + Return the newly compiled spec. + Eventually generate the field accessors according to the policy defined in aSymbol." + | byteOffset maxByteSize typeSpec newCompiledSpec newByteAlignment | + byteOffset := 1. + newByteAlignment := 1. + maxByteSize := 0. + typeSpec := WriteStream on: (WordArray new: specArray size + 1). + typeSpec nextPut: FFIFlagStructure. + specArray do: [:spec | + | fieldName fieldTypeName externalType typeSize typeAlignment | + fieldName := spec first. + fieldTypeName := spec second. + externalType := (ExternalType typeNamed: fieldTypeName) + ifNil: [self errorTypeNotFound: spec second]. + typeSize := externalType byteSize. + typeAlignment := externalType byteAlignment. + spec size > 2 ifTrue: ["extra size" + spec third < typeSize + ifTrue: [^ self error: 'Explicit type size is less than expected']. + typeSize := spec third. + ]. + (fieldName notNil and: [self shouldGenerateAccessorsFor: fieldName policy: aSymbol]) ifTrue: [ + self generateStructureFieldAccessorsFor: fieldName startingAt: byteOffset type: externalType. + ]. + typeSpec nextPutAll: (externalType embeddedSpecWithSize: typeSize). + maxByteSize := maxByteSize max: typeSize. + newByteAlignment := newByteAlignment max: typeAlignment + ]. + maxByteSize := maxByteSize alignedTo: newByteAlignment. + newCompiledSpec := typeSpec contents. + newCompiledSpec at: 1 put: (maxByteSize bitOr: FFIFlagStructure). + self + setCompiledSpec: newCompiledSpec + byteAlignment: newByteAlignment.!
Item was removed: - ----- Method: ExternalUnion class>>compileStructureSpec:withAccessors: (in category 'field definition - support') ----- - compileStructureSpec: specArray withAccessors: aSymbol - "Compile a type specification for the FFI machinery. - Return the newly compiled spec. - Eventually generate the field accessors according to the policy defined in aSymbol." - | byteOffset maxByteSize typeSpec newCompiledSpec newByteAlignment | - byteOffset := 1. - newByteAlignment := 1. - maxByteSize := 0. - typeSpec := WriteStream on: (WordArray new: specArray size + 1). - typeSpec nextPut: FFIFlagStructure. - specArray do: [:spec | - | fieldName fieldTypeName externalType typeSize typeAlignment | - fieldName := spec first. - fieldTypeName := spec second. - externalType := (ExternalType typeNamed: fieldTypeName) - ifNil: [self errorTypeNotFound: spec second]. - typeSize := externalType byteSize. - typeAlignment := externalType byteAlignment. - spec size > 2 ifTrue: ["extra size" - spec third < typeSize - ifTrue: [^ self error: 'Explicit type size is less than expected']. - typeSize := spec third. - ]. - (fieldName notNil and: [self shouldGenerate: fieldName policy: aSymbol]) ifTrue: [ - self generateStructureFieldAccessorsFor: fieldName startingAt: byteOffset type: externalType. - ]. - typeSpec nextPutAll: (externalType embeddedSpecWithSize: typeSize). - maxByteSize := maxByteSize max: typeSize. - newByteAlignment := newByteAlignment max: typeAlignment - ]. - maxByteSize := maxByteSize alignedTo: newByteAlignment. - newCompiledSpec := typeSpec contents. - newCompiledSpec at: 1 put: (maxByteSize bitOr: FFIFlagStructure). - self - setCompiledSpec: newCompiledSpec - byteAlignment: newByteAlignment.!
Item was added: + ----- Method: ExternalUnion class>>compileTypeAliasSpec:generateAccessors: (in category 'field definition - support') ----- + compileTypeAliasSpec: spec generateAccessors: aSymbol + + self error: 'Use ExternalStructure or ExternalTypeAlias to define a type alias, not ExternalUnion'.!
Item was removed: - ----- Method: ExternalUnion class>>compileTypeAliasSpec:withAccessors: (in category 'field definition - support') ----- - compileTypeAliasSpec: spec withAccessors: aSymbol - - self error: 'Use ExternalStructure or ExternalTypeAlias to define a type alias, not ExternalUnion'.!
packages@lists.squeakfoundation.org