Eliot Miranda uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-eem.881.mcz
==================== Summary ====================
Name: Collections-eem.881
Author: eem
Time: 11 March 2020, 6:53:50.254027 pm
UUID: 012691b6-410a-4e9a-9c64-97b5abfdba49
Ancestors: Collections-eem.880
Include the Array bulk-become machinery in the ModificationForbidden framework.
=============== Diff against Collections-eem.880 ===============
Item was changed:
----- Method: Array>>elementsExchangeIdentityWith: (in category 'converting') -----
elementsExchangeIdentityWith: otherArray
"This primitive performs a bulk mutation, causing all pointers to the elements of the
receiver to be replaced by pointers to the corresponding elements of otherArray.
At the same time, all pointers to the elements of otherArray are replaced by
pointers to the corresponding elements of this array. The identityHashes remain
with the pointers rather than with the objects so that objects in hashed structures
should still be properly indexed after the mutation."
<primitive: 128 error: ec>
+ ec == #'no modification' ifTrue:
+ [^self modificationForbiddenFor: otherArray becomeSelector: #elementsExchangeIdentityWith:].
ec == #'bad receiver' ifTrue:
[^self error: 'receiver must be of class Array'].
ec == #'bad argument' ifTrue:
[^self error: (otherArray class == Array
ifTrue: ['arg must be of class Array']
ifFalse: ['receiver and argument must have the same size'])].
ec == #'inappropriate operation' ifTrue:
[^self error: 'can''t become immediates such as SmallIntegers or Characters'].
- ec == #'no modification' ifTrue:
- [^self error: 'can''t become immutable objects'].
ec == #'object is pinned' ifTrue:
[^self error: 'can''t become pinned objects'].
ec == #'insufficient object memory' ifTrue:
[| maxRequired |
"In Spur, two-way become may involve making each pair of objects into a forwarder into a copy of the other.
So if become fails with #'insufficient object memory', garbage collect, and if necessary, grow memory."
maxRequired := (self detectSum: [:obj | obj class byteSizeOfInstanceOfSize: obj basicSize])
+ (otherArray detectSum: [:obj | obj class byteSizeOfInstanceOfSize: obj basicSize]).
(Smalltalk garbageCollectMost < maxRequired
and: [Smalltalk garbageCollect < maxRequired]) ifTrue:
[Smalltalk growMemoryByAtLeast: maxRequired].
^self elementsExchangeIdentityWith: otherArray].
self primitiveFailed!
Item was changed:
----- Method: Array>>elementsForwardIdentityTo: (in category 'converting') -----
elementsForwardIdentityTo: otherArray
"This primitive performs a bulk mutation, causing all pointers to the elements of the
receiver to be replaced by pointers to the corresponding elements of otherArray.
The identityHashes remain with the pointers rather than with the objects so that
the objects in this array should still be properly indexed in any existing hashed
structures after the mutation."
<primitive: 72 error: ec>
+ ec == #'no modification' ifTrue:
+ [^self modificationForbiddenFor: otherArray becomeSelector: #elementsForwardIdentityTo:].
ec == #'bad receiver' ifTrue:
[^self error: 'receiver must be of class Array'].
ec == #'bad argument' ifTrue:
[^self error: (otherArray class == Array
ifTrue: ['arg must be of class Array']
ifFalse: ['receiver and argument must have the same size'])].
ec == #'inappropriate operation' ifTrue:
[^self error: 'can''t become immediates such as SmallIntegers or Characters'].
- ec == #'no modification' ifTrue:
- [^self error: 'can''t become immutable objects'].
ec == #'object is pinned' ifTrue:
[^self error: 'can''t become pinned objects'].
ec == #'insufficient object memory' ifTrue:
[self error: 'The virtual machine is out-of-date. Please upgrade.'].
self primitiveFailed!
Item was changed:
----- Method: Array>>elementsForwardIdentityTo:copyHash: (in category 'converting') -----
elementsForwardIdentityTo: otherArray copyHash: copyHash
"This primitive performs a bulk mutation, causing all pointers to the elements of the
receiver to be replaced by pointers to the corresponding elements of otherArray.
If copyHash is true, the identityHashes remain with the pointers rather than with the
objects so that the objects in the receiver should still be properly indexed in any
existing hashed structures after the mutation. If copyHash is false, then the hashes
of the objects in otherArray remain unchanged. If you know what you're doing this
may indeed be what you want."
<primitive: 249 error: ec>
+ ec == #'no modification' ifTrue:
+ [^self modificationForbiddenFor: otherArray argument: copyHash becomeSelector: #elementsForwardIdentityTo:copyHash:].
ec == #'bad receiver' ifTrue:
[^self error: 'receiver must be of class Array'].
ec == #'bad argument' ifTrue:
[^self error: (otherArray class == Array
ifTrue: ['arg must be of class Array']
ifFalse: ['receiver and argument must have the same size'])].
ec == #'inappropriate operation' ifTrue:
[^self error: 'can''t become immediates such as SmallIntegers or Characters'].
- ec == #'no modification' ifTrue:
- [^self error: 'can''t become immutable objects'].
ec == #'object is pinned' ifTrue:
[^self error: 'can''t become pinned objects'].
self primitiveFailed!
Item was added:
+ ----- Method: Array>>modificationForbiddenFor:argument:becomeSelector: (in category 'read-only objects') -----
+ modificationForbiddenFor: otherArray argument: argument becomeSelector: retrySelector
+ "Raise a ModificationForbidden error for an attempt to modify a read-only object through a become operation."
+ ^(ModificationForbidden new
+ mirror: self
+ object: otherArray
+ index: nil
+ newValue: argument
+ resumptionValue: self
+ retrySelector: retrySelector) signal!
Item was added:
+ ----- Method: Array>>modificationForbiddenFor:becomeSelector: (in category 'read-only objects') -----
+ modificationForbiddenFor: otherArray becomeSelector: retrySelector
+ "Raise a ModificationForbidden error for an attempt to modify a read-only object through a become operation."
+ ^(BinaryModificationForbidden new
+ mirror: self
+ object: otherArray
+ index: nil
+ newValue: nil
+ resumptionValue: self
+ retrySelector: retrySelector) signal!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1318.mcz
==================== Summary ====================
Name: Kernel-eem.1318
Author: eem
Time: 11 March 2020, 6:49:23.875063 pm
UUID: 25265ede-0f88-439d-8800-8a39e3f1898a
Ancestors: Kernel-eem.1317
Read-only object support.
Have ModificationForbidden allow retrying modification without resuming (retryModificationNoResume) or resuming (retryModificatio). Ideally this would just be retryModification and resume but Pharo got there first and compatibility is a virtue.
Add BinaryModificationForbidden to support Array and the elementsExchangeIdentityWith: become machinery, and simplify the Behavior adoptInstance: mchinery. Decouople resumeValue from newValue to allow Array and the elementsExchangeIdentityWith: become machinery to answer the correct result.
Extend the execution simulation machionery to correctly simulate attempting to assign the inst vars of read-only objects.
Add Object class>>releaseNotes as a scratch pad for people to add things that should appear in the release notes.
=============== Diff against Kernel-eem.1317 ===============
Item was removed:
- ----- Method: Behavior>>adoptInstance:ignore: (in category 'read-only objects') -----
- adoptInstance: anInstance ignore: ignore
- "This method exists only to adapt to the pattern used in ModificationForbidden>>retryModification,
- which expects all mutators to take an argument."
- ^self adoptInstance: anInstance!
Item was changed:
----- Method: Behavior>>modificationForbiddenAdopting: (in category 'read-only objects') -----
modificationForbiddenAdopting: anObject
+ ^(BinaryModificationForbidden new
- ^(ModificationForbidden new
mirror: self
object: anObject
index: nil
newValue: nil
+ retrySelector: #adoptInstance:) signal!
- retrySelector: #adoptInstance:ignore:) signal!
Item was added:
+ ModificationForbidden subclass: #BinaryModificationForbidden
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Kernel-Exceptions'!
+
+ !BinaryModificationForbidden commentStamp: 'eem 3/11/2020 15:56' prior: 0!
+ A BinaryModificationForbidden is a variation of ModificationForbidden for messages that need neither fieldIndex nor newObject, such as elementsExchangeIdentityWith: and adoptInstance:. It overrides the retryModification method.
+
+ Instance Variables
+ !
Item was added:
+ ----- Method: BinaryModificationForbidden>>retryModification (in category 'retrying') -----
+ retryModification
+ mirror perform: retrySelector with: object.
+ self resume: resumptionValue!
Item was added:
+ ----- Method: BinaryModificationForbidden>>retryModificationNoResume (in category 'retrying') -----
+ retryModificationNoResume
+ mirror perform: retrySelector with: object!
Item was added:
+ ----- Method: Context>>attemptToAssign:to:withIndex: (in category 'read-only objects') -----
+ attemptToAssign: value to: anObject withIndex: index
+ "Sent by the execution simulation machinery when attempting to assign an instance
+ variable of an read-only object. This mimics the VM's send of attemptToAssign:withIndex:
+ when trying to do the same. Upon return, executing will resume *after* the inst var assignment.
+ This method differs from Object>>attemptToAssign:withIndex: in not doing a Context>>jump,
+ which does not simulate properly."
+
+ self modificationForbiddenFor: anObject instVarAt: index put: value!
Item was changed:
----- Method: Context>>modificationForbiddenFor:at:put: (in category 'read-only objects') -----
+ modificationForbiddenFor: target at: index put: anObject
- modificationForbiddenFor: target at: index put: aCharacter
^(ModificationForbidden new
mirror: self
object: target
index: index
+ newValue: anObject
- newValue: aCharacter
retrySelector: #object:basicAt:put:) signal!
Item was changed:
----- Method: Context>>modificationForbiddenFor:instVarAt:put: (in category 'read-only objects') -----
+ modificationForbiddenFor: target instVarAt: index put: anObject
- modificationForbiddenFor: target instVarAt: index put: aCharacter
^(ModificationForbidden new
mirror: self
object: target
index: index
+ newValue: anObject
- newValue: aCharacter
retrySelector: #object:instVarAt:put:) signal!
Item was changed:
----- Method: Context>>object:instVarAt:put: (in category 'mirror primitives') -----
object: anObject instVarAt: anIndex put: aValue
"Primitive. Store a value into a fixed variable in the argument anObject.
The numbering of the variables corresponds to the named instance
variables. Fail if the index is not an Integer or is not the index of a
+ fixed variable, or if anObject is read-only. Answer the value stored as
+ the result. Using this message violates the principle that each object
+ has sovereign control over the storing of values into its instance variables.
+ Essential for the debugger. See Object documentation whatIsAPrimitive."
- fixed variable. Answer the value stored as the result. Using this
- message violates the principle that each object has sovereign control
- over the storing of values into its instance variables. Essential for the
- debugger. See Object documentation whatIsAPrimitive."
<primitive: 174 error: ec>
+ ec == #'no modification' ifTrue:
+ [^self modificationForbiddenFor: anObject instVarAt: anIndex put: aValue].
self primitiveFailed!
Item was changed:
----- Method: Context>>popIntoLiteralVariable: (in category 'instruction decoding') -----
popIntoLiteralVariable: value
"Simulate the action of bytecode that removes the top of the stack and
+ stores it into a literal variable of my method. If the receiver is read-only
+ this will provoke a send of #attemptToAssign:withIndex:"
- stores it into a literal variable of my method."
+ | top result |
+ top := self pop.
+ result := self simulatedObject: value instVarAt: ValueIndex put: top.
+ ^(self object: result eqeq: top)
+ ifTrue: [self]
+ ifFalse: [result]!
- self object: value instVarAt: ValueIndex put: self pop!
Item was changed:
----- Method: Context>>popIntoReceiverVariable: (in category 'instruction decoding') -----
popIntoReceiverVariable: offset
"Simulate the action of bytecode that removes the top of the stack and
+ stores it into an instance variable of my receiver. If the receiver is read-only
+ this will provoke a send of #attemptToAssign:withIndex:"
- stores it into an instance variable of my receiver."
+ | top result |
+ top := self pop.
+ result := self simulatedObject: self receiver instVarAt: offset + 1 put: top.
+ ^(self object: result eqeq: top)
+ ifTrue: [self]
+ ifFalse: [result]!
- self object: self receiver instVarAt: offset + 1 put: self pop!
Item was added:
+ ----- Method: Context>>simulatedObject:instVarAt:put: (in category 'read-only objects') -----
+ simulatedObject: anObject instVarAt: anIndex put: aValue
+ "Primitive. Store a value into a fixed variable in the argument anObject.
+ The numbering of the variables corresponds to the named instance
+ variables. Fail if the index is not an Integer or is not the index of a
+ fixed variable, or if anObject is read-only. This version correctly simulates
+ assigning to a read-only object. Answer the value stored as the result.
+ Using this message violates the principle that each object has sovereign
+ control over the storing of values into its instance variables. Essential for
+ the debugger. See Object documentation whatIsAPrimitive."
+
+ <primitive: 174 error: ec>
+ ec == #'no modification' ifTrue:
+ [^self send: #attemptToAssign:to:withIndex: to: self with: {aValue. anObject. anIndex} lookupIn: self class].
+ self primitiveFailed!
Item was changed:
----- Method: Context>>storeIntoLiteralVariable: (in category 'instruction decoding') -----
storeIntoLiteralVariable: value
"Simulate the action of bytecode that stores the top of the stack into a
+ literal variable of my method. If the receiver is read-only
+ this will provoke a send of #attemptToAssign:withIndex:"
- literal variable of my method."
+ | top result |
+ top := self top.
+ result := self simulatedObject: value instVarAt: ValueIndex put: top.
+ ^(self object: result eqeq: top)
+ ifTrue: [self]
+ ifFalse: [result]!
- self object: value instVarAt: ValueIndex put: self top!
Item was changed:
----- Method: Context>>storeIntoReceiverVariable: (in category 'instruction decoding') -----
storeIntoReceiverVariable: offset
"Simulate the action of bytecode that stores the top of the stack into an
+ instance variable of my receiver. If the receiver is read-only
+ this will provoke a send of #attemptToAssign:withIndex:"
- instance variable of my receiver."
+ | top result |
+ top := self top.
+ result := self simulatedObject: self receiver instVarAt: offset + 1 put: top.
+ ^(self object: result eqeq: top)
+ ifTrue: [self]
+ ifFalse: [result]!
- self object: self receiver instVarAt: offset + 1 put: self top!
Item was changed:
Exception subclass: #ModificationForbidden
+ instanceVariableNames: 'mirror object fieldIndex newValue retrySelector resumptionValue'
- instanceVariableNames: 'mirror object fieldIndex newValue retrySelector'
classVariableNames: ''
poolDictionaries: ''
category: 'Kernel-Exceptions'!
+ !ModificationForbidden commentStamp: 'eem 3/11/2020 15:46' prior: 0!
- !ModificationForbidden commentStamp: 'eem 3/11/2020 11:53' prior: 0!
This exception is raised when attempting to mutate a read-only object.
My instances have 5 fields to be able to reproduce the modification via the retryModification method.
+ mirror <Context|Behavior|Array> the object that will perform the modification on object if modificationRetried
+ object <Object> read-only object that attempted to mutate
+ index <SmallInteger | nil> index of the field in the object mutated, relevant for the corresponding selector
+ value <Object> value that was attempted to be stored into the read-only object
+ selector <Symbol> selector that can be used to reproduce the mutation (#object:basicAt:put:, #object:instVarAt:put:, etc)!
- mirror <Context|Behavior> the Context or Behavior that will perform the modification if modificationRetried
- object <Object> read-only object that attempted to mutate
- index <SmallInteger | nil> index of the field in the object mutated, relevant for the corresponding selector
- value <Object> value that was attempted to be stored into the read-only object
- selector <Symbol> selector that can be used to reproduce the mutation (typically, #object:basicAt:put:, #object:instVarAt:put:, etc.)!
Item was changed:
----- Method: ModificationForbidden>>fieldIndex (in category 'accessing') -----
fieldIndex
+ ^fieldIndex!
- ^ fieldIndex!
Item was added:
+ ----- Method: ModificationForbidden>>mirror:object:index:newValue:resumptionValue:retrySelector: (in category 'accessing') -----
+ mirror: aContext object: anObject index: index newValue: value resumptionValue: valueToResumeWith retrySelector: selector
+
+ mirror := aContext.
+ object := anObject.
+ fieldIndex := index.
+ newValue := value.
+ retrySelector := selector.
+ resumptionValue := valueToResumeWith!
Item was changed:
----- Method: ModificationForbidden>>mirror:object:index:newValue:retrySelector: (in category 'accessing') -----
mirror: aContext object: anObject index: index newValue: value retrySelector: selector
mirror := aContext.
object := anObject.
fieldIndex := index.
newValue := value.
+ retrySelector := selector.
+ resumptionValue := value!
- retrySelector := selector!
Item was changed:
----- Method: ModificationForbidden>>newValue (in category 'accessing') -----
newValue
+ ^newValue!
- ^ newValue!
Item was changed:
----- Method: ModificationForbidden>>object (in category 'accessing') -----
object
+ ^object!
- ^ object!
Item was added:
+ ----- Method: ModificationForbidden>>resume (in category 'controlling') -----
+ resume
+ "Roll back thisContext to self and resume. Execute unwind blocks when rolling back. ASSUMES self is a sender of thisContext"
+
+ self resume: resumptionValue!
Item was added:
+ ----- Method: ModificationForbidden>>resumptionValue (in category 'accessing') -----
+ resumptionValue
+ ^resumptionValue!
Item was added:
+ ----- Method: ModificationForbidden>>resumptionValue: (in category 'accessing') -----
+ resumptionValue: anObject
+ resumptionValue := anObject!
Item was changed:
----- Method: ModificationForbidden>>retryModification (in category 'retrying') -----
retryModification
fieldIndex
ifNotNil: [mirror perform: retrySelector with: object with: fieldIndex with: newValue]
ifNil: [mirror perform: retrySelector with: object with: newValue].
+ self resume: resumptionValue!
- self resume: newValue!
Item was added:
+ ----- Method: ModificationForbidden>>retryModificationNoResume (in category 'retrying') -----
+ retryModificationNoResume
+ fieldIndex
+ ifNotNil: [mirror perform: retrySelector with: object with: fieldIndex with: newValue]
+ ifNil: [mirror perform: retrySelector with: object with: newValue]!
Item was changed:
----- Method: ModificationForbidden>>retrySelector (in category 'accessing') -----
retrySelector
+ ^retrySelector!
- ^ retrySelector!
Item was added:
+ ----- Method: Object class>>releaseNotes (in category 'documentation') -----
+ releaseNotes
+ "This is a scratch pad of release3 notes for the 6.0 release this version is building towards.
+ Feel free to add to this comment mention of things that should appear in the release notes.
+
+ Read-only object support and read-only literals.
+ the current VM supports a per-object read-only bit and will fail to modify objects marked with this flag bit.
+ This affects assignments to inst vars, to indexed fields in at:put: primitives, attempts to become read-only
+ objects into non-read-only objects, and attempts to change the class of read-only objects. All such attempts
+ raise a ModificationForbidden error. The error may retry the modification once the object has been made
+ writable. The compiler has been modified to make all literals read-only."
+
+ self error: 'comment only'!
Item was changed:
----- Method: Object>>attemptToAssign:withIndex: (in category 'write barrier') -----
attemptToAssign: value withIndex: index
+ "Called by the VM when attempting to assign an instance variable of an read-only object.
+ Upon return, executing will resume *after* the inst var assignment. If the inst var
+ mutation has to be performed, do it manually here in the call back with instVarAt:put:.
+ This method has to return *no* value by jumping to the context's sender"
- "Called by the VM when assigning an instance variable of an immutable object.
- Upon return, executing will resume *after* the inst var assignment. If the inst var mutation has to be
- performed, do it manually here in the call back with instVarAt:put:.
- This method has to return *no* value by jumping to the context's sender"
thisContext modificationForbiddenFor: self instVarAt: index put: value.
thisContext sender jump
"CAN'T REACH"!
Eliot Miranda uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-eem.880.mcz
==================== Summary ====================
Name: Collections-eem.880
Author: eem
Time: 11 March 2020, 1:13:58.722295 pm
UUID: 927e58eb-1ab6-470a-8eb2-f36065351836
Ancestors: Collections-nice.879
Add the read-only object support to accompany Kernel-eem.1317
=============== Diff against Collections-nice.879 ===============
Item was changed:
----- Method: ByteString>>at:put: (in category 'accessing') -----
at: index put: aCharacter
+ "Primitive. Store the Character in the field of the receiver indicated by the index.
+ Fail if the index is not an Integer or is out of bounds, or if the argument is not a
+ Character, or the Character's code is outside the 0-255 range, or if the receiver
+ is read-only. Essential. See Object documentation whatIsAPrimitive."
- "Primitive. Store the Character in the field of the receiver indicated by
- the index. Fail if the index is not an Integer or is out of bounds, or if
- the argument is not a Character. Essential. See Object documentation
- whatIsAPrimitive."
+ <primitive: 64 error: ec>
+ aCharacter isCharacter ifFalse:
+ [^self errorImproperStore].
- <primitive: 64>
- aCharacter isCharacter
- ifFalse:[^self errorImproperStore].
- aCharacter isOctetCharacter ifFalse:[
- "Convert to WideString"
- self becomeForward: (WideString from: self).
- ^self at: index put: aCharacter.
- ].
index isInteger
+ ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self at: index putCharacter: aCharacter].
+ aCharacter isOctetCharacter ifFalse: "Convert to WideString"
+ [self becomeForward: (WideString from: self).
+ ^self at: index put: aCharacter].
+ self errorSubscriptBounds: index]
- ifTrue: [self errorSubscriptBounds: index]
ifFalse: [self errorNonIntegerIndex]!
Item was changed:
----- Method: ByteSymbol>>pvtAt:put: (in category 'private') -----
pvtAt: index put: aCharacter
+ "Primitive. Store the Character in the field of the receiver indicated by the index.
+ Fail if the index is not an Integer or is out of bounds, or if the argument is not a
+ Character, or the Character's code is outside the 0-255 range, or if the receiver
+ is read-only. Essential. See Object documentation whatIsAPrimitive."
- "Primitive. Store the Character in the field of the receiver indicated by
- the index. Fail if the index is not an Integer or is out of bounds, or if
- the argument is not a Character. Essential. See Object documentation
- whatIsAPrimitive."
+ <primitive: 64 error: ec>
+ aCharacter isCharacter ifFalse:
+ [^self errorImproperStore].
- <primitive: 64>
- aCharacter isCharacter
- ifFalse:[^self errorImproperStore].
index isInteger
+ ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self at: index putCharacter: aCharacter].
+ self errorSubscriptBounds: index]
- ifTrue: [self errorSubscriptBounds: index]
ifFalse: [self errorNonIntegerIndex]!
Item was changed:
----- Method: WideString>>at:put: (in category 'accessing') -----
at: index put: aCharacter
+ "Primitive. Store the Character in the field of the receiver indicated by
+ the index. Fail if the index is not an Integer or is out of bounds, or if
+ the argument is not a Character, or if the receiver is read-only.
+ Essential. See Object documentation whatIsAPrimitive."
- "Store the Character into the field of the receiver indicated by the index.
- Primitive. Fail if the index is not an Integer or is out of bounds, or if the
- argument is not a Character. Essential. See Object documentation whatIsAPrimitive."
+ <primitive: 64 error: ec>
+ aCharacter isCharacter ifFalse:
+ [^self errorImproperStore].
+ index isInteger
- <primitive: 64>
- ^aCharacter isCharacter
ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self at: index putCharacter: aCharacter].
+ self errorSubscriptBounds: index]
+ ifFalse: [self errorNonIntegerIndex]!
- [index isInteger
- ifTrue: [self errorSubscriptBounds: index]
- ifFalse: [self errorNonIntegerIndex]]
- ifFalse:
- [self errorImproperStore]!
Item was changed:
----- Method: WideSymbol>>pvtAt:put: (in category 'private') -----
pvtAt: index put: aCharacter
"Primitive. Store the Character in the field of the receiver indicated by
+ the index. Fail if the index is not an Integer or is out of bounds, or if
+ the argument is not a Character, or if the receiver is read-only.
+ Essential. See Object documentation whatIsAPrimitive."
- the index. Fail if the index is not an Integer or is out of bounds, or if
- the argument is not a Character. Essential. See Object documentation
- whatIsAPrimitive."
+ <primitive: 61 error: ec>
+ aCharacter isCharacter ifFalse:
+ [^self errorImproperStore].
- <primitive: 61>
index isInteger
+ ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self at: index putCharacter: aCharacter].
+ self errorSubscriptBounds: index]
- ifTrue: [self errorSubscriptBounds: index]
ifFalse: [self errorNonIntegerIndex]!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1317.mcz
==================== Summary ====================
Name: Kernel-eem.1317
Author: eem
Time: 11 March 2020, 1:12:02.344414 pm
UUID: 3755843a-380e-4cbc-a498-b1f1a85f2906
Ancestors: Kernel-eem.1316
Add the core of read-only support, which will provide both for read-only literals and for efficient write-through cacheing to object databases such as gemstone.
This implementation differs slightly from Clément Béra's original implementatin for Pharo in that here ModificationForbidden always uses a mirror (either a Context or a Class) to attempt to modify the read-only
object in retryModification.
=============== Diff against Kernel-eem.1316 ===============
Item was changed:
----- Method: Behavior>>adoptInstance: (in category 'instance creation') -----
+ adoptInstance: anObject
+ "Change the class of anObject to me.
+ Primitive (found in Cog and new VMs) follows the same rules as primitiveChangeClassTo:, but returns the class rather than the modified instance"
- adoptInstance: anInstance
- "Change the class of anInstance to the receiver.
- Primitive. Change the class of the argument anInstance into the receiver, provided
- that the format of the receiver matches the format of the argument's class.
- Fail if the argument is an immediate, or when the pointerness of the receiver is different
- from the pointerness of the argument, or when the receiver is a fixed pointer class and
- anInstance's size differs from the size that an instance of the receiver should have,
- or when anInstance's size is not an integer multiple of the receiver's unit size."
<primitive: 160 error: ec>
+ ec == #'no modification' ifTrue:
+ [^self modificationForbiddenAdopting: anObject].
+ self primitiveFailed!
- ^self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>adoptInstance:ignore: (in category 'read-only objects') -----
+ adoptInstance: anInstance ignore: ignore
+ "This method exists only to adapt to the pattern used in ModificationForbidden>>retryModification,
+ which expects all mutators to take an argument."
+ ^self adoptInstance: anInstance!
Item was added:
+ ----- Method: Behavior>>modificationForbiddenAdopting: (in category 'read-only objects') -----
+ modificationForbiddenAdopting: anObject
+ ^(ModificationForbidden new
+ mirror: self
+ object: anObject
+ index: nil
+ newValue: nil
+ retrySelector: #adoptInstance:ignore:) signal!
Item was added:
+ ----- Method: Context>>modificationForbiddenFor:at:put: (in category 'read-only objects') -----
+ modificationForbiddenFor: target at: index put: aCharacter
+ ^(ModificationForbidden new
+ mirror: self
+ object: target
+ index: index
+ newValue: aCharacter
+ retrySelector: #object:basicAt:put:) signal!
Item was added:
+ ----- Method: Context>>modificationForbiddenFor:at:putCharacter: (in category 'read-only objects') -----
+ modificationForbiddenFor: target at: index putCharacter: aCharacter
+ "eem 3/11/2020 13:09 this may be a mistake. Instead perhaps String clients should
+ send asInteger and use modificationForbiddenFor:at:put:. Opinions appreciated."
+ ^(ModificationForbidden new
+ mirror: self
+ object: target
+ index: index
+ newValue: (aCharacter isCharacter ifTrue: [aCharacter asInteger] ifFalse: [aCharacter])
+ retrySelector: #object:basicAt:put:) signal!
Item was added:
+ ----- Method: Context>>modificationForbiddenFor:instVarAt:put: (in category 'read-only objects') -----
+ modificationForbiddenFor: target instVarAt: index put: aCharacter
+ ^(ModificationForbidden new
+ mirror: self
+ object: target
+ index: index
+ newValue: aCharacter
+ retrySelector: #object:instVarAt:put:) signal!
Item was changed:
----- Method: Context>>object:basicAt:put: (in category 'mirror primitives') -----
object: anObject basicAt: index put: value
+ "Store the last argument value in the indexable element of the argument anObject
+ indicated by index without sending anObject a message. Fail if the argument index
+ is not an Integer or is out of bounds, or if anObject is not indexable, or if anObject is
+ read-only, or if value is an inappropriate value for anObject's indexable slots.
+ This mimics the action of the VM when it indexes an object. Used to simulate
+ the execution machinery by, for example, the debugger.
- "Store the last argument
- value in the indexable element of the argument anObject indicated by index without sending
- anObject a message. Fail if the argument index is not an Integer or is out of bounds, or if
- anObject is not indexable, or if value is an inappropriate value for anObject's indexable slots.
- This mimics the action of the VM when it indexes an object.
- Used to simulate the execution machinery by, for example, the debugger.
Primitive. See Object documentation whatIsAPrimitive."
+ <primitive: 61 error: ec>
+ index isInteger ifTrue:
+ [(index >= 1 and: [index <= (self objectSize: anObject)])
+ ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^self modificationForbiddenFor: anObject at: index put: value].
+ self errorImproperStore]
+ ifFalse: [self errorSubscriptBounds: index]].
+ index isNumber ifTrue:
+ [^self object: anObject basicAt: index asInteger put: value].
+ self errorNonIntegerIndex!
- <primitive: 61>
- index isInteger
- ifTrue: [(index >= 1 and: [index <= (self objectSize: anObject)])
- ifTrue: [self errorImproperStore]
- ifFalse: [self errorSubscriptBounds: index]].
- index isNumber
- ifTrue: [^self object: anObject basicAt: index asInteger put: value]
- ifFalse: [self errorNonIntegerIndex]!
Item was changed:
----- Method: FutureMaker>>basicAt:put: (in category 'accessing') -----
basicAt: index put: value
"Primitive. Assumes receiver is indexable. Store the second argument
value in the indexable element of the receiver indicated by index. Fail
if the index is not an Integer or is out of bounds. Or fail if the value is
not of the right type for this kind of collection. Answer the value that
was stored. Essential. Do not override in a subclass. See Object
documentation whatIsAPrimitive."
+ <primitive: 61 error: ec>
+ index isInteger ifTrue:
+ [(index >= 1 and: [index <= self basicSize])
+ ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self at: index put: value].
+ self errorImproperStore]
+ ifFalse: [self errorSubscriptBounds: index]].
+ index isNumber ifTrue:
+ [^self basicAt: index asInteger put: value].
+ self errorNonIntegerIndex!
- <primitive: 61>
- index isInteger
- ifTrue: [(index >= 1 and: [index <= self size])
- ifTrue: [self errorImproperStore]
- ifFalse: [self errorSubscriptBounds: index]].
- index isNumber
- ifTrue: [^self basicAt: index asInteger put: value]
- ifFalse: [self errorNonIntegerIndex]!
Item was changed:
----- Method: FutureMaker>>instVarAt:put: (in category 'accessing') -----
+ instVarAt: anInteger put: anObject
- instVarAt: anInteger put: anObject
"Primitive. Store a value into a fixed variable in the receiver. The
numbering of the variables corresponds to the named instance variables.
Fail if the index is not an Integer or is not the index of a fixed variable.
Answer the value stored as the result. Using this message violates the
principle that each object has sovereign control over the storing of
values into its instance variables. Essential. See Object documentation
whatIsAPrimitive."
<primitive: 174 error: ec>
+ ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self instVarAt: anInteger value: anObject].
self primitiveFailed!
Item was added:
+ Exception subclass: #ModificationForbidden
+ instanceVariableNames: 'mirror object fieldIndex newValue retrySelector'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Kernel-Exceptions'!
+
+ !ModificationForbidden commentStamp: 'eem 3/11/2020 11:53' prior: 0!
+ This exception is raised when attempting to mutate a read-only object.
+
+ My instances have 5 fields to be able to reproduce the modification via the retryModification method.
+
+ mirror <Context|Behavior> the Context or Behavior that will perform the modification if modificationRetried
+ object <Object> read-only object that attempted to mutate
+ index <SmallInteger | nil> index of the field in the object mutated, relevant for the corresponding selector
+ value <Object> value that was attempted to be stored into the read-only object
+ selector <Symbol> selector that can be used to reproduce the mutation (typically, #object:basicAt:put:, #object:instVarAt:put:, etc.)!
Item was added:
+ ----- Method: ModificationForbidden>>defaultAction (in category 'priv handling') -----
+ defaultAction
+ UnhandledError signalForException: self!
Item was added:
+ ----- Method: ModificationForbidden>>fieldIndex (in category 'accessing') -----
+ fieldIndex
+ ^ fieldIndex!
Item was added:
+ ----- Method: ModificationForbidden>>indexedMessageText (in category 'printing') -----
+ indexedMessageText
+ ^String streamContents:
+ [ :s |
+ s << ' '.
+ self printObject: object on: s.
+ s << ' is read-only, hence its field '.
+ fieldIndex printOn: s.
+ s << ' cannot be modified with '.
+ self printObject: newValue on: s]!
Item was added:
+ ----- Method: ModificationForbidden>>messageText (in category 'printing') -----
+ messageText
+ "Overwritten to initialize the message text to a standard text if it has not yet been set"
+
+ ^ messageText ifNil: [ messageText := self standardMessageText ]!
Item was added:
+ ----- Method: ModificationForbidden>>mirror (in category 'accessing') -----
+ mirror
+ ^mirror!
Item was added:
+ ----- Method: ModificationForbidden>>mirror:object:index:newValue:retrySelector: (in category 'accessing') -----
+ mirror: aContext object: anObject index: index newValue: value retrySelector: selector
+
+ mirror := aContext.
+ object := anObject.
+ fieldIndex := index.
+ newValue := value.
+ retrySelector := selector!
Item was added:
+ ----- Method: ModificationForbidden>>newValue (in category 'accessing') -----
+ newValue
+ ^ newValue!
Item was added:
+ ----- Method: ModificationForbidden>>nonIndexedMessageText (in category 'printing') -----
+ nonIndexedMessageText
+ ^String streamContents:
+ [ :s |
+ s << ' '.
+ self printObject: object on: s.
+ s << ' is read-only, hence its selector '.
+ s << retrySelector.
+ s << ' cannot be executed with '.
+ self printObject: newValue on: s]!
Item was added:
+ ----- Method: ModificationForbidden>>object (in category 'accessing') -----
+ object
+ ^ object!
Item was added:
+ ----- Method: ModificationForbidden>>printObject:on: (in category 'printing') -----
+ printObject: obj on: s
+ [obj printOn: s]
+ on: Exception
+ do: [ :ex | s << '<cannot print object>' ]!
Item was added:
+ ----- Method: ModificationForbidden>>retryModification (in category 'retrying') -----
+ retryModification
+ fieldIndex
+ ifNotNil: [mirror perform: retrySelector with: object with: fieldIndex with: newValue]
+ ifNil: [mirror perform: retrySelector with: object with: newValue].
+ self resume: newValue!
Item was added:
+ ----- Method: ModificationForbidden>>retrySelector (in category 'accessing') -----
+ retrySelector
+ ^ retrySelector!
Item was added:
+ ----- Method: ModificationForbidden>>standardMessageText (in category 'printing') -----
+ standardMessageText
+ ^fieldIndex
+ ifNil: [self nonIndexedMessageText]
+ ifNotNil: [self indexedMessageText]!
Item was changed:
----- Method: Object>>at:put: (in category 'accessing') -----
+ at: index put: anObject
+ "Primitive. Assumes receiver is indexable. Store the argument anObject in
+ the indexable element of the receiver indicated by index. Fail if the index
+ is not an Integer or is out of bounds, or if the receiver is read-only, or if
+ anObject is not of the right type for this kind of collection. Answer the
+ value (anObject) that was stored. Essential. See Object documentation
+ whatIsAPrimitive."
- at: index put: value
- "Primitive. Assumes receiver is indexable. Store the argument value in
- the indexable element of the receiver indicated by index. Fail if the
- index is not an Integer or is out of bounds. Or fail if the value is not of
- the right type for this kind of collection. Answer the value that was
- stored. Essential. See Object documentation whatIsAPrimitive."
+ <primitive: 61 error: ec>
- <primitive: 61>
index isInteger ifTrue:
[self class isVariable
+ ifTrue:
+ [(index >= 1 and: [index <= self size])
+ ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self at: index put: anObject].
+ self errorImproperStore]
- ifTrue: [(index >= 1 and: [index <= self size])
- ifTrue: [self errorImproperStore]
ifFalse: [self errorSubscriptBounds: index]]
ifFalse: [self errorNotIndexable]].
+ index isNumber ifTrue:
+ [^self at: index asInteger put: anObject].
+ self errorNonIntegerIndex!
- index isNumber
- ifTrue: [^self at: index asInteger put: value]
- ifFalse: [self errorNonIntegerIndex]!
Item was added:
+ ----- Method: Object>>attemptToAssign:withIndex: (in category 'write barrier') -----
+ attemptToAssign: value withIndex: index
+ "Called by the VM when assigning an instance variable of an immutable object.
+ Upon return, executing will resume *after* the inst var assignment. If the inst var mutation has to be
+ performed, do it manually here in the call back with instVarAt:put:.
+ This method has to return *no* value by jumping to the context's sender"
+
+ thisContext modificationForbiddenFor: self instVarAt: index put: value.
+
+ thisContext sender jump
+ "CAN'T REACH"!
Item was changed:
----- Method: Object>>basicAt:put: (in category 'accessing') -----
+ basicAt: index put: anObject
+ "Primitive. Assumes receiver is indexable. Store the argument anObject in
+ the indexable element of the receiver indicated by index. Fail if the index
+ is not an Integer or is out of bounds, or if the receiver is read-only, or if
+ anObject is not of the right type for this kind of collection. Answer the
+ value (anObject) that was stored. Essential. Do not override in a subclass.
+ See Object documentation whatIsAPrimitive."
- basicAt: index put: value
- "Primitive. Assumes receiver is indexable. Store the second argument
- value in the indexable element of the receiver indicated by index. Fail
- if the index is not an Integer or is out of bounds. Or fail if the value is
- not of the right type for this kind of collection. Answer the value that
- was stored. Essential. Do not override in a subclass. See Object
- documentation whatIsAPrimitive."
+ <primitive: 61 error: ec>
+ index isInteger ifTrue:
+ [self class isVariable
+ ifTrue:
+ [(index >= 1 and: [index <= self basicSize])
+ ifTrue:
+ [ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self at: index put: anObject].
+ self errorImproperStore]
+ ifFalse: [self errorSubscriptBounds: index]]
+ ifFalse: [self errorNotIndexable]].
+ index isNumber ifTrue:
+ [^self basicAt: index asInteger put: anObject].
+ self errorNonIntegerIndex!
- <primitive: 61>
- index isInteger
- ifTrue: [(index >= 1 and: [index <= self size])
- ifTrue: [self errorImproperStore]
- ifFalse: [self errorSubscriptBounds: index]].
- index isNumber
- ifTrue: [^self basicAt: index asInteger put: value]
- ifFalse: [self errorNonIntegerIndex]!
Item was added:
+ ----- Method: Object>>beReadOnlyObject (in category 'write barrier') -----
+ beReadOnlyObject
+ "If the VM supports read-only objects it will not write to read-only objects.
+ An attempt to write to an instance variable of a read-only object will
+ cause the VM to send attemptToAssign:withIndex: to the read-only object.
+ An attempt to modify a read-only object in a primitive will cause the
+ primitive to fail with a #'no modification' error code.
+ Set the read-only flag of the receiver to true and answer the previous vaue of the flag."
+ ^self setIsReadOnlyObject: true!
Item was added:
+ ----- Method: Object>>beWritableObject (in category 'write barrier') -----
+ beWritableObject
+ "If the VM supports read-only objects it will not write to read-only objects.
+ An attempt to write to an instance variable of a read-only object will
+ cause the VM to send attemptToAssign:withIndex: to the read-only object.
+ An attempt to modify a read-only object in a primitive will cause the
+ primitive to fail with a #'no modification' error code.
+ Set the read-only flag of the receiver to false and answer the previous vaue of the flag."
+ ^self setIsReadOnlyObject: false!
Item was changed:
----- Method: Object>>instVarAt:put: (in category 'system primitives') -----
instVarAt: index put: anObject
"Primitive. Store a value into a fixed variable in an object. The numbering of the
variables corresponds to the named instance variables, followed by the indexed
instance variables. Fail if the index is not an Integer or is not the index of a fixed
+ or indexed variable, or if the receiver is read-only.
+ Essential. See Object documentation whatIsAPrimitive."
- or indexed variable. Essential. See Object documentation whatIsAPrimitive."
<primitive: 174 error: ec>
+ ec == #'no modification' ifTrue:
+ [^thisContext modificationForbiddenFor: self instVarAt: index put: anObject].
self primitiveFailed!
Item was added:
+ ----- Method: Object>>isReadOnlyObject (in category 'write barrier') -----
+ isReadOnlyObject
+ "Answer if the receiver is read-only.
+ If the VM supports read-only objects it will not write to read-only objects.
+ An attempt to write to an instance variable of a read-only object will
+ cause the VM to send attemptToAssign:withIndex: to the read-only object.
+ An attempt to modify a read-only object in a primitive will cause the
+ primitive to fail with a #'no modification' error code."
+ <primitive: 163 error: ec>
+ ^self class isImmediateClass!
Item was changed:
----- Method: Object>>primitiveChangeClassTo: (in category 'system primitives') -----
primitiveChangeClassTo: anObject
+ "Primitive. Change the class of the receiver into the class of the argument
+ given that the format of the receiver matches the format of the argument's
+ class. Fail if receiver or argument are immediates (SmallIntegers, Characters
+ or SmallFloat64s), or when the format of the receiver is different from the
+ format of the argument's class, or when the arguments class is fixed and
+ the receiver's size differs from the size that an instance of the argument's
+ class should have.
- "Primitive. Change the class of the receiver into the class of the argument given that the format of the receiver matches the format of the argument's class. Fail if receiver or argument are SmallIntegers, or the receiver is an instance of a compact class and the argument isn't, or when the argument's class is compact and the receiver isn't, or when the format of the receiver is different from the format of the argument's class, or when the arguments class is fixed and the receiver's size differs from the size that an instance of the argument's class should have.
- Note: The primitive will fail in most cases that you think might work. This is mostly because of a) the difference between compact and non-compact classes, and b) because of differences in the format. As an example, '(Array new: 3) primitiveChangeClassTo: Morph basicNew' would fail for three of the reasons mentioned above. Array is compact, Morph is not (failure #1). Array is variable and Morph is fixed (different format - failure #2). Morph is a fixed-field-only object and the array is too short (failure #3).
- The facility is really provided for certain, very specific applications (mostly related to classes changing shape) and not for casual use."
+ Note: The primitive will fail in cases that you think might work. This is mostly
+ because of because of differences in the format. As an example,
+ '(Array new: 3) primitiveChangeClassTo: Morph basicNew'
+ would fail because Morph is a fixed-field-only object with about 6 instance
+ variables, and the array is too short (failure #3).
+
+ The facility is really provided for certain, very specific applications (mostly related to classes changing shape) and not for casual use."
+
+ <primitive: 115 error: ec>
+ ec == #'no modification' ifTrue:
+ [^anObject class modificationForbiddenAdopting: self].
- <primitive: 115>
self primitiveFailed!
Item was added:
+ ----- Method: Object>>setIsReadOnlyObject: (in category 'write barrier') -----
+ setIsReadOnlyObject: aBoolean
+ "If the VM supports read-only objects it will not write to read-only objects.
+ An attempt to write to an instance variable of a read-only object will
+ cause the VM to send attemptToAssign:withIndex: to the read-only object.
+ An attempt to modify a read-only object in a primitive will cause the
+ primitive to fail with a #'no modification' error code.
+ This primitive sets the read-only flag of the receiver to the given
+ value and answers the previous vaue of the flag.
+ Note: Some objects can't be read-only, currently contexts and objects related
+ to process scheduling (Processor, Process instances, Semaphore instances, ...)"
+ <primitive: 164 error: ec>
+ ^self primitiveFailed!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1316.mcz
==================== Summary ====================
Name: Kernel-eem.1316
Author: eem
Time: 11 March 2020, 1:02:37.986482 pm
UUID: daa453eb-09f1-446b-bc64-6f6c0298daf2
Ancestors: Kernel-nice.1315
Improve Object class-side documentation for primtiives.
=============== Diff against Kernel-nice.1315 ===============
Item was changed:
----- Method: Object class>>howToModifyPrimitives (in category 'documentation') -----
howToModifyPrimitives
"You are allowed to write methods which specify primitives, but please use
caution. If you make a subclass of a class which contains a primitive method,
the subclass inherits the primitive. The message which is implemented
primitively may be overridden in the subclass (E.g., see at:put: in String's
subclass Symbol). The primitive behavior can be invoked using super (see
Symbol string:).
A class which attempts to mimic the behavior of another class without being
its subclass may or may not be able to use the primitives of the original class.
In general, if the instance variables read or written by a primitive have the
same meanings and are in the same fields in both classes, the primitive will
work.
For certain frequently used 'special selectors', the compiler emits a
send-special-selector bytecode instead of a send-message bytecode. Special
selectors were created because they offer two advantages. First, code which
sends special selectors compiles into fewer bytes than normal. Second, for
some pairs of receiver classes and special selectors, the interpreter jumps
directly to a primitive routine without looking up the method in the class,
and the just-in-time (JIT) compiler (if in use) may emit code to directly execute
+ the primitive. At least in the interpreter this is much faster than a normal
- the primitive. At least in the interpeeter this is much faster than a normal
message lookup. In both the interpreter and the JIT send-special-selector,
+ conditional branch pairs are short-circuited for the comparison selectors when
+ applied to SmallIntegers or Floats.
- conditional branch pairs are short-circuited for the comparison selectors.
+ A selector which is a special selector solely in order to save space has
- A selector which is a special selector solely in order to save space has a
normal behavior. Methods whose selectors are special in order to
+ gain speed contain the comment, 'No Lookup'. When the virtual machine
- gain speed contain the comment, 'No Lookup'. When the interpreter
encounters a send-special-selector bytecode, it checks the class of the
receiver and the selector. If the class-selector pair is a no-lookup pair,
then the interpreter swiftly jumps to the routine which implements the
corresponding primitive. (A special selector whose receiver is not of the
right class to make a no-lookup pair, is looked up normally). The pairs are
listed below. No-lookup methods contain a primitive number specification,
<primitive: xx>, which is redundant. Since the method is not normally looked
up, deleting the primitive number specification cannot prevent this
primitive from running. If a no-lookup primitive fails, the method is looked
up normally, and the expressions in it are executed.
No Lookup pairs of (class, selector)
SmallInteger and Float with any of + - * /
SmallInteger with any of \\ bitOr: bitShift: bitAnd: // @
SmallInteger and Float with any of = ~= > < >= <=
Any class with == ~~ class
Point with either of x y (interpreter only)
BlockClosure with either of value value: (interpreter only)
"
self error: 'comment only'!
Item was changed:
----- Method: Object class>>whatIsAPrimitive (in category 'documentation') -----
whatIsAPrimitive
"Some messages in the system are responded to primitively. A primitive
+ response is performed directly by the virtual machine rather than by
+ evaluating expressions in a method. The methods for these messages
+ indicate the presence of a primitive response by including one of
+ <primitive: N>
+ <primitive: N error: errorCode>
+ <primitive: 'primitiveName' module: 'module name'>
+ <primitive: 'primitiveName' module: 'module name' error: errorCode>
+ before the first expression in the method.
- response is performed directly by the interpreter rather than by evaluating
- expressions in a method. The methods for these messages indicate the
- presence of a primitive response by including <primitive: xx> before the
- first expression in the method.
+ Primitives exist for several reasons. Certain basic or 'primitive' operations
+ cannot be performed in any other way. Smalltalk without primitives can
+ move values from one variable to another, but cannot add two SmallIntegers
+ together. Many methods for arithmetic and comparison between numbers
+ are primitives. Some primitives allow Smalltalk to communicate with I/O
+ devices such as the disk, the display, and the keyboard. Some primitives
+ exist only to make the system run faster; each does the same thing as a
+ certain Smalltalk method, and its implementation as a primitive is optional.
+
+ When the Smalltalk virtual machine begins to execute a method which
+ specifies a primitive response, it tries to perform the primitive action and to
+ return a result. If the routine in the virtual machine for this primitive is
+ successful, it will return a value and the expressions in the method will not
+ be evaluated. If the primitive routine is not successful, the primitive 'fails',
+ and the Smalltalk expressions in the method are executed instead. These
+ expressions are evaluated as though the primitive routine had not been called.
+
+ The Smalltalk code that is evaluated when a primitive fails usually anticipates
+ why that primitive might fail. If the primitive is optional, the expressions in the
+ method do exactly what the primitive would have done (See Number @). If the
+ primitive only works on certain classes of arguments, the Smalltalk code tries
+ to coerce the argument or appeals to a superclass to find a more general way
+ of doing the operation (see SmallInteger +). If the primitive is never supposed
+ to fail, the expressions signal an error (see e.g. SmallInteger asFloat).
+
- Primitives exist for several reasons. Certain basic or 'primitive'
- operations cannot be performed in any other way. Smalltalk without
- primitives can move values from one variable to another, but cannot add two
- SmallIntegers together. Many methods for arithmetic and comparison
- between numbers are primitives. Some primitives allow Smalltalk to
- communicate with I/O devices such as the disk, the display, and the keyboard.
- Some primitives exist only to make the system run faster; each does the same
- thing as a certain Smalltalk method, and its implementation as a primitive is
- optional.
-
- When the Smalltalk interpreter begins to execute a method which specifies a
- primitive response, it tries to perform the primitive action and to return a
- result. If the routine in the interpreter for this primitive is successful,
- it will return a value and the expressions in the method will not be evaluated.
- If the primitive routine is not successful, the primitive 'fails', and the
- Smalltalk expressions in the method are executed instead. These
- expressions are evaluated as though the primitive routine had not been
- called.
-
- The Smalltalk code that is evaluated when a primitive fails usually
- anticipates why that primitive might fail. If the primitive is optional, the
- expressions in the method do exactly what the primitive would have done (See
- Number @). If the primitive only works on certain classes of arguments, the
- Smalltalk code tries to coerce the argument or appeals to a superclass to find
- a more general way of doing the operation (see SmallInteger +). If the
- primitive is never supposed to fail, the expressions signal an error (see
- SmallInteger asFloat).
-
Each method that specifies a primitive has a comment in it. If the primitive is
optional, the comment will say 'Optional'. An optional primitive that is not
+ implemented always fails, and the Smalltalk expressions do the work instead.
- implemented always fails, and the Smalltalk expressions do the work
- instead.
+ If a primitive is not optional, the comment will say, 'Essential'. If the primitive is
+ so required, the comment will say 'Do not override in a subclass'. Some methods
+ will have the comment, 'No Lookup'. See Object howToModifyPrimitives for an
+ explanation of special selectors which are not looked up.
- If a primitive is not optional, the comment will say, 'Essential'. Some
- methods will have the comment, 'No Lookup'. See Object
- howToModifyPrimitives for an explanation of special selectors which are
- not looked up.
+ The comments in the SmallInteger primitives say 'Fails if result is not a SmallInteger',
+ even though the implementor has the option to construct a LargePositiveInteger.
+ For further information on primitives, see the 'Primitive Methods' part of the
+ chapter on the formal specification of the virtual machine in
+ Smalltalk-80: The Language and its Implementation."
- For the primitives for +, -, *, and bitShift: in SmallInteger, and truncated
- in Float, the primitive constructs and returns a 16-bit
- LargePositiveInteger when the result warrants it. Returning 16-bit
- LargePositiveIntegers from these primitives instead of failing is
- optional in the same sense that the LargePositiveInteger arithmetic
- primitives are optional. The comments in the SmallInteger primitives say,
- 'Fails if result is not a SmallInteger', even though the implementor has the
- option to construct a LargePositiveInteger. For further information on
- primitives, see the 'Primitive Methods' part of the chapter on the formal
- specification of the interpreter in the Smalltalk book."
self error: 'comment only'!
Eliot Miranda uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System-eem.1146.mcz
==================== Summary ====================
Name: System-eem.1146
Author: eem
Time: 10 March 2020, 3:57:36.849789 pm
UUID: b7fb488c-bb55-4116-b634-6299a784171d
Ancestors: System-eem.1145
Accurate info for vm parameter 65 (bytecode set, read-only support, heartbeat implementation)
=============== Diff against System-eem.1145 ===============
Item was changed:
----- Method: SmalltalkImage>>vmParameterAt: (in category 'vm parameters') -----
vmParameterAt: parameterIndex
"parameterIndex is a positive integer corresponding to one of the VM's internal parameter/metric registers.
Answer with the current value of that register. Fail if parameterIndex has no corresponding register.
VM parameters are numbered as follows:
1 byte size of old-space (read-only)
2 byte size of young-space (read-only)
3 byte size of object memory (read-only)
4 allocationCount (read-only; nil in Cog VMs)
5 allocations between GCs (read-write; nil in Cog VMs)
6 survivor count tenuring threshold (read-write)
7 full GCs since startup (read-only)
8 total milliseconds in full GCs since startup (read-only)
9 incremental GCs since startup (read-only; scavenging GCs on Spur)
10 total milliseconds in incremental/scavenging GCs since startup (read-only)
11 tenures of surving objects since startup (read-only)
12-15 specific to the translating VM
16 total microseconds in idle since startup
17 proportion of code zone available for use (Sista VMs only; read-write)
18 total milliseconds in full GC compaction since startup (a portion of parameter 8)
19 scavenge threshold; the effective size of eden
20 utc microseconds at VM start-up (actually at time initialization, which precedes image load) (newer Cog VMs only).
21 root (remembered) table size (read-only)
22 root (remembered) table overflows since startup (read-only)
23 bytes of extra memory to reserve for VM buffers, plugins, etc.
24 memory threshold above which to shrink object memory (read-write)
25 ammount to grow by when growing object memory (read-write)
26 interruptChecksEveryNms - force an ioProcessEvents every N milliseconds (read-write)
27 number of times mark loop iterated for current IGC/FGC (read-only) includes ALL marking
28 number of times sweep loop iterated for current IGC/FGC (read-only)
29 number of times make forward loop iterated for current IGC/FGC (read-only)
30 number of times compact move loop iterated for current IGC/FGC (read-only)
31 number of grow memory requests (read-only)
32 number of shrink memory requests (read-only)
33 number of root table entries used for current IGC/FGC (read-only)
34 bytes allocated in total since start-up or reset (read-write)
35 number of survivor objects after current IGC/FGC (read-only)
36 millisecond clock when current IGC/FGC completed (read-only)
37 number of marked objects for Roots of the world, not including Root Table entries for current IGC/FGC (read-only)
38 milliseconds taken by current IGC (read-only)
39 Number of finalization signals for Weak Objects pending when current IGC/FGC completed (read-only)
40 BytesPerWord for this image
41 imageFormatVersion for the VM
42 number of stack pages in use (Cog Stack VM only, otherwise nil)
43 desired number of stack pages (stored in image file header, max 65535; Cog VMs only, otherwise nil)
44 size of eden, in bytes (Cog VMs only, otherwise nil)
45 desired size of eden, in bytes (stored in image file header; Cog VMs only, otherwise nil)
46 size of machine code zone, in bytes (stored in image file header; Cog JIT VM only, otherwise nil)
47 desired size of machine code zone, in bytes (applies at startup only, stored in image file header; Cog JIT VM only)
48 various properties of the Cog VM as an integer encoding an array of bit flags.
Bit 0: tells the VM that the image's Process class has threadId as its 5th inst var (after nextLink, suspendedContext, priority & myList)
Bit 1: on Cog JIT VMs asks the VM to set the flag bit in interpreted methods
Bit 2: if set, preempting a process puts it to the head of its run queue, not the back,
i.e. preempting a process by a higher priority one will not cause the preempted process to yield
to others at the same priority.
Bit 3: in a muilt-threaded VM, if set, the Window system will only be accessed from the first VM thread
Bit 4: in a Spur vm, if set, causes weaklings and ephemerons to be queued individually for finalization
Bit 5: if set, implies wheel events will be delivered as such and not mapped to arrow key events
Bit 6: if set, implies arithmetic primitives will fail if given arguments of different types (float vs int)
49 the size of the external semaphore table (read-write; Cog VMs only)
50-51 reserved for VM parameters that persist in the image (such as eden above)
52 root (remembered) table maximum size (read-only)
53 the number of oldSpace segments (Spur only, otherwise nil)
54 total size of free old space (Spur only, otherwise nil)
55 ratio of growth and image size at or above which a GC will be performed post scavenge (Spur only, otherwise nil)
56 number of process switches since startup (read-only)
57 number of ioProcessEvents calls since startup (read-only)
58 number of forceInterruptCheck (Cog VMs) or quickCheckInterruptCalls (non-Cog VMs) calls since startup (read-only)
59 number of check event calls since startup (read-only)
60 number of stack page overflows since startup (read-only; Cog VMs only)
61 number of stack page divorces since startup (read-only; Cog VMs only)
62 number of machine code zone compactions since startup (read-only; Cog VMs only)
63 milliseconds taken by machine code zone compactions since startup (read-only; Cog VMs only)
64 current number of machine code methods (read-only; Cog VMs only)
65 In newer Cog VMs a set of flags describing VM features,
if non-zero bit 0 implies multiple bytecode set support;
+ if non-zero bit 1 implies read-only object support;
+ if non-zero bit 2 implies the VM suffers from using an ITIMER heartbeat (if 0 it has a thread that provides the heartbeat)
- if non-zero bit 0 implies read-only object support
(read-only; Cog VMs only; nil in older Cog VMs, a boolean answering multiple bytecode support in not so old Cog VMs)
66 the byte size of a stack page in the stack zone (read-only; Cog VMs only)
67 the maximum allowed size of old space in bytes, 0 implies no internal limit (Spur VMs only).
68 the average number of live stack pages when scanned by GC (at scavenge/gc/become et al)
69 the maximum number of live stack pages when scanned by GC (at scavenge/gc/become et al)
70 the value of VM_PROXY_MAJOR (the interpreterProxy major version number)
71 the value of VM_PROXY_MINOR (the interpreterProxy minor version number)
72 total milliseconds in full GCs Mark phase since startup (read-only)
73 total milliseconds in full GCs Sweep phase since startup (read-only, can be 0 depending on compactors)
74 maximum pause time due to segment allocation"
<primitive: 254>
self primitiveFailed!