Marcel Taeumel uploaded a new version of Regex-Tests-Core to project The Trunk:
http://source.squeak.org/trunk/Regex-Tests-Core-tobe.13.mcz
==================== Summary ====================
Name: Regex-Tests-Core-tobe.13
Author: tobe
Time: 12 August 2021, 11:28:42.158361 am
UUID: 2ae5d8ba-6382-4b3b-9a07-7e10d0889a2c
Ancestors: Regex-Tests-Core-ct.12
Complements Regex-Core-tobe.60
=============== Diff against Regex-Tests-Core-ct.12 ===============
Item was added:
+ ----- Method: RxParserTest>>testCharacterSetWithEscapedAndRange (in category 'tests') -----
+ testCharacterSetWithEscapedAndRange
+
+ " two examples of where a - should not parse as a range "
+ self assert: ('[\+-]' asRegex matches: '+').
+ self assert: ('[\+\-]' asRegex matches: '-').
+
+ " construct a range from an escaped + (43) to digit 4 (52) "
+ self assert: ('[\+-4]' asRegex matches: '3')!
Marcel Taeumel uploaded a new version of Regex-Tests-Core to project The Trunk:
http://source.squeak.org/trunk/Regex-Tests-Core-mt.16.mcz
==================== Summary ====================
Name: Regex-Tests-Core-mt.16
Author: mt
Time: 13 August 2021, 12:31:24.998724 pm
UUID: cde10f88-8cb5-a442-8d8c-6e53444970d2
Ancestors: Regex-Tests-Core-mt.15, Regex-Tests-Core-tobe.13
Merge
=============== Diff against Regex-Tests-Core-mt.15 ===============
Item was added:
+ ----- Method: RxParserTest>>testCharacterSetWithEscapedAndRange (in category 'tests') -----
+ testCharacterSetWithEscapedAndRange
+
+ " two examples of where a - should not parse as a range "
+ self assert: ('[\+-]' asRegex matches: '+').
+ self assert: ('[\+\-]' asRegex matches: '-').
+
+ " construct a range from an escaped + (43) to digit 4 (52) "
+ self assert: ('[\+-4]' asRegex matches: '3')!
Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel-mt.202.mcz
==================== Summary ====================
Name: FFI-Kernel-mt.202
Author: mt
Time: 13 August 2021, 10:08:38.629551 am
UUID: b7a408ea-4287-7248-bc5a-a18fff4dab53
Ancestors: FFI-Kernel-mt.201
Fixes a regression / ensures compatibility with Alien and 3DTransform around floatAt:(put:).
Note that Alien (being a subclass of ByteArray) breaks polymorphism in the sense that it changes all atomic read/write primitives from byteOffset-based to index-based. Yet, Alien is way older than what the recent SqueakFFI efforts are trying to achieve here: a more robust programming model.
The fundamental issue considering the programming model is as follows:
anArray at: 4 put: 1.234. "Easy. Dynamic. Clear semantics."
anArray floatAt: 4 put: 1.234. "Depends on whether you got Alien or ByteArray ... or Float32Array for that matter."
Note that this issue does not occur with the integer primitives ... even though it might make sense to add the #*ByteOffset:* variants as well in the future.
Note that 3DTransform actually adds the extension #floatAt:(put:) to FloatArray.
=============== Diff against FFI-Kernel-mt.201 ===============
Item was changed:
----- Method: ByteArray>>doubleAt: (in category '*FFI-Kernel-accessing - float') -----
doubleAt: byteOffset
"Primitive. Return a float value from the receiver.
- FAILS IF the receiver has not enough bytes for an IEEE 754 (64 bits) floating point number.
- NOTE that this primitive will access memory in the outer space if invoked from ExternalAddress.
- SEE Float class >> #fromIEEE64Bit: and Float >> #asIEEE64BitWord"
<primitive: #primitiveFFIDoubleAt module: #SqueakFFIPrims>
+ "<ffiAtomicRead: #double> -- See #doubleAtByteOffset:."
- <ffiAtomicRead: #double>
"Examples:
ExternalType double handle: #[ 0 0 0 255 0 0 0 0 ] at: 1.
ExternalType double handle: #[ 0 0 0 255 ] at: 1. --- Error.
"
^ self primitiveFailed!
Item was changed:
----- Method: ByteArray>>doubleAt:put: (in category '*FFI-Kernel-accessing - float') -----
doubleAt: byteOffset put: value
"Primitive. Store the given value as IEEE 754 (64 bits) floating point number.
- FAILS IF the receiver has not enough bytes for that representation.
- NOTE that this primitive will access memory in the outer space if invoked from ExternalAddress.
- SEE Float class >> #fromIEEE64Bit: and Float >> #asIEEE64BitWord"
<primitive: #primitiveFFIDoubleAtPut module: #SqueakFFIPrims>
+ "<ffiAtomicWrite: #double> -- See doubleAtByteOffset:put:."
- <ffiAtomicWrite: #double>
"Examples:
ExternalType double allocate value: 123.4567890; explore
ExternalType double allocate value: 0.0001; explore
"
^ self primitiveFailed!
Item was added:
+ ----- Method: ByteArray>>doubleAtByteOffset: (in category '*FFI-Kernel-accessing - float') -----
+ doubleAtByteOffset: byteOffset
+ "Duplicates #doubleAt: for compatibility reasons with Alien and 3DTransform. See comment in #doubleAt:."
+ <primitive: #primitiveFFIDoubleAt module: #SqueakFFIPrims>
+ <ffiAtomicRead: #double>
+ ^ self primitiveFailed!
Item was added:
+ ----- Method: ByteArray>>doubleAtByteOffset:put: (in category '*FFI-Kernel-accessing - float') -----
+ doubleAtByteOffset: byteOffset put: value
+ "Duplicates #doubleAt:put: for compatibility reasons with Alien and 3DTransform. See comment in #doubleAt:put:."
+ <primitive: #primitiveFFIDoubleAtPut module: #SqueakFFIPrims>
+ <ffiAtomicWrite: #double>
+ ^ self primitiveFailed!
Item was changed:
----- Method: ByteArray>>floatAt: (in category '*FFI-Kernel-accessing - float') -----
floatAt: byteOffset
"Primitive. Return a float value from the receiver.
- FAILS IF the receiver has not enough bytes for an IEEE 754 (32 bits) floating point number.
- NOTE that this primitive will access memory in the outer space if invoked from ExternalAddress.
- SEE Float class >> #fromIEEE32Bit: and Float >> #asIEEE32BitWord"
<primitive: #primitiveFFIFloatAt module: #SqueakFFIPrims>
+ "<ffiAtomicRead: #float> -- See #floatAtByteOffset:."
- <ffiAtomicRead: #float>
"Examples:
ExternalType float handle: #[ 0 0 0 255 ] at: 1.
ExternalType float handle: #[ 0 0 255 ] at: 1. --- Error.
"
^ self primitiveFailed!
Item was changed:
----- Method: ByteArray>>floatAt:put: (in category '*FFI-Kernel-accessing - float') -----
floatAt: byteOffset put: value
"Primitive. Store the given value as IEEE 754 (32 bits) floating point number.
- FAILS IF the receiver has not enough bytes for that representation.
- NOTE that this primitive will access memory in the outer space if invoked from ExternalAddress.
- SEE Float class >> #fromIEEE32Bit: and Float >> #asIEEE32BitWord"
<primitive: #primitiveFFIFloatAtPut module: #SqueakFFIPrims>
+ "<ffiAtomicWrite: #float> -- See floatAtByteOffset:put:."
- <ffiAtomicWrite: #float>
"Examples:
ExternalType float allocate value: 123.4567890; explore
ExternalType float allocate value: 0.0001; explore
"
^ self primitiveFailed!
Item was added:
+ ----- Method: ByteArray>>floatAtByteOffset: (in category '*FFI-Kernel-accessing - float') -----
+ floatAtByteOffset: byteOffset
+ "Duplicates #floatAt: for compatibility reasons with Alien and 3DTransform. See comment in #floatAt:."
+ <primitive: #primitiveFFIFloatAt module: #SqueakFFIPrims>
+ <ffiAtomicRead: #float>
+ ^ self primitiveFailed!
Item was added:
+ ----- Method: ByteArray>>floatAtByteOffset:put: (in category '*FFI-Kernel-accessing - float') -----
+ floatAtByteOffset: byteOffset put: value
+ "Duplicates #floatAt:put: for compatibility reasons with Alien and 3DTransform. See comment in #floatAt:put:."
+ <primitive: #primitiveFFIFloatAtPut module: #SqueakFFIPrims>
+ <ffiAtomicWrite: #float>
+ ^ self primitiveFailed!
Item was changed:
----- Method: ByteArrayReadWriter>>doubleAt: (in category 'read/write atomics') -----
doubleAt: oByteOffset
+ self shouldNotImplement. "See doubleAtByteOffset:"!
- self checkAt: oByteOffset.
- ^ byteArray doubleAt: oByteOffset + byteOffset!
Item was changed:
----- Method: ByteArrayReadWriter>>doubleAt:put: (in category 'read/write atomics') -----
doubleAt: oByteOffset put: value
+ self shouldNotImplement. "See doubleAtByteOffset:put:"!
- self checkAt: oByteOffset.
- ^ byteArray doubleAt: oByteOffset + byteOffset put: value!
Item was added:
+ ----- Method: ByteArrayReadWriter>>doubleAtByteOffset: (in category 'read/write atomics') -----
+ doubleAtByteOffset: oByteOffset
+
+ self checkAt: oByteOffset.
+ ^ byteArray doubleAtByteOffset: oByteOffset + byteOffset!
Item was added:
+ ----- Method: ByteArrayReadWriter>>doubleAtByteOffset:put: (in category 'read/write atomics') -----
+ doubleAtByteOffset: oByteOffset put: value
+
+ self checkAt: oByteOffset.
+ ^ byteArray doubleAtByteOffset: oByteOffset + byteOffset put: value!
Item was changed:
----- Method: ByteArrayReadWriter>>floatAt: (in category 'read/write atomics') -----
floatAt: oByteOffset
+ self shouldNotImplement. "See floatAtByteOffset:"!
- self checkAt: oByteOffset.
- ^ byteArray floatAt: oByteOffset + byteOffset!
Item was changed:
----- Method: ByteArrayReadWriter>>floatAt:put: (in category 'read/write atomics') -----
floatAt: oByteOffset put: value
+ self shouldNotImplement. "See floatAtByteOffset:put:"!
- self checkAt: oByteOffset.
- ^ byteArray floatAt: oByteOffset + byteOffset put: value!
Item was added:
+ ----- Method: ByteArrayReadWriter>>floatAtByteOffset: (in category 'read/write atomics') -----
+ floatAtByteOffset: oByteOffset
+
+ self checkAt: oByteOffset.
+ ^ byteArray floatAtByteOffset: oByteOffset + byteOffset!
Item was added:
+ ----- Method: ByteArrayReadWriter>>floatAtByteOffset:put: (in category 'read/write atomics') -----
+ floatAtByteOffset: oByteOffset put: value
+
+ self checkAt: oByteOffset.
+ ^ byteArray floatAtByteOffset: oByteOffset + byteOffset put: value!
Item was removed:
- ----- Method: Float32Array>>floatAt: (in category '*FFI-Kernel-accessing') -----
- floatAt: byteOffset
- "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:."
-
- ^ self atByteOffset: byteOffset!
Item was removed:
- ----- Method: Float32Array>>floatAt:put: (in category '*FFI-Kernel-accessing') -----
- floatAt: byteOffset put: value
- "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:put:."
-
- ^ self atByteOffset: byteOffset put: value!
Item was added:
+ ----- Method: Float32Array>>floatAtByteOffset: (in category '*FFI-Kernel-accessing') -----
+ floatAtByteOffset: byteOffset
+ "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:."
+
+ ^ self atByteOffset: byteOffset!
Item was added:
+ ----- Method: Float32Array>>floatAtByteOffset:put: (in category '*FFI-Kernel-accessing') -----
+ floatAtByteOffset: byteOffset put: value
+ "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:put:."
+
+ ^ self atByteOffset: byteOffset put: value!
Item was removed:
- ----- Method: Float64Array>>doubleAt: (in category '*FFI-Kernel-accessing') -----
- doubleAt: byteOffset
- "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:."
-
- ^ self atByteOffset: byteOffset!
Item was removed:
- ----- Method: Float64Array>>doubleAt:put: (in category '*FFI-Kernel-accessing') -----
- doubleAt: byteOffset put: value
- "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:put:."
-
- ^ self atByteOffset: byteOffset put: value!
Item was added:
+ ----- Method: Float64Array>>doubleAtByteOffset: (in category '*FFI-Kernel-accessing') -----
+ doubleAtByteOffset: byteOffset
+ "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:."
+
+ ^ self atByteOffset: byteOffset!
Item was added:
+ ----- Method: Float64Array>>doubleAtByteOffset:put: (in category '*FFI-Kernel-accessing') -----
+ doubleAtByteOffset: byteOffset put: value
+ "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:put:."
+
+ ^ self atByteOffset: byteOffset put: value!
Eliot Miranda uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel.terf-eem.202.mcz
==================== Summary ====================
Name: FFI-Kernel.terf-eem.202
Author: eem
Time: 12 August 2021, 1:45:51.806758 pm
UUID: ac9a5229-0be7-4ef7-abde-cef2682ee2f0
Ancestors: FFI-Kernel-mt.201
Fork because of indefensible definition of Float32Array>>floatAt:
=============== Diff against FFI-Kernel-mt.201 ===============
Item was removed:
- ----- Method: Float32Array>>floatAt: (in category '*FFI-Kernel-accessing') -----
- floatAt: byteOffset
- "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:."
-
- ^ self atByteOffset: byteOffset!
Item was removed:
- ----- Method: Float32Array>>floatAt:put: (in category '*FFI-Kernel-accessing') -----
- floatAt: byteOffset put: value
- "Backstop for compatibility with handle-based access. Raw-bits arrays are their own handle. See #getHandle and ExternalType >> #handle:at:put:."
-
- ^ self atByteOffset: byteOffset put: value!
Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel-mt.201.mcz
==================== Summary ====================
Name: FFI-Kernel-mt.201
Author: mt
Time: 12 August 2021, 4:59:01.488801 pm
UUID: 31d99f8f-471c-4b4d-ae81-67d2d93588c1
Ancestors: FFI-Kernel-mt.200
Speed up struct-field accessor generation/compilation further. Make logging opt-in via preference for debugging or learning purposes only.
=============== Diff against FFI-Kernel-mt.200 ===============
Item was changed:
ExternalObject subclass: #ExternalStructure
instanceVariableNames: ''
+ classVariableNames: 'LogAccessorSourceCode'
- classVariableNames: ''
poolDictionaries: 'ExternalTypePool FFIConstants'
category: 'FFI-Kernel'!
ExternalStructure class
instanceVariableNames: 'compiledSpec byteAlignment'!
!ExternalStructure commentStamp: 'eem 6/26/2019 15:26' prior: 0!
An ExternalStructure is for representing external data that is
- either a structure composed of different fields (a struct of C language)
- or an alias for another type (like a typedef of C language)
It reserves enough bytes of data for representing all the fields.
The data is stored into the handle instance variable which can be of two different types:
- ExternalAddress
If the handle is an external address then the object described does not reside in the Smalltalk object memory.
- ByteArray
If the handle is a byte array then the object described resides in Smalltalk memory.
Instance Variables (class side)
byteAlignment: <Integer>
compiledSpec: <WordArray>
byteAlignment
- the required alignment for the structure
compiledSpec
- the bit-field definiton of the structure in the ExternalType encoding understood by the VM's FFI call marshalling machinery.
A specific structure is defined by subclassing ExternalStructure and specifying its #fields via a class side method.
For example if we define a subclass:
ExternalStructure subclass: #StructExample
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'garbage'.
Then declare the fields like this:
StructExample class compile: 'fields ^#( (name ''char*'') (color ''ulong'') )' classified: 'garbage'.
It means that this type is composed of two different fields:
- a string (accessed thru the field #name)
- and an unsigned 32bit integer (accessed thru the field #color).
It represents the following C type:
struct StructExample {char *name; uint32_t color; };
The accessors for those fields can be generated automatically like this:
StructExample defineFields.
As can be verified in a Browser:
StructExample browse.
We see that name and color fields are stored sequentially in different zones of data.
The total size of the structure can be verified with:
StructExample byteSize = (Smalltalk wordSize + 4).
An ExternalStructure can also be used for defining an alias.
The fields definition must contain only 2 elements: an eventual accessor (or nil) and the type.
For example, We can define a machine dependent 'unsigned long' like this:
ExternalStructure subclass: #UnsignedLong
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'garbage'.
Then set the fields like this:
UnsignedLong class compile: 'fields ^(Smalltalk wordSize=4 or: [Smalltalk platformName=''Win64''])
ifTrue: [#(nil ''ulong'')] ifFalse: [#(nil ''ulonglong'')]' classified: 'garbage'.
And verify the size on current platform:
UnsignedLong byteSize.
Then, the class names 'UnsignedLong' and 'StructExamples' acts as a type specification.
They can be used for composing other types, and for defining prototype of external functions:
LibraryExample>>initMyStruct: aStructExample name: name color: anInteger
<cdecl: void 'init_my_struct'( StructExample * char * UnsignedLong )>
self externalCallFailed
!
ExternalStructure class
instanceVariableNames: 'compiledSpec byteAlignment'!
Item was added:
+ ----- Method: ExternalStructure class>>logAccessorSourceCode (in category 'preferences') -----
+ logAccessorSourceCode
+ <preference: 'Log source code for generated accessors'
+ categoryList: #('FFI Kernel')
+ description: 'When true, keep the sources generated for struct-field accessors in the method trailer. While this might increase the image file notably, no sources file will be accessed for performance reasons. When false, only the decompiled sources will be available for those accessors.'
+ type: #Boolean>
+ ^ LogAccessorSourceCode ifNil: [false]!
Item was added:
+ ----- Method: ExternalStructure class>>logAccessorSourceCode: (in category 'preferences') -----
+ logAccessorSourceCode: aBoolean
+
+ LogAccessorSourceCode = aBoolean ifTrue: [^ self].
+ LogAccessorSourceCode := aBoolean.
+ ExternalStructure defineAllFields.!
Item was changed:
----- Method: ExternalStructure class>>maybeCompileAccessor:withSelector: (in category 'field definition - support') -----
maybeCompileAccessor: newSourceString withSelector: selector
+ "When logging is enabled, only compile if category or source changed."
- "Only compile if category or source changed. Use generic author initials during compilation."
+ | log newCategory oldMethod newMethod |
+ log := self logAccessorSourceCode.
- | newCategory existingReference method |
newCategory := #'*autogenerated - accessing'.
+
+ (log and: [self includesSelector: selector]) ifTrue: [
+ oldMethod := self compiledMethodAt: selector.
+ ((self organization categoryOfElement: selector) = newCategory
+ and: [oldMethod trailer sourceCode = newSourceString])
+ ifTrue: [^ self]].
- ((existingReference := MethodReference class: self selector: selector) isValid
- and: [existingReference category = newCategory]
- and: [existingReference sourceString = newSourceString])
- ifTrue: [^ self].
"Compile silently. No changeStamp. No access to sources file. Keep source code in method trailer."
self compileSilently: newSourceString classified: newCategory.
+ log ifTrue: [
+ newMethod := self compiledMethodAt: selector.
+ newMethod becomeForward: (newMethod copyWithSourceCode: newSourceString)].!
- method := self compiledMethodAt: selector.
- method becomeForward: (method copyWithSourceCode: newSourceString).!
Item was changed:
----- Method: GenericIntegerReadWriteSend class>>useSpecificIntegerPrimitives: (in category 'preferences') -----
useSpecificIntegerPrimitives: aBoolean
UseSpecificIntegerPrimitives = aBoolean ifTrue: [^ self].
aBoolean ~= self canUseSpecificIntegerPrimitives
ifTrue: [self notify: 'FFI plugin does not support specific integer primitives. Proceed to update atomic sends anyway. Fallback code will redirect to generic integer primitive. Performance might be affected.'].
UseSpecificIntegerPrimitives := aBoolean.
Cursor wait showWhile: [
ExternalType initializeAtomicSends.
+ ExternalStructure defineAllFields].!
- MessageTally spyOn: [ExternalStructure defineAllFields]].!