Eliot Miranda uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System.spur-cwp.670.mcz
==================== Summary ====================
Name: System.spur-cwp.670
Author: eem
Time: 26 June 2014, 5:28:50.051 pm
UUID: fd5710f2-36da-4775-9731-bbad54bdebd4
Ancestors: System-cwp.670
System-cwp.670 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
Rename EnvironmentRequest to CurrentEnvironment, use the new "Environment current" mechanism where appropriate.
=============== Diff against System-cwp.670 ===============
Item was changed:
----- Method: SmalltalkImage>>compactClassesArray (in category 'special objects') -----
compactClassesArray
"Smalltalk compactClassesArray"
+ "Backward-compatibility support. Spur does not have compact classes."
+ ^{}!
- "Return the array of 31 classes whose instances may be
- represented compactly"
- ^ self specialObjectsArray at: 29!
Item was added:
+ ----- Method: SmalltalkImage>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Essential. Fail if no memory is available."
+ <primitive: 180>
+ (numBytes isInteger and: [numBytes > 0]) ifTrue:
+ [OutOfMemory signal].
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SmalltalkImage>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was changed:
----- Method: SmalltalkImage>>setGCParameters (in category 'snapshot and quit') -----
setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
- "Adjust the VM's default GC parameters to avoid premature tenuring."
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
- self vmParameterAt: 5 put: 4000. "do an incremental GC after this many allocations"
- self vmParameterAt: 6 put: 2000. "tenure when more than this many objects survive the GC"
- !
Item was changed:
----- Method: SpaceTally>>spaceForInstancesOf: (in category 'instance size') -----
spaceForInstancesOf: aClass
+ "Answer a pair of the number of bytes consumed by all instances of the
+ given class, including their object headers, and the number of instances."
- "Answer the number of bytes consumed by all instances of the given class, including their object headers and the number of instances."
+ | instances total |
+ instances := aClass allInstances.
+ instances isEmpty ifTrue: [^#(0 0)].
- | smallHeaderSize instVarBytes isVariable bytesPerElement total lastInstance instance instanceCount |
- instance := aClass someInstance ifNil: [ ^#(0 0) ].
- smallHeaderSize := aClass isCompact ifTrue: [ 4 ] ifFalse: [ 8 ].
- instVarBytes := aClass instSize * 4.
- isVariable := aClass isVariable.
- bytesPerElement := isVariable
- ifFalse: [ 0 ]
- ifTrue: [ aClass isBytes ifTrue: [ 1 ] ifFalse: [ 4 ] ].
total := 0.
+ aClass isVariable
+ ifTrue:
+ [instances do:
+ [:i| total := total + (aClass byteSizeOfInstanceOfSize: i basicSize)]]
+ ifFalse:
+ [total := instances size * aClass byteSizeOfInstance].
+ ^{ total. instances size }!
- instanceCount := 0.
- "A modified version of #allInstancesDo: is inlined here. It avoids an infinite loop when another process is creating new instances of aClass."
- self flag: #allInstancesDo:.
- lastInstance :=
- aClass == CompiledMethod "CompiledMethod has special format, see its class comment"
- ifTrue: [aClass new]
- ifFalse: [aClass basicNew].
- [ instance == lastInstance ] whileFalse: [
- | contentBytes headerBytes |
- contentBytes := instVarBytes + (isVariable
- ifFalse: [ 0 ]
- ifTrue: [ instance basicSize * bytesPerElement ]).
- headerBytes := contentBytes > 255
- ifTrue: [ 12 ]
- ifFalse: [ smallHeaderSize ].
- total := total + headerBytes + (contentBytes roundUpTo: 4).
- instanceCount := instanceCount + 1.
- instance := instance nextInstance ].
- ^{ total. instanceCount }!
Item was added:
+ ----- Method: SystemDictionary>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Fail if no memory is available. Essential."
+ <primitive: 180>
+ ^(numBytes isInteger and: [numBytes > 0])
+ ifTrue: [OutOfMemory signal]
+ ifFalse: [self primitiveFailed]!
Item was added:
+ ----- Method: SystemDictionary>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SystemDictionary>>setGCParameters (in category 'as yet unclassified') -----
+ setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
+
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
Item was added:
+ ----- Method: SystemNavigation>>allObjects (in category 'as yet unclassified') -----
+ allObjects
+ "Answer an Array of all objects in the system. Fail if
+ there isn't enough memory to instantiate the result."
+ <primitive: 178>
+ ^self primitiveFailed!
Item was changed:
----- Method: SystemNavigation>>allObjectsDo: (in category 'query') -----
allObjectsDo: aBlock
+ "Evaluate the argument, aBlock, for each object in the system, excluding immediates
+ such as SmallInteger and Character."
+ self allObjectsOrNil
+ ifNotNil: [:allObjects| allObjects do: aBlock]
+ ifNil:
+ ["Fall back on the old single object primitive code. With closures, this needs
+ to use an end marker (lastObject) since activation of the block will create
+ new contexts and cause an infinite loop. The lastObject must be created
+ before calling someObject, so that the VM can settle the enumeration (e.g.
+ by flushing new space) as a side effect of someObject"
+ | object lastObject |
+ lastObject := Object new.
+ object := self someObject.
+ [lastObject == object or: [0 == object]] whileFalse:
+ [aBlock value: object.
+ object := object nextObject]]!
- "Evaluate the argument, aBlock, for each object in the system
- excluding SmallIntegers. With closures, this needs to use an end
- marker (lastObject) since activation of the block will create new
- contexts and cause an infinite loop."
- | object lastObject |
- object := self someObject.
- lastObject := Object new.
- [lastObject == object or: [0 == object]]
- whileFalse: [aBlock value: object.
- object := object nextObject]!
Item was added:
+ ----- Method: SystemNavigation>>allObjectsOrNil (in category 'as yet unclassified') -----
+ allObjectsOrNil
+ "Answer an Array of all objects in the system. Fail if there isn't
+ enough memory to instantiate the result and answer nil."
+ <primitive: 178>
+ ^nil!
Eliot Miranda uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System.spur-cmm.669.mcz
==================== Summary ====================
Name: System.spur-cmm.669
Author: eem
Time: 26 June 2014, 5:28:44.931 pm
UUID: 3037b349-8896-4bb0-9ef3-1943b62e3494
Ancestors: System-cmm.669
System-cmm.669 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
#moveChanges should prompt for the name of the condensed sources.
=============== Diff against System-cmm.669 ===============
Item was changed:
----- Method: SmalltalkImage>>compactClassesArray (in category 'special objects') -----
compactClassesArray
"Smalltalk compactClassesArray"
+ "Backward-compatibility support. Spur does not have compact classes."
+ ^{}!
- "Return the array of 31 classes whose instances may be
- represented compactly"
- ^ self specialObjectsArray at: 29!
Item was added:
+ ----- Method: SmalltalkImage>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Essential. Fail if no memory is available."
+ <primitive: 180>
+ (numBytes isInteger and: [numBytes > 0]) ifTrue:
+ [OutOfMemory signal].
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SmalltalkImage>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was changed:
----- Method: SmalltalkImage>>setGCParameters (in category 'snapshot and quit') -----
setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
- "Adjust the VM's default GC parameters to avoid premature tenuring."
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
- self vmParameterAt: 5 put: 4000. "do an incremental GC after this many allocations"
- self vmParameterAt: 6 put: 2000. "tenure when more than this many objects survive the GC"
- !
Item was changed:
----- Method: SpaceTally>>spaceForInstancesOf: (in category 'instance size') -----
spaceForInstancesOf: aClass
+ "Answer a pair of the number of bytes consumed by all instances of the
+ given class, including their object headers, and the number of instances."
- "Answer the number of bytes consumed by all instances of the given class, including their object headers and the number of instances."
+ | instances total |
+ instances := aClass allInstances.
+ instances isEmpty ifTrue: [^#(0 0)].
- | smallHeaderSize instVarBytes isVariable bytesPerElement total lastInstance instance instanceCount |
- instance := aClass someInstance ifNil: [ ^#(0 0) ].
- smallHeaderSize := aClass isCompact ifTrue: [ 4 ] ifFalse: [ 8 ].
- instVarBytes := aClass instSize * 4.
- isVariable := aClass isVariable.
- bytesPerElement := isVariable
- ifFalse: [ 0 ]
- ifTrue: [ aClass isBytes ifTrue: [ 1 ] ifFalse: [ 4 ] ].
total := 0.
+ aClass isVariable
+ ifTrue:
+ [instances do:
+ [:i| total := total + (aClass byteSizeOfInstanceOfSize: i basicSize)]]
+ ifFalse:
+ [total := instances size * aClass byteSizeOfInstance].
+ ^{ total. instances size }!
- instanceCount := 0.
- "A modified version of #allInstancesDo: is inlined here. It avoids an infinite loop when another process is creating new instances of aClass."
- self flag: #allInstancesDo:.
- lastInstance :=
- aClass == CompiledMethod "CompiledMethod has special format, see its class comment"
- ifTrue: [aClass new]
- ifFalse: [aClass basicNew].
- [ instance == lastInstance ] whileFalse: [
- | contentBytes headerBytes |
- contentBytes := instVarBytes + (isVariable
- ifFalse: [ 0 ]
- ifTrue: [ instance basicSize * bytesPerElement ]).
- headerBytes := contentBytes > 255
- ifTrue: [ 12 ]
- ifFalse: [ smallHeaderSize ].
- total := total + headerBytes + (contentBytes roundUpTo: 4).
- instanceCount := instanceCount + 1.
- instance := instance nextInstance ].
- ^{ total. instanceCount }!
Item was added:
+ ----- Method: SystemDictionary>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Fail if no memory is available. Essential."
+ <primitive: 180>
+ ^(numBytes isInteger and: [numBytes > 0])
+ ifTrue: [OutOfMemory signal]
+ ifFalse: [self primitiveFailed]!
Item was added:
+ ----- Method: SystemDictionary>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SystemDictionary>>setGCParameters (in category 'as yet unclassified') -----
+ setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
+
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
Item was added:
+ ----- Method: SystemNavigation>>allObjects (in category 'as yet unclassified') -----
+ allObjects
+ "Answer an Array of all objects in the system. Fail if
+ there isn't enough memory to instantiate the result."
+ <primitive: 178>
+ ^self primitiveFailed!
Item was changed:
----- Method: SystemNavigation>>allObjectsDo: (in category 'query') -----
allObjectsDo: aBlock
+ "Evaluate the argument, aBlock, for each object in the system, excluding immediates
+ such as SmallInteger and Character."
+ self allObjectsOrNil
+ ifNotNil: [:allObjects| allObjects do: aBlock]
+ ifNil:
+ ["Fall back on the old single object primitive code. With closures, this needs
+ to use an end marker (lastObject) since activation of the block will create
+ new contexts and cause an infinite loop. The lastObject must be created
+ before calling someObject, so that the VM can settle the enumeration (e.g.
+ by flushing new space) as a side effect of someObject"
+ | object lastObject |
+ lastObject := Object new.
+ object := self someObject.
+ [lastObject == object or: [0 == object]] whileFalse:
+ [aBlock value: object.
+ object := object nextObject]]!
- "Evaluate the argument, aBlock, for each object in the system
- excluding SmallIntegers. With closures, this needs to use an end
- marker (lastObject) since activation of the block will create new
- contexts and cause an infinite loop."
- | object lastObject |
- object := self someObject.
- lastObject := Object new.
- [lastObject == object or: [0 == object]]
- whileFalse: [aBlock value: object.
- object := object nextObject]!
Item was added:
+ ----- Method: SystemNavigation>>allObjectsOrNil (in category 'as yet unclassified') -----
+ allObjectsOrNil
+ "Answer an Array of all objects in the system. Fail if there isn't
+ enough memory to instantiate the result and answer nil."
+ <primitive: 178>
+ ^nil!
Eliot Miranda uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System.spur-cmm.668.mcz
==================== Summary ====================
Name: System.spur-cmm.668
Author: eem
Time: 26 June 2014, 5:28:39.898 pm
UUID: 7becf71d-af15-4fbc-9ecf-bdb7bd8a639f
Ancestors: System-cmm.668
System-cmm.668 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
- Fix to SmalltalkImage>>#sourcesName allows appending the changes to the sources file (via Levente's SmalltalkImage>>#appendChangesTo:) to work.
- Added #moveChanges as this should become a normal part of the release process.
- Some categorizations.
=============== Diff against System-cmm.668 ===============
Item was changed:
----- Method: SmalltalkImage>>compactClassesArray (in category 'special objects') -----
compactClassesArray
"Smalltalk compactClassesArray"
+ "Backward-compatibility support. Spur does not have compact classes."
+ ^{}!
- "Return the array of 31 classes whose instances may be
- represented compactly"
- ^ self specialObjectsArray at: 29!
Item was added:
+ ----- Method: SmalltalkImage>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Essential. Fail if no memory is available."
+ <primitive: 180>
+ (numBytes isInteger and: [numBytes > 0]) ifTrue:
+ [OutOfMemory signal].
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SmalltalkImage>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was changed:
----- Method: SmalltalkImage>>setGCParameters (in category 'snapshot and quit') -----
setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
- "Adjust the VM's default GC parameters to avoid premature tenuring."
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
- self vmParameterAt: 5 put: 4000. "do an incremental GC after this many allocations"
- self vmParameterAt: 6 put: 2000. "tenure when more than this many objects survive the GC"
- !
Item was changed:
----- Method: SpaceTally>>spaceForInstancesOf: (in category 'instance size') -----
spaceForInstancesOf: aClass
+ "Answer a pair of the number of bytes consumed by all instances of the
+ given class, including their object headers, and the number of instances."
- "Answer the number of bytes consumed by all instances of the given class, including their object headers and the number of instances."
+ | instances total |
+ instances := aClass allInstances.
+ instances isEmpty ifTrue: [^#(0 0)].
- | smallHeaderSize instVarBytes isVariable bytesPerElement total lastInstance instance instanceCount |
- instance := aClass someInstance ifNil: [ ^#(0 0) ].
- smallHeaderSize := aClass isCompact ifTrue: [ 4 ] ifFalse: [ 8 ].
- instVarBytes := aClass instSize * 4.
- isVariable := aClass isVariable.
- bytesPerElement := isVariable
- ifFalse: [ 0 ]
- ifTrue: [ aClass isBytes ifTrue: [ 1 ] ifFalse: [ 4 ] ].
total := 0.
+ aClass isVariable
+ ifTrue:
+ [instances do:
+ [:i| total := total + (aClass byteSizeOfInstanceOfSize: i basicSize)]]
+ ifFalse:
+ [total := instances size * aClass byteSizeOfInstance].
+ ^{ total. instances size }!
- instanceCount := 0.
- "A modified version of #allInstancesDo: is inlined here. It avoids an infinite loop when another process is creating new instances of aClass."
- self flag: #allInstancesDo:.
- lastInstance :=
- aClass == CompiledMethod "CompiledMethod has special format, see its class comment"
- ifTrue: [aClass new]
- ifFalse: [aClass basicNew].
- [ instance == lastInstance ] whileFalse: [
- | contentBytes headerBytes |
- contentBytes := instVarBytes + (isVariable
- ifFalse: [ 0 ]
- ifTrue: [ instance basicSize * bytesPerElement ]).
- headerBytes := contentBytes > 255
- ifTrue: [ 12 ]
- ifFalse: [ smallHeaderSize ].
- total := total + headerBytes + (contentBytes roundUpTo: 4).
- instanceCount := instanceCount + 1.
- instance := instance nextInstance ].
- ^{ total. instanceCount }!
Item was added:
+ ----- Method: SystemDictionary>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Fail if no memory is available. Essential."
+ <primitive: 180>
+ ^(numBytes isInteger and: [numBytes > 0])
+ ifTrue: [OutOfMemory signal]
+ ifFalse: [self primitiveFailed]!
Item was added:
+ ----- Method: SystemDictionary>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SystemDictionary>>setGCParameters (in category 'as yet unclassified') -----
+ setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
+
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
Item was added:
+ ----- Method: SystemNavigation>>allObjects (in category 'as yet unclassified') -----
+ allObjects
+ "Answer an Array of all objects in the system. Fail if
+ there isn't enough memory to instantiate the result."
+ <primitive: 178>
+ ^self primitiveFailed!
Item was changed:
----- Method: SystemNavigation>>allObjectsDo: (in category 'query') -----
allObjectsDo: aBlock
+ "Evaluate the argument, aBlock, for each object in the system, excluding immediates
+ such as SmallInteger and Character."
+ self allObjectsOrNil
+ ifNotNil: [:allObjects| allObjects do: aBlock]
+ ifNil:
+ ["Fall back on the old single object primitive code. With closures, this needs
+ to use an end marker (lastObject) since activation of the block will create
+ new contexts and cause an infinite loop. The lastObject must be created
+ before calling someObject, so that the VM can settle the enumeration (e.g.
+ by flushing new space) as a side effect of someObject"
+ | object lastObject |
+ lastObject := Object new.
+ object := self someObject.
+ [lastObject == object or: [0 == object]] whileFalse:
+ [aBlock value: object.
+ object := object nextObject]]!
- "Evaluate the argument, aBlock, for each object in the system
- excluding SmallIntegers. With closures, this needs to use an end
- marker (lastObject) since activation of the block will create new
- contexts and cause an infinite loop."
- | object lastObject |
- object := self someObject.
- lastObject := Object new.
- [lastObject == object or: [0 == object]]
- whileFalse: [aBlock value: object.
- object := object nextObject]!
Item was added:
+ ----- Method: SystemNavigation>>allObjectsOrNil (in category 'as yet unclassified') -----
+ allObjectsOrNil
+ "Answer an Array of all objects in the system. Fail if there isn't
+ enough memory to instantiate the result and answer nil."
+ <primitive: 178>
+ ^nil!
Eliot Miranda uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System.spur-cmm.667.mcz
==================== Summary ====================
Name: System.spur-cmm.667
Author: eem
Time: 26 June 2014, 5:28:34.664 pm
UUID: 236f1600-f04d-44a0-a5a5-500a8af8ccdc
Ancestors: System-cmm.667
System-cmm.667 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
- Added method to get a valid MethodReference from a stale, invalid one.
=============== Diff against System-cmm.667 ===============
Item was changed:
----- Method: SmalltalkImage>>compactClassesArray (in category 'special objects') -----
compactClassesArray
"Smalltalk compactClassesArray"
+ "Backward-compatibility support. Spur does not have compact classes."
+ ^{}!
- "Return the array of 31 classes whose instances may be
- represented compactly"
- ^ self specialObjectsArray at: 29!
Item was added:
+ ----- Method: SmalltalkImage>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Essential. Fail if no memory is available."
+ <primitive: 180>
+ (numBytes isInteger and: [numBytes > 0]) ifTrue:
+ [OutOfMemory signal].
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SmalltalkImage>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was changed:
----- Method: SmalltalkImage>>setGCParameters (in category 'snapshot and quit') -----
setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
- "Adjust the VM's default GC parameters to avoid premature tenuring."
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
- self vmParameterAt: 5 put: 4000. "do an incremental GC after this many allocations"
- self vmParameterAt: 6 put: 2000. "tenure when more than this many objects survive the GC"
- !
Item was changed:
----- Method: SpaceTally>>spaceForInstancesOf: (in category 'instance size') -----
spaceForInstancesOf: aClass
+ "Answer a pair of the number of bytes consumed by all instances of the
+ given class, including their object headers, and the number of instances."
- "Answer the number of bytes consumed by all instances of the given class, including their object headers and the number of instances."
+ | instances total |
+ instances := aClass allInstances.
+ instances isEmpty ifTrue: [^#(0 0)].
- | smallHeaderSize instVarBytes isVariable bytesPerElement total lastInstance instance instanceCount |
- instance := aClass someInstance ifNil: [ ^#(0 0) ].
- smallHeaderSize := aClass isCompact ifTrue: [ 4 ] ifFalse: [ 8 ].
- instVarBytes := aClass instSize * 4.
- isVariable := aClass isVariable.
- bytesPerElement := isVariable
- ifFalse: [ 0 ]
- ifTrue: [ aClass isBytes ifTrue: [ 1 ] ifFalse: [ 4 ] ].
total := 0.
+ aClass isVariable
+ ifTrue:
+ [instances do:
+ [:i| total := total + (aClass byteSizeOfInstanceOfSize: i basicSize)]]
+ ifFalse:
+ [total := instances size * aClass byteSizeOfInstance].
+ ^{ total. instances size }!
- instanceCount := 0.
- "A modified version of #allInstancesDo: is inlined here. It avoids an infinite loop when another process is creating new instances of aClass."
- self flag: #allInstancesDo:.
- lastInstance :=
- aClass == CompiledMethod "CompiledMethod has special format, see its class comment"
- ifTrue: [aClass new]
- ifFalse: [aClass basicNew].
- [ instance == lastInstance ] whileFalse: [
- | contentBytes headerBytes |
- contentBytes := instVarBytes + (isVariable
- ifFalse: [ 0 ]
- ifTrue: [ instance basicSize * bytesPerElement ]).
- headerBytes := contentBytes > 255
- ifTrue: [ 12 ]
- ifFalse: [ smallHeaderSize ].
- total := total + headerBytes + (contentBytes roundUpTo: 4).
- instanceCount := instanceCount + 1.
- instance := instance nextInstance ].
- ^{ total. instanceCount }!
Item was added:
+ ----- Method: SystemDictionary>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Fail if no memory is available. Essential."
+ <primitive: 180>
+ ^(numBytes isInteger and: [numBytes > 0])
+ ifTrue: [OutOfMemory signal]
+ ifFalse: [self primitiveFailed]!
Item was added:
+ ----- Method: SystemDictionary>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SystemDictionary>>setGCParameters (in category 'as yet unclassified') -----
+ setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
+
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
Item was added:
+ ----- Method: SystemNavigation>>allObjects (in category 'as yet unclassified') -----
+ allObjects
+ "Answer an Array of all objects in the system. Fail if
+ there isn't enough memory to instantiate the result."
+ <primitive: 178>
+ ^self primitiveFailed!
Item was changed:
----- Method: SystemNavigation>>allObjectsDo: (in category 'query') -----
allObjectsDo: aBlock
+ "Evaluate the argument, aBlock, for each object in the system, excluding immediates
+ such as SmallInteger and Character."
+ self allObjectsOrNil
+ ifNotNil: [:allObjects| allObjects do: aBlock]
+ ifNil:
+ ["Fall back on the old single object primitive code. With closures, this needs
+ to use an end marker (lastObject) since activation of the block will create
+ new contexts and cause an infinite loop. The lastObject must be created
+ before calling someObject, so that the VM can settle the enumeration (e.g.
+ by flushing new space) as a side effect of someObject"
+ | object lastObject |
+ lastObject := Object new.
+ object := self someObject.
+ [lastObject == object or: [0 == object]] whileFalse:
+ [aBlock value: object.
+ object := object nextObject]]!
- "Evaluate the argument, aBlock, for each object in the system
- excluding SmallIntegers. With closures, this needs to use an end
- marker (lastObject) since activation of the block will create new
- contexts and cause an infinite loop."
- | object lastObject |
- object := self someObject.
- lastObject := Object new.
- [lastObject == object or: [0 == object]]
- whileFalse: [aBlock value: object.
- object := object nextObject]!
Item was added:
+ ----- Method: SystemNavigation>>allObjectsOrNil (in category 'as yet unclassified') -----
+ allObjectsOrNil
+ "Answer an Array of all objects in the system. Fail if there isn't
+ enough memory to instantiate the result and answer nil."
+ <primitive: 178>
+ ^nil!
Eliot Miranda uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System.spur-dtl.666.mcz
==================== Summary ====================
Name: System.spur-dtl.666
Author: eem
Time: 26 June 2014, 5:28:55.798 pm
UUID: d673105c-29df-4497-8c8b-b7a8247384ee
Ancestors: System-dtl.666
System-dtl.666 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
Sending basicNew to CompiledMethod may crash the VM, so don't do that.
=============== Diff against System-dtl.666 ===============
Item was changed:
----- Method: SmalltalkImage>>compactClassesArray (in category 'special objects') -----
compactClassesArray
"Smalltalk compactClassesArray"
+ "Backward-compatibility support. Spur does not have compact classes."
+ ^{}!
- "Return the array of 31 classes whose instances may be
- represented compactly"
- ^ self specialObjectsArray at: 29!
Item was added:
+ ----- Method: SmalltalkImage>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Essential. Fail if no memory is available."
+ <primitive: 180>
+ (numBytes isInteger and: [numBytes > 0]) ifTrue:
+ [OutOfMemory signal].
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SmalltalkImage>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was changed:
----- Method: SmalltalkImage>>setGCParameters (in category 'snapshot and quit') -----
setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
- "Adjust the VM's default GC parameters to avoid premature tenuring."
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
- self vmParameterAt: 5 put: 4000. "do an incremental GC after this many allocations"
- self vmParameterAt: 6 put: 2000. "tenure when more than this many objects survive the GC"
- !
Item was changed:
----- Method: SpaceTally>>spaceForInstancesOf: (in category 'instance size') -----
spaceForInstancesOf: aClass
+ "Answer a pair of the number of bytes consumed by all instances of the
+ given class, including their object headers, and the number of instances."
- "Answer the number of bytes consumed by all instances of the given class, including their object headers and the number of instances."
+ | instances total |
+ instances := aClass allInstances.
+ instances isEmpty ifTrue: [^#(0 0)].
- | smallHeaderSize instVarBytes isVariable bytesPerElement total lastInstance instance instanceCount |
- instance := aClass someInstance ifNil: [ ^#(0 0) ].
- smallHeaderSize := aClass isCompact ifTrue: [ 4 ] ifFalse: [ 8 ].
- instVarBytes := aClass instSize * 4.
- isVariable := aClass isVariable.
- bytesPerElement := isVariable
- ifFalse: [ 0 ]
- ifTrue: [ aClass isBytes ifTrue: [ 1 ] ifFalse: [ 4 ] ].
total := 0.
+ aClass isVariable
+ ifTrue:
+ [instances do:
+ [:i| total := total + (aClass byteSizeOfInstanceOfSize: i basicSize)]]
+ ifFalse:
+ [total := instances size * aClass byteSizeOfInstance].
+ ^{ total. instances size }!
- instanceCount := 0.
- "A modified version of #allInstancesDo: is inlined here. It avoids an infinite loop when another process is creating new instances of aClass."
- self flag: #allInstancesDo:.
- lastInstance :=
- aClass == CompiledMethod "CompiledMethod has special format, see its class comment"
- ifTrue: [aClass new]
- ifFalse: [aClass basicNew].
- [ instance == lastInstance ] whileFalse: [
- | contentBytes headerBytes |
- contentBytes := instVarBytes + (isVariable
- ifFalse: [ 0 ]
- ifTrue: [ instance basicSize * bytesPerElement ]).
- headerBytes := contentBytes > 255
- ifTrue: [ 12 ]
- ifFalse: [ smallHeaderSize ].
- total := total + headerBytes + (contentBytes roundUpTo: 4).
- instanceCount := instanceCount + 1.
- instance := instance nextInstance ].
- ^{ total. instanceCount }!
Item was added:
+ ----- Method: SystemDictionary>>growMemoryByAtLeast: (in category 'as yet unclassified') -----
+ growMemoryByAtLeast: numBytes
+ "Grow memory by at least the requested number of bytes.
+ Primitive. Fail if no memory is available. Essential."
+ <primitive: 180>
+ ^(numBytes isInteger and: [numBytes > 0])
+ ifTrue: [OutOfMemory signal]
+ ifFalse: [self primitiveFailed]!
Item was added:
+ ----- Method: SystemDictionary>>maxIdentityHash (in category 'as yet unclassified') -----
+ maxIdentityHash
+ "Answer the maximum identityHash value supported by the VM."
+ <primitive: 176>
+ ^self primitiveFailed!
Item was added:
+ ----- Method: SystemDictionary>>setGCParameters (in category 'as yet unclassified') -----
+ setGCParameters
+ "Adjust the VM's default GC parameters to avoid too much tenuring.
+ Maybe this should be left to the VM?"
+
+ | proportion edenSize survivorSize averageObjectSize numObjects |
+ proportion := 0.9. "tenure when 90% of pastSpace is full"
+ edenSize := SmalltalkImage current vmParameterAt: 44.
+ survivorSize := edenSize / 5.0. "David's paper uses 140Kb eden + 2 x 28kb survivor spaces; Spur uses the same ratios :-)"
+ averageObjectSize := 8 * self wordSize. "a good approximation"
+ numObjects := (proportion * survivorSize / averageObjectSize) rounded.
+ SmalltalkImage current vmParameterAt: 6 put: numObjects "tenure when more than this many objects survive the GC"!
Item was added:
+ ----- Method: SystemNavigation>>allObjects (in category 'as yet unclassified') -----
+ allObjects
+ "Answer an Array of all objects in the system. Fail if
+ there isn't enough memory to instantiate the result."
+ <primitive: 178>
+ ^self primitiveFailed!
Item was changed:
----- Method: SystemNavigation>>allObjectsDo: (in category 'query') -----
allObjectsDo: aBlock
+ "Evaluate the argument, aBlock, for each object in the system, excluding immediates
+ such as SmallInteger and Character."
+ self allObjectsOrNil
+ ifNotNil: [:allObjects| allObjects do: aBlock]
+ ifNil:
+ ["Fall back on the old single object primitive code. With closures, this needs
+ to use an end marker (lastObject) since activation of the block will create
+ new contexts and cause an infinite loop. The lastObject must be created
+ before calling someObject, so that the VM can settle the enumeration (e.g.
+ by flushing new space) as a side effect of someObject"
+ | object lastObject |
+ lastObject := Object new.
+ object := self someObject.
+ [lastObject == object or: [0 == object]] whileFalse:
+ [aBlock value: object.
+ object := object nextObject]]!
- "Evaluate the argument, aBlock, for each object in the system
- excluding SmallIntegers. With closures, this needs to use an end
- marker (lastObject) since activation of the block will create new
- contexts and cause an infinite loop."
- | object lastObject |
- object := self someObject.
- lastObject := Object new.
- [lastObject == object or: [0 == object]]
- whileFalse: [aBlock value: object.
- object := object nextObject]!
Item was added:
+ ----- Method: SystemNavigation>>allObjectsOrNil (in category 'as yet unclassified') -----
+ allObjectsOrNil
+ "Answer an Array of all objects in the system. Fail if there isn't
+ enough memory to instantiate the result and answer nil."
+ <primitive: 178>
+ ^nil!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel.spur-eem.857.mcz
==================== Summary ====================
Name: Kernel.spur-eem.857
Author: eem
Time: 26 June 2014, 5:27:37.986 pm
UUID: 54a23565-3aa4-4fc3-9b77-306ba5c6f06d
Ancestors: Kernel-eem.857
Kernel-eem.857 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
Make the debuggber process faithful.
"Process>>effectiveProcess is a mechanism to allow process-
faithful debugging. The debugger executes code on behalf of
processes, so unless some effort is made the identity of
Processor activeProcess is not correctly maintained when
debugging code. The debugger uses evaluate:onBehalfOf: to
assign the debugged process as the effectiveProcess of the
process executing the code, preserving process identity."
=============== Diff against Kernel-eem.857 ===============
Item was changed:
----- Method: Behavior>>allInstances (in category 'accessing instances and variables') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ (inst == insts or: [inst == insts originalContents]) ifFalse: [insts nextPut: inst].
+ inst := next].
+ ^insts contents!
- allInstances
- "Answer a collection of all current instances of the receiver."
-
- | all |
- all := OrderedCollection new.
- self allInstancesDo: [:x | x == all ifFalse: [all add: x]].
- ^ all asArray
- !
Item was changed:
----- Method: Behavior>>allInstancesDo: (in category 'enumerating') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst."
- allInstancesDo: aBlock
- "Evaluate the argument, aBlock, for each of the current instances of the
- receiver.
-
- Because aBlock might change the class of inst (for example, using become:),
- it is essential to compute next before aBlock value: inst."
- | inst next |
inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
- [inst == nil]
- whileFalse:
- [
- next := inst nextInstance.
- aBlock value: inst.
- inst := next]!
Item was added:
+ ----- Method: Behavior>>allInstancesOrNil (in category 'as yet unclassified') -----
+ allInstancesOrNil
+ "Answer all instances of the receiver, or nil if the primitive
+ fails, which it may be due to being out of memory."
+ <primitive: 177>
+ ^nil!
Item was changed:
----- Method: Behavior>>basicNew (in category 'instance creation') -----
basicNew
"Primitive. Answer an instance of the receiver (which is a class) with no
+ indexable variables. Fail if the class is indexable. Essential. See Object
+ documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger
+ will run before the method is activated. Check arguments and
+ retry via handleFailingBasicNew if they're OK."
- indexable variables. Fail if the class is indexable. Essential. See Object
- documentation whatIsAPrimitive."
<primitive: 70>
+ self isVariable ifTrue: [^self basicNew: 0].
+ "space must have been low, and the scavenger must have run.
+ retry after the scavenge."
+ ^self handleFailingBasicNew!
- self isVariable ifTrue: [ ^ self basicNew: 0 ].
- "space must be low"
- OutOfMemory signal.
- ^ self basicNew "retry if user proceeds"
- !
Item was changed:
----- Method: Behavior>>basicNew: (in category 'instance creation') -----
basicNew: sizeRequested
+ "Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger will run before the
+ method is activated. Check args and retry via handleFailingBasicNew: if they're OK."
- "Primitive. Answer an instance of this class with the number
- of indexable variables specified by the argument, sizeRequested.
- Fail if this class is not indexable or if the argument is not a
- positive Integer, or if there is not enough memory available.
- Essential. See Object documentation whatIsAPrimitive."
<primitive: 71>
self isVariable ifFalse:
[self error: self printString, ' cannot have variable sized instances'].
(sizeRequested isInteger and: [sizeRequested >= 0]) ifTrue:
+ ["arg okay; space must have been low, and the scavenger must have run.
+ retry after the scavenge"
+ ^self handleFailingBasicNew: sizeRequested].
- ["arg okay; space must be low."
- OutOfMemory signal.
- ^ self basicNew: sizeRequested "retry if user proceeds"].
self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstance (in category 'as yet unclassified') -----
+ byteSizeOfInstance
+ "Answer the total memory size of an instance of the receiver."
+
+ <primitive: 181>
+ self isVariable ifTrue:
+ [^self byteSizeOfInstanceOfSize: 0].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstanceOfSize: (in category 'as yet unclassified') -----
+ byteSizeOfInstanceOfSize: basicSize
+ "Answer the total memory size of an instance of the receiver
+ with the given number of indexable instance variables."
+
+ <primitive: 181>
+ self isVariable ifFalse:
+ [basicSize = 0 ifTrue:
+ [^self byteSizeOfInstance]].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>elementSize (in category 'as yet unclassified') -----
+ elementSize
+ "Answer the size in bytes of an element in the receiver. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ instSpec < 9 ifTrue: [^Smalltalk wordSize].
+ instSpec >= 16 ifTrue: [^1].
+ instSpec >= 12 ifTrue: [^2].
+ instSpec >= 10 ifTrue: [^4].
+ ^8!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingBasicNew
+ "handleFailingBasicNew gets sent after basicNew has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew. If
+ handleFailingBasicNew fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ Smalltalk garbageCollect < 1048576 ifTrue:
+ [Smalltalk growMemoryByAtLeast: 1048576].
+ ^self handleFailingFailingBasicNew "retry after global garbage collect"!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingBasicNew: sizeRequested
+ "handleFailingBasicNew: gets sent after basicNew: has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew:. If
+ handleFailingBasicNew: fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ | bytesRequested |
+ bytesRequested := self byteSizeOfInstanceOfSize: sizeRequested.
+ Smalltalk garbageCollect < bytesRequested ifTrue:
+ [Smalltalk growMemoryByAtLeast: bytesRequested].
+ "retry after global garbage collect and possible grow"
+ ^self handleFailingFailingBasicNew: sizeRequested!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew
+ "This basicNew gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ "space must be low"
+ OutOfMemory signal.
+ ^self basicNew "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew: sizeRequested
+ "This basicNew: gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew: fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ "space must be low."
+ OutOfMemory signal.
+ ^self basicNew: sizeRequested "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>identityHash (in category 'as yet unclassified') -----
+ identityHash
+ "Answer a SmallInteger whose value is related to the receiver's identity.
+ Behavior implements identityHash to allow the VM to use an object representation which
+ does not include a direct reference to an object's class in an object. If the VM is using
+ this implementation then classes are held in a class table and instances contain the index
+ of their class in the table. A class's class table index is its identityHash so that an instance
+ can be created without searching the table for a class's index. The VM uses this primitive
+ to enter the class into the class table, assigning its identityHash with an as yet unused
+ class table index. If this primitive fails it means that the class table is full. In Spur as of
+ 2014 there are 22 bits of classTable index and 22 bits of identityHash per object.
+
+ Primitive. Essential. Do not override. See Object documentation whatIsAPrimitive."
+
+ <primitive: 175>
+ self primitiveFailed!
Item was changed:
----- Method: Behavior>>instSize (in category 'testing') -----
instSize
"Answer the number of named instance variables
+ (as opposed to indexed variables) of the receiver.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>"
+ ^format bitAnd: 16rFFFF!
- (as opposed to indexed variables) of the receiver."
-
- self flag: #instSizeChange. "Smalltalk browseAllCallsOn: #instSizeChange"
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- When we revise the image format, it should become...
- ^ ((format bitShift: -1) bitAnd: 16rFF) - 1
- Note also that every other method in this category will require
- 2 bits more of right shift after the change.
- "
- ^ ((format bitShift: -10) bitAnd: 16rC0) + ((format bitShift: -1) bitAnd: 16r3F) - 1!
Item was changed:
----- Method: Behavior>>instSpec (in category 'testing') -----
instSpec
+ "Answer the instance specification part of the format that defines what kind of object
+ an instance of the receiver is. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^(format bitShift: -16) bitAnd: 16r1F!
- ^ (format bitShift: -7) bitAnd: 16rF!
Item was changed:
----- Method: Behavior>>isBits (in category 'testing') -----
isBits
+ "Answer whether the receiver contains just bits (not pointers).
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 7!
- "Answer whether the receiver contains just bits (not pointers)."
-
- ^ self instSpec >= 6!
Item was changed:
----- Method: Behavior>>isBytes (in category 'testing') -----
isBytes
+ "Answer whether the receiver has 8-bit instance variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 16!
- "Answer whether the receiver has 8-bit instance variables."
-
- ^ self instSpec >= 8!
Item was added:
+ ----- Method: Behavior>>isEphemeronClass (in category 'as yet unclassified') -----
+ isEphemeronClass
+ "Answer whether the receiver has ephemeral instance variables. The garbage collector will
+ fire (queue for finalization) any ephemeron whose first instance variable is not referenced
+ other than from the transitive closure of references from ephemerons. Hence referring to
+ an object from the first inst var of an ephemeron will cause the ephemeron to fire when
+ the rest of the system does not refer to the object and that object is ready to be collected.
+ Since references from the remaining inst vars of an ephemeron will not prevent the ephemeron
+ from firing, ephemerons may act as the associations in weak dictionaries such that the value
+ (e.g. properties attached to the key) will not prevent firing when the key is no longer referenced
+ other than from ephemerons. Ephemerons can therefore be used to implement instance-based
+ pre-mortem finalization."
+ ^self instSpec = 5!
Item was added:
+ ----- Method: Behavior>>isImmediateClass (in category 'as yet unclassified') -----
+ isImmediateClass
+ "Answer whether the receiver has immediate instances. Immediate instances
+ store their value in their object pointer, not in an object body. Hence immediates
+ take no space and are immutable. The immediates are distinguished by tag bits
+ in the pointer. They include SmallIntegers and Characters. Hence in the 32-bit
+ system SmallIntegers are 31-bit signed integers and Characters are 30-bit
+ unsigned character codes."
+ ^self instSpec = 7!
Item was changed:
----- Method: Behavior>>isVariable (in category 'testing') -----
isVariable
+ "Answer whether the receiver has indexable variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ ^instSpec >= 2 and: [instSpec <= 4 or: [instSpec >= 9]]!
- "Answer whether the receiver has indexable variables."
-
- ^ self instSpec >= 2!
Item was changed:
----- Method: Behavior>>kindOfSubclass (in category 'testing class hierarchy') -----
kindOfSubclass
+ "Answer a String that is the keyword that describes the receiver's kind of subclass,
+ either a regular subclass, a variableSubclass, a variableByteSubclass,
+ a variableWordSubclass, a weakSubclass, an ephemeronSubclass or an immediateSubclass.
+ c.f. typeOfClass"
+ ^self isVariable
+ ifTrue:
+ [self isBits
+ ifTrue:
+ [self isBytes
+ ifTrue: [' variableByteSubclass: ']
+ ifFalse: [' variableWordSubclass: ']]
+ ifFalse:
+ [self isWeak
+ ifTrue: [' weakSubclass: ']
+ ifFalse: [' variableSubclass: ']]]
+ ifFalse:
+ [self isImmediateClass
+ ifTrue: [' immediateSubclass: ']
+ ifFalse:
+ [self isEphemeronClass
+ ifTrue: [' ephemeronSubclass: ']
+ ifFalse: [' subclass: ']]]!
- "Answer a String that is the keyword that describes the receiver's kind
- of subclass, either a regular subclass, a variableSubclass, a
- variableByteSubclass, a variableWordSubclass, or a weakSubclass."
- self isWeak
- ifTrue: [^ ' weakSubclass: '].
- ^ self isVariable
- ifTrue: [self isBits
- ifTrue: [self isBytes
- ifTrue: [ ' variableByteSubclass: ']
- ifFalse: [ ' variableWordSubclass: ']]
- ifFalse: [ ' variableSubclass: ']]
- ifFalse: [ ' subclass: ']!
Item was changed:
----- Method: Behavior>>shouldNotBeRedefined (in category 'testing') -----
shouldNotBeRedefined
+ "Answer if the receiver should not be redefined.
+ The assumption is that classes in Smalltalk specialObjects and
+ instance-specific Behaviors should not be redefined"
- "Return true if the receiver should not be redefined.
- The assumption is that compact classes,
- classes in Smalltalk specialObjects and
- Behaviors should not be redefined"
+ ^(Smalltalk specialObjectsArray
+ identityIndexOf: self
+ ifAbsent: [(self isKindOf: self) ifTrue: [1] ifFalse: [0]]) ~= 0!
- ^(Smalltalk compactClassesArray includes: self)
- or:[(Smalltalk specialObjectsArray includes: self)
- or:[self isKindOf: self]]!
Item was changed:
----- Method: Behavior>>typeOfClass (in category 'accessing') -----
typeOfClass
+ "Answer a symbol uniquely describing the type of the receiver. c.f. kindOfSubclass"
+ self isBytes ifTrue:
+ [^self instSpec = CompiledMethod instSpec
+ ifTrue: [#compiledMethod] "Very special!!"
+ ifFalse: [#bytes]].
+ (self isWords and: [self isPointers not]) ifTrue:
+ [^self instSpec = SmallInteger instSpec
+ ifTrue: [#immediate] "Very special!!"
+ ifFalse: [#words]].
+ self isWeak ifTrue: [^#weak].
+ self isVariable ifTrue: [^#variable].
+ self isEphemeronClass ifTrue: [^#ephemeron].
+ ^#normal!
- "Answer a symbol uniquely describing the type of the receiver"
- self instSpec = CompiledMethod instSpec ifTrue:[^#compiledMethod]. "Very special!!"
- self isBytes ifTrue:[^#bytes].
- (self isWords and:[self isPointers not]) ifTrue:[^#words].
- self isWeak ifTrue:[^#weak].
- self isVariable ifTrue:[^#variable].
- ^#normal.!
Item was added:
+ ----- Method: Class>>immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ immediateSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a new
+ immediate class as a subclass of an existing class (the receiver)."
+ ^ClassBuilder new
+ superclass: self
+ immediateSubclass: t
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>computeFormat:instSize:forSuper:ccIndex: (in category 'class format') -----
computeFormat: type instSize: newInstSize forSuper: newSuper ccIndex: ccIndex
"Compute the new format for making oldClass a subclass of newSuper.
+ Answer the format or nil if there is any problem."
- Return the format or nil if there is any problem."
| instSize isVar isWords isPointers isWeak |
type == #compiledMethod ifTrue:
+ [newInstSize > 0 ifTrue:
+ [self error: 'A compiled method class cannot have named instance variables'.
+ ^nil].
+ ^CompiledMethod format].
- [^(CompiledMethod format
- bitClear: (16r1F bitShift: 11))
- bitOr: (ccIndex bitShift: 11)].
instSize := newInstSize + (newSuper ifNil:[0] ifNotNil:[newSuper instSize]).
+ instSize > 65535 ifTrue:
- instSize > 254 ifTrue:
[self error: 'Class has too many instance variables (', instSize printString,')'.
^nil].
type == #normal ifTrue:[isVar := isWeak := false. isWords := isPointers := true].
type == #bytes ifTrue:[isVar := true. isWords := isPointers := isWeak := false].
type == #words ifTrue:[isVar := isWords := true. isPointers := isWeak := false].
type == #variable ifTrue:[isVar := isPointers := isWords := true. isWeak := false].
type == #weak ifTrue:[isVar := isWeak := isWords := isPointers := true].
+ type == #ephemeron ifTrue:[isVar := false. isWeak := isWords := isPointers := true].
+ type == #immediate ifTrue:[isVar := isWeak := isPointers := false. isWords := true].
+ (isPointers not and: [instSize > 0]) ifTrue:
+ [self error: 'A non-pointer class cannot have named instance variables'.
- (isPointers not and:[instSize > 0]) ifTrue:
- [self error:'A non-pointer class cannot have instance variables'.
^nil].
+ ^self format: instSize variable: isVar words: isWords pointers: isPointers weak: isWeak!
- ^(self format: instSize
- variable: isVar
- words: isWords
- pointers: isPointers
- weak: isWeak) + (ccIndex bitShift: 11).!
Item was changed:
----- Method: ClassBuilder>>format:variable:words:pointers:weak: (in category 'class format') -----
format: nInstVars variable: isVar words: isWords pointers: isPointers weak: isWeak
+ "Compute the format for the given instance specfication.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = reserved for 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
- "Compute the format for the given instance specfication."
- | cClass instSpec sizeHiBits fmt |
- self flag: #instSizeChange.
- "
- Smalltalk browseAllCallsOn: #instSizeChange.
- Smalltalk browseAllImplementorsOf: #fixedFieldsOf:.
- Smalltalk browseAllImplementorsOf: #instantiateClass:indexableSize:.
- "
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- For now the format word is...
- <2 bits=instSize//64><5 bits=cClass><4 bits=instSpec><6 bits=instSize\\64><1 bit=0>
- But when we revise the image format, it should become...
- <5 bits=cClass><4 bits=instSpec><8 bits=instSize><1 bit=0>
- "
- sizeHiBits := (nInstVars+1) // 64.
- cClass := 0. "for now"
instSpec := isWeak
+ ifTrue:
+ [isVar
+ ifTrue: [4]
+ ifFalse: [5]]
+ ifFalse:
+ [isPointers
+ ifTrue:
+ [isVar
+ ifTrue: [nInstVars > 0 ifTrue: [3] ifFalse: [2]]
+ ifFalse: [nInstVars > 0 ifTrue: [1] ifFalse: [0]]]
+ ifFalse:
+ [isVar
+ ifTrue: [isWords ifTrue: [12] ifFalse: [16]]
+ ifFalse: [7]]].
+ ^(instSpec bitShift: 16) + nInstVars!
- ifTrue:[4]
- ifFalse:[isPointers
- ifTrue: [isVar
- ifTrue: [nInstVars>0 ifTrue: [3] ifFalse: [2]]
- ifFalse: [nInstVars>0 ifTrue: [1] ifFalse: [0]]]
- ifFalse: [isWords ifTrue: [6] ifFalse: [8]]].
- fmt := sizeHiBits.
- fmt := (fmt bitShift: 5) + cClass.
- fmt := (fmt bitShift: 4) + instSpec.
- fmt := (fmt bitShift: 6) + ((nInstVars+1)\\64). "+1 since prim size field includes header"
- fmt := (fmt bitShift: 1). "This shift plus integer bit lets wordSize work like byteSize"
- ^fmt!
Item was added:
+ ----- Method: ClassBuilder>>superclass:immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ superclass: aClass
+ immediateSubclass: t instanceVariableNames: f
+ classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a
+ new immediate class as a subclass of an existing class."
+ | env |
+ aClass instSize > 0
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with named fields'].
+ aClass isVariable
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with indexed instance variables'].
+ aClass isPointers
+ ifFalse: [^self error: 'cannot make an immediate subclass of a class without pointer fields'].
+ "Cope with pre-environment and environment versions. Simplify asap."
+ env := (Smalltalk classNamed: #EnvironmentRequest)
+ ifNil: [aClass environment]
+ ifNotNil: [:erc| erc signal ifNil: [aClass environment]].
+ ^self
+ name: t
+ inEnvironment: env
+ subclassOf: aClass
+ type: #immediate
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>update:to: (in category 'class mutation') -----
update: oldClass to: newClass
+ "Convert oldClass, all its instances and possibly its meta class into newClass,
+ instances of newClass and possibly its meta class. The process is surprisingly
+ simple in its implementation and surprisingly complex in its nuances and potentially
+ bad side effects.
+ We can rely on two assumptions (which are critical):
+ #1: The method #updateInstancesFrom: will not create any lasting pointers to
+ 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do
+ a become of the old vs. the new instances and therefore it will not create
+ pointers to *new* instances before the #become: which are *old* afterwards)
+ #2: The non-preemptive execution of the critical piece of code guarantees that
+ nobody can get a hold by 'other means' (such as process interruption and
+ reflection) on the old instances.
+ Given the above two, we know that after #updateInstancesFrom: there are no pointers
+ to any old instances. After the forwarding become there will be no pointers to the old
+ class or meta class either.
+ Andreas Raab, 2/27/2003 23:42"
- "Convert oldClass, all its instances and possibly its meta class into newClass, instances of newClass and possibly its meta class. The process is surprisingly simple in its implementation and surprisingly complex in its nuances and potentially bad side effects.
- We can rely on two assumptions (which are critical):
- #1: The method #updateInstancesFrom: will not create any lasting pointers to 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do a become of the old vs. the new instances and therefore it will not create pointers to *new* instances before the #become: which are *old* afterwards)
- #2: The non-preemptive execution of the critical piece of code guarantees that nobody can get a hold by 'other means' (such as process interruption and reflection) on the old instances.
- Given the above two, we know that after #updateInstancesFrom: there are no pointer to any old instances. After the forwarding become there will be no pointers to the old class or meta class either. Meaning that if we throw in a nice fat GC at the end of the critical block, everything will be gone (but see the comment right there). There's no need to worry.
- "
| meta |
meta := oldClass isMeta.
"Note: Everything from here on will run without the ability to get interrupted
to prevent any other process to create new instances of the old class."
+ ["Note: The following removal may look somewhat obscure and needs an explanation.
+ When we mutate the class hierarchy we create new classes for any existing subclass.
+ So it may look as if we don't have to remove the old class from its superclass. However,
+ at the top of the hierarchy (the first class we reshape) that superclass itself is not newly
+ created so therefore it will hold both the oldClass and newClass in its (obsolete or not)
+ subclasses. Since the #become: below will transparently replace the pointers to oldClass
+ with newClass the superclass would have newClass in its subclasses TWICE. With rather
+ unclear effects if we consider that we may convert the meta-class hierarchy itself (which
+ is derived from the non-meta class hierarchy).
+ Due to this problem ALL classes are removed from their superclass just prior to converting
+ them. Here, breaking the superclass/subclass invariant really doesn't matter since we will
+ effectively remove the oldClass (becomeForward:) just a few lines below."
- [
- "Note: The following removal may look somewhat obscure and needs an explanation. When we mutate the class hierarchy we create new classes for any existing subclass. So it may look as if we don't have to remove the old class from its superclass. However, at the top of the hierarchy (the first class we reshape) that superclass itself is not newly created so therefore it will hold both the oldClass and newClass in its (obsolete or not) subclasses. Since the #become: below will transparently replace the pointers to oldClass with newClass the superclass would have newClass in its subclasses TWICE. With rather unclear effects if we consider that we may convert the meta-class hierarchy itself (which is derived from the non-meta class hierarchy).
- Due to this problem ALL classes are removed from their superclass just prior to converting them. Here, breaking the superclass/subclass invariant really doesn't matter since we will effectively remove the oldClass (become+GC) just a few lines below."
oldClass superclass removeSubclass: oldClass.
oldClass superclass removeObsoleteSubclass: oldClass.
"make sure that the VM cache is clean"
oldClass methodDict do: [:cm | cm flushCache].
"Convert the instances of oldClass into instances of newClass"
newClass updateInstancesFrom: oldClass.
meta
ifTrue:
[oldClass becomeForward: newClass.
oldClass updateMethodBindingsTo: oldClass binding]
ifFalse:
[{oldClass. oldClass class} elementsForwardIdentityTo: {newClass. newClass class}.
oldClass updateMethodBindingsTo: oldClass binding.
oldClass class updateMethodBindingsTo: oldClass class binding].
+ "eem 5/31/2014 07:22 At this point there used to be a garbage collect whose purpose was
+ to ensure no old instances existed after the becomeForward:. Without the GC it was possible
+ to resurrect old instances using e.g. allInstancesDo:. This was because the becomeForward:
+ updated references from the old objects to new objects but didn't destroy the old objects.
+ But as of late 2013/early 2014 becomeForward: has been modified to free all the old objects."]
+ valueUnpreemptively!
- Smalltalk garbageCollect.
-
- "Warning: Read this before you even think about removing the GC. Yes, it slows us down. Quite heavily if you have a large image. However, there's no good and simple alternative here, since unfortunately, #become: does change class pointers. What happens is that after the above become all of the instances of the old class will have a class pointer identifying them as instances of newClass. If we get our hands on any of these instances we will break immediately since their expected instance layout (that of its class, e.g., newClass) will not match their actual instance layout (that of oldClass). And getting your hands on any of those instances is really simple - just reshaping one class two times in rapid succession will do it. Reflection techniques, interrupts, etc. will only add to this problem. In the case of Metaclass things get even worse since when we recompile the entire class hierarchy we will recompile both, Metaclass and its instances (and some of its instances will have the old and some the new layout).
-
- The only easy solution to this problem would be to 'fix up' the class pointers of the old instances to point to the old class (using primitiveChangeClassTo:). But this won't work either - as we do a one-way become we would have to search the entire object memory for the oldClass and couldn't even clearly identify it unless we give it some 'special token' which sounds quite error-prone. If you really need to get rid of the GC here are some alternatives:
-
- On the image level, one could create a copy of the oldClass before becoming it into the new class and, after becoming it, 'fix up' the old instances. That would certainly work but it sounds quite complex, as we need to make sure we're not breaking any of the superclass/subclass meta/non-meta class variants.
-
- Alternatively, fix up #becomeForward on the VM-level to 'dump the source objects' of #become. This would be quite doable (just 'convert' them into a well known special class such as bitmap) yet it has problems if (accidentally or not) one of the objects in #become: appears on 'both sides of the fence' (right now, this will work ... in a way ... even though the consequences are unclear).
-
- Another alternative is to provide a dedicated primitive for this (instead of using it implicitly in become) which would allow us to dump all the existing instances right here. This is equivalent to a more general primitiveChangeClassTo: and might be worthwhile but it would likely have to keep in mind the differences between bits and pointer thingies etc.
-
- Since all of the alternatives seem rather complex and magical compared to a straight-forward GC it seems best to stick with the GC solution for now. If someone has a real need to fix this problem, that person will likely be motivated enough to check out the alternatives. Personally I'd probably go for #1 (copy the old class and remap the instances to it) since it's a solution that could be easily reverted from within the image if there's any problem with it."
-
- ] valueUnpreemptively.
- !
Item was added:
+ ----- Method: MethodContext>>allInstances (in category 'as yet unclassified') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since this context has been created only to
+ compute the existing instances."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ insts nextPut: inst.
+ inst := next].
+ ^insts contents!
Item was added:
+ ----- Method: MethodContext>>allInstancesDo: (in category 'as yet unclassified') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since evaluation of aBlock will create new contexts."
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
Item was changed:
----- Method: ProtoObject>>scaledIdentityHash (in category 'comparing') -----
scaledIdentityHash
"For identityHash values returned by primitive 75, answer
+ such values times 2^8. Otherwise, match the existing
+ identityHash implementation"
- such values times 2^18. Otherwise, match the existing
- identityHash implementation"
+ ^self identityHash * 256 "bitShift: 8"!
- ^self identityHash * 262144 "bitShift: 18"!
Item was changed:
==== ERROR ===
Error: Unrecognized class type
27 June 2014 1:05:23.414 am
VM: unix - a SmalltalkImage
Image: Squeak3.11alpha [latest update: #8824]
SecurityManager state:
Restricted: false
FileAccess: true
SocketAccess: true
Working Dir /home/squeaksource
Trusted Dir /home/squeaksource/secure
Untrusted Dir /home/squeaksource/My Squeak
MCClassDefinition(Object)>>error:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
aString: 'Unrecognized class type'
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>kindOfSubclass
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>printDefinitionOn:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
stream: a WriteStream
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
Receiver: a MCDiffyTextWriter
Arguments and temporary variables:
definition: a WriteStream
s: a MCClassDefinition(SmallInteger)
Receiver's instance variables:
stream: a WriteStream
initStream: nil
--- The full stack ---
MCClassDefinition(Object)>>error:
MCClassDefinition>>kindOfSubclass
MCClassDefinition>>printDefinitionOn:
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>chunkContents:
MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
MCDiffyTextWriter(MCStWriter)>>visitClassDefinition:
MCClassDefinition>>accept:
[] in MCDiffyTextWriter(MCTextWriter)>>visitInFork:
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>visitInFork:
MCDiffyTextWriter>>writePatchFrom:to:
MCDiffyTextWriter>>writeModification:
[] in MCDiffyTextWriter>>writePatch:
SortedCollection(OrderedCollection)>>do:
MCDiffyTextWriter>>writePatch:
SSDiffyTextWriter>>writePatch:
[] in SSDiffyTextWriter>>writeVersion:for:
BlockClosure>>on:do:
SSDiffyTextWriter>>writeVersion:for:
[] in SSEMailSubscription>>versionAdded:to:
BlockClosure>>on:do:
SSEMailSubscription>>versionAdded:to:
[] in [] in SSProject>>versionAdded:
[] in BlockClosure>>newProcess
I'd like "More About Squeak..." to open a SystemReporter. Any objections?
Any votes for replacing the 'About Squeak...' pop-up with the
SystemReporter (my preference)?
--
best,
Eliot
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel.spur-nice.853.mcz
==================== Summary ====================
Name: Kernel.spur-nice.853
Author: eem
Time: 26 June 2014, 5:28:29.561 pm
UUID: 54c52ce5-114b-45b5-b444-95f9c08d1413
Ancestors: Kernel-nice.853
Kernel-nice.853 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
Introduce an isAnExactFloat test, which is true when a Number can be converted as Float exactly.
Use this to boost some mixed arithmetic comparisons by avoidance of Float>>asTrueFraction in more cases.
Use this to make Fraction>>hash more explicit.
While at it, improve a bit the Fraction>>hash in inexact case (previous naive bitXor: causes too many collisions)
Since some hash has been modified, rehashAll in postscript.
=============== Diff against Kernel-nice.853 ===============
Item was changed:
----- Method: Behavior>>allInstances (in category 'accessing instances and variables') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ (inst == insts or: [inst == insts originalContents]) ifFalse: [insts nextPut: inst].
+ inst := next].
+ ^insts contents!
- allInstances
- "Answer a collection of all current instances of the receiver."
-
- | all |
- all := OrderedCollection new.
- self allInstancesDo: [:x | x == all ifFalse: [all add: x]].
- ^ all asArray
- !
Item was changed:
----- Method: Behavior>>allInstancesDo: (in category 'enumerating') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst."
- allInstancesDo: aBlock
- "Evaluate the argument, aBlock, for each of the current instances of the
- receiver.
-
- Because aBlock might change the class of inst (for example, using become:),
- it is essential to compute next before aBlock value: inst."
- | inst next |
inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
- [inst == nil]
- whileFalse:
- [
- next := inst nextInstance.
- aBlock value: inst.
- inst := next]!
Item was added:
+ ----- Method: Behavior>>allInstancesOrNil (in category 'as yet unclassified') -----
+ allInstancesOrNil
+ "Answer all instances of the receiver, or nil if the primitive
+ fails, which it may be due to being out of memory."
+ <primitive: 177>
+ ^nil!
Item was changed:
----- Method: Behavior>>basicNew (in category 'instance creation') -----
basicNew
"Primitive. Answer an instance of the receiver (which is a class) with no
+ indexable variables. Fail if the class is indexable. Essential. See Object
+ documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger
+ will run before the method is activated. Check arguments and
+ retry via handleFailingBasicNew if they're OK."
- indexable variables. Fail if the class is indexable. Essential. See Object
- documentation whatIsAPrimitive."
<primitive: 70>
+ self isVariable ifTrue: [^self basicNew: 0].
+ "space must have been low, and the scavenger must have run.
+ retry after the scavenge."
+ ^self handleFailingBasicNew!
- self isVariable ifTrue: [ ^ self basicNew: 0 ].
- "space must be low"
- OutOfMemory signal.
- ^ self basicNew "retry if user proceeds"
- !
Item was changed:
----- Method: Behavior>>basicNew: (in category 'instance creation') -----
basicNew: sizeRequested
+ "Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger will run before the
+ method is activated. Check args and retry via handleFailingBasicNew: if they're OK."
- "Primitive. Answer an instance of this class with the number
- of indexable variables specified by the argument, sizeRequested.
- Fail if this class is not indexable or if the argument is not a
- positive Integer, or if there is not enough memory available.
- Essential. See Object documentation whatIsAPrimitive."
<primitive: 71>
self isVariable ifFalse:
[self error: self printString, ' cannot have variable sized instances'].
(sizeRequested isInteger and: [sizeRequested >= 0]) ifTrue:
+ ["arg okay; space must have been low, and the scavenger must have run.
+ retry after the scavenge"
+ ^self handleFailingBasicNew: sizeRequested].
- ["arg okay; space must be low."
- OutOfMemory signal.
- ^ self basicNew: sizeRequested "retry if user proceeds"].
self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstance (in category 'as yet unclassified') -----
+ byteSizeOfInstance
+ "Answer the total memory size of an instance of the receiver."
+
+ <primitive: 181>
+ self isVariable ifTrue:
+ [^self byteSizeOfInstanceOfSize: 0].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstanceOfSize: (in category 'as yet unclassified') -----
+ byteSizeOfInstanceOfSize: basicSize
+ "Answer the total memory size of an instance of the receiver
+ with the given number of indexable instance variables."
+
+ <primitive: 181>
+ self isVariable ifFalse:
+ [basicSize = 0 ifTrue:
+ [^self byteSizeOfInstance]].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>elementSize (in category 'as yet unclassified') -----
+ elementSize
+ "Answer the size in bytes of an element in the receiver. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ instSpec < 9 ifTrue: [^Smalltalk wordSize].
+ instSpec >= 16 ifTrue: [^1].
+ instSpec >= 12 ifTrue: [^2].
+ instSpec >= 10 ifTrue: [^4].
+ ^8!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingBasicNew
+ "handleFailingBasicNew gets sent after basicNew has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew. If
+ handleFailingBasicNew fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ Smalltalk garbageCollect < 1048576 ifTrue:
+ [Smalltalk growMemoryByAtLeast: 1048576].
+ ^self handleFailingFailingBasicNew "retry after global garbage collect"!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingBasicNew: sizeRequested
+ "handleFailingBasicNew: gets sent after basicNew: has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew:. If
+ handleFailingBasicNew: fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ | bytesRequested |
+ bytesRequested := self byteSizeOfInstanceOfSize: sizeRequested.
+ Smalltalk garbageCollect < bytesRequested ifTrue:
+ [Smalltalk growMemoryByAtLeast: bytesRequested].
+ "retry after global garbage collect and possible grow"
+ ^self handleFailingFailingBasicNew: sizeRequested!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew
+ "This basicNew gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ "space must be low"
+ OutOfMemory signal.
+ ^self basicNew "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew: sizeRequested
+ "This basicNew: gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew: fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ "space must be low."
+ OutOfMemory signal.
+ ^self basicNew: sizeRequested "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>identityHash (in category 'as yet unclassified') -----
+ identityHash
+ "Answer a SmallInteger whose value is related to the receiver's identity.
+ Behavior implements identityHash to allow the VM to use an object representation which
+ does not include a direct reference to an object's class in an object. If the VM is using
+ this implementation then classes are held in a class table and instances contain the index
+ of their class in the table. A class's class table index is its identityHash so that an instance
+ can be created without searching the table for a class's index. The VM uses this primitive
+ to enter the class into the class table, assigning its identityHash with an as yet unused
+ class table index. If this primitive fails it means that the class table is full. In Spur as of
+ 2014 there are 22 bits of classTable index and 22 bits of identityHash per object.
+
+ Primitive. Essential. Do not override. See Object documentation whatIsAPrimitive."
+
+ <primitive: 175>
+ self primitiveFailed!
Item was changed:
----- Method: Behavior>>instSize (in category 'testing') -----
instSize
"Answer the number of named instance variables
+ (as opposed to indexed variables) of the receiver.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>"
+ ^format bitAnd: 16rFFFF!
- (as opposed to indexed variables) of the receiver."
-
- self flag: #instSizeChange. "Smalltalk browseAllCallsOn: #instSizeChange"
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- When we revise the image format, it should become...
- ^ ((format bitShift: -1) bitAnd: 16rFF) - 1
- Note also that every other method in this category will require
- 2 bits more of right shift after the change.
- "
- ^ ((format bitShift: -10) bitAnd: 16rC0) + ((format bitShift: -1) bitAnd: 16r3F) - 1!
Item was changed:
----- Method: Behavior>>instSpec (in category 'testing') -----
instSpec
+ "Answer the instance specification part of the format that defines what kind of object
+ an instance of the receiver is. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^(format bitShift: -16) bitAnd: 16r1F!
- ^ (format bitShift: -7) bitAnd: 16rF!
Item was changed:
----- Method: Behavior>>isBits (in category 'testing') -----
isBits
+ "Answer whether the receiver contains just bits (not pointers).
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 7!
- "Answer whether the receiver contains just bits (not pointers)."
-
- ^ self instSpec >= 6!
Item was changed:
----- Method: Behavior>>isBytes (in category 'testing') -----
isBytes
+ "Answer whether the receiver has 8-bit instance variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 16!
- "Answer whether the receiver has 8-bit instance variables."
-
- ^ self instSpec >= 8!
Item was added:
+ ----- Method: Behavior>>isEphemeronClass (in category 'as yet unclassified') -----
+ isEphemeronClass
+ "Answer whether the receiver has ephemeral instance variables. The garbage collector will
+ fire (queue for finalization) any ephemeron whose first instance variable is not referenced
+ other than from the transitive closure of references from ephemerons. Hence referring to
+ an object from the first inst var of an ephemeron will cause the ephemeron to fire when
+ the rest of the system does not refer to the object and that object is ready to be collected.
+ Since references from the remaining inst vars of an ephemeron will not prevent the ephemeron
+ from firing, ephemerons may act as the associations in weak dictionaries such that the value
+ (e.g. properties attached to the key) will not prevent firing when the key is no longer referenced
+ other than from ephemerons. Ephemerons can therefore be used to implement instance-based
+ pre-mortem finalization."
+ ^self instSpec = 5!
Item was added:
+ ----- Method: Behavior>>isImmediateClass (in category 'as yet unclassified') -----
+ isImmediateClass
+ "Answer whether the receiver has immediate instances. Immediate instances
+ store their value in their object pointer, not in an object body. Hence immediates
+ take no space and are immutable. The immediates are distinguished by tag bits
+ in the pointer. They include SmallIntegers and Characters. Hence in the 32-bit
+ system SmallIntegers are 31-bit signed integers and Characters are 30-bit
+ unsigned character codes."
+ ^self instSpec = 7!
Item was changed:
----- Method: Behavior>>isVariable (in category 'testing') -----
isVariable
+ "Answer whether the receiver has indexable variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ ^instSpec >= 2 and: [instSpec <= 4 or: [instSpec >= 9]]!
- "Answer whether the receiver has indexable variables."
-
- ^ self instSpec >= 2!
Item was changed:
----- Method: Behavior>>kindOfSubclass (in category 'testing class hierarchy') -----
kindOfSubclass
+ "Answer a String that is the keyword that describes the receiver's kind of subclass,
+ either a regular subclass, a variableSubclass, a variableByteSubclass,
+ a variableWordSubclass, a weakSubclass, an ephemeronSubclass or an immediateSubclass.
+ c.f. typeOfClass"
+ ^self isVariable
+ ifTrue:
+ [self isBits
+ ifTrue:
+ [self isBytes
+ ifTrue: [' variableByteSubclass: ']
+ ifFalse: [' variableWordSubclass: ']]
+ ifFalse:
+ [self isWeak
+ ifTrue: [' weakSubclass: ']
+ ifFalse: [' variableSubclass: ']]]
+ ifFalse:
+ [self isImmediateClass
+ ifTrue: [' immediateSubclass: ']
+ ifFalse:
+ [self isEphemeronClass
+ ifTrue: [' ephemeronSubclass: ']
+ ifFalse: [' subclass: ']]]!
- "Answer a String that is the keyword that describes the receiver's kind
- of subclass, either a regular subclass, a variableSubclass, a
- variableByteSubclass, a variableWordSubclass, or a weakSubclass."
- self isWeak
- ifTrue: [^ ' weakSubclass: '].
- ^ self isVariable
- ifTrue: [self isBits
- ifTrue: [self isBytes
- ifTrue: [ ' variableByteSubclass: ']
- ifFalse: [ ' variableWordSubclass: ']]
- ifFalse: [ ' variableSubclass: ']]
- ifFalse: [ ' subclass: ']!
Item was changed:
----- Method: Behavior>>shouldNotBeRedefined (in category 'testing') -----
shouldNotBeRedefined
+ "Answer if the receiver should not be redefined.
+ The assumption is that classes in Smalltalk specialObjects and
+ instance-specific Behaviors should not be redefined"
- "Return true if the receiver should not be redefined.
- The assumption is that compact classes,
- classes in Smalltalk specialObjects and
- Behaviors should not be redefined"
+ ^(Smalltalk specialObjectsArray
+ identityIndexOf: self
+ ifAbsent: [(self isKindOf: self) ifTrue: [1] ifFalse: [0]]) ~= 0!
- ^(Smalltalk compactClassesArray includes: self)
- or:[(Smalltalk specialObjectsArray includes: self)
- or:[self isKindOf: self]]!
Item was changed:
----- Method: Behavior>>typeOfClass (in category 'accessing') -----
typeOfClass
+ "Answer a symbol uniquely describing the type of the receiver. c.f. kindOfSubclass"
+ self isBytes ifTrue:
+ [^self instSpec = CompiledMethod instSpec
+ ifTrue: [#compiledMethod] "Very special!!"
+ ifFalse: [#bytes]].
+ (self isWords and: [self isPointers not]) ifTrue:
+ [^self instSpec = SmallInteger instSpec
+ ifTrue: [#immediate] "Very special!!"
+ ifFalse: [#words]].
+ self isWeak ifTrue: [^#weak].
+ self isVariable ifTrue: [^#variable].
+ self isEphemeronClass ifTrue: [^#ephemeron].
+ ^#normal!
- "Answer a symbol uniquely describing the type of the receiver"
- self instSpec = CompiledMethod instSpec ifTrue:[^#compiledMethod]. "Very special!!"
- self isBytes ifTrue:[^#bytes].
- (self isWords and:[self isPointers not]) ifTrue:[^#words].
- self isWeak ifTrue:[^#weak].
- self isVariable ifTrue:[^#variable].
- ^#normal.!
Item was added:
+ ----- Method: Class>>immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ immediateSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a new
+ immediate class as a subclass of an existing class (the receiver)."
+ ^ClassBuilder new
+ superclass: self
+ immediateSubclass: t
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>computeFormat:instSize:forSuper:ccIndex: (in category 'class format') -----
computeFormat: type instSize: newInstSize forSuper: newSuper ccIndex: ccIndex
"Compute the new format for making oldClass a subclass of newSuper.
+ Answer the format or nil if there is any problem."
- Return the format or nil if there is any problem."
| instSize isVar isWords isPointers isWeak |
type == #compiledMethod ifTrue:
+ [newInstSize > 0 ifTrue:
+ [self error: 'A compiled method class cannot have named instance variables'.
+ ^nil].
+ ^CompiledMethod format].
- [^(CompiledMethod format
- bitClear: (16r1F bitShift: 11))
- bitOr: (ccIndex bitShift: 11)].
instSize := newInstSize + (newSuper ifNil:[0] ifNotNil:[newSuper instSize]).
+ instSize > 65535 ifTrue:
- instSize > 254 ifTrue:
[self error: 'Class has too many instance variables (', instSize printString,')'.
^nil].
type == #normal ifTrue:[isVar := isWeak := false. isWords := isPointers := true].
type == #bytes ifTrue:[isVar := true. isWords := isPointers := isWeak := false].
type == #words ifTrue:[isVar := isWords := true. isPointers := isWeak := false].
type == #variable ifTrue:[isVar := isPointers := isWords := true. isWeak := false].
type == #weak ifTrue:[isVar := isWeak := isWords := isPointers := true].
+ type == #ephemeron ifTrue:[isVar := false. isWeak := isWords := isPointers := true].
+ type == #immediate ifTrue:[isVar := isWeak := isPointers := false. isWords := true].
+ (isPointers not and: [instSize > 0]) ifTrue:
+ [self error: 'A non-pointer class cannot have named instance variables'.
- (isPointers not and:[instSize > 0]) ifTrue:
- [self error:'A non-pointer class cannot have instance variables'.
^nil].
+ ^self format: instSize variable: isVar words: isWords pointers: isPointers weak: isWeak!
- ^(self format: instSize
- variable: isVar
- words: isWords
- pointers: isPointers
- weak: isWeak) + (ccIndex bitShift: 11).!
Item was changed:
----- Method: ClassBuilder>>format:variable:words:pointers:weak: (in category 'class format') -----
format: nInstVars variable: isVar words: isWords pointers: isPointers weak: isWeak
+ "Compute the format for the given instance specfication.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = reserved for 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
- "Compute the format for the given instance specfication."
- | cClass instSpec sizeHiBits fmt |
- self flag: #instSizeChange.
- "
- Smalltalk browseAllCallsOn: #instSizeChange.
- Smalltalk browseAllImplementorsOf: #fixedFieldsOf:.
- Smalltalk browseAllImplementorsOf: #instantiateClass:indexableSize:.
- "
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- For now the format word is...
- <2 bits=instSize//64><5 bits=cClass><4 bits=instSpec><6 bits=instSize\\64><1 bit=0>
- But when we revise the image format, it should become...
- <5 bits=cClass><4 bits=instSpec><8 bits=instSize><1 bit=0>
- "
- sizeHiBits := (nInstVars+1) // 64.
- cClass := 0. "for now"
instSpec := isWeak
+ ifTrue:
+ [isVar
+ ifTrue: [4]
+ ifFalse: [5]]
+ ifFalse:
+ [isPointers
+ ifTrue:
+ [isVar
+ ifTrue: [nInstVars > 0 ifTrue: [3] ifFalse: [2]]
+ ifFalse: [nInstVars > 0 ifTrue: [1] ifFalse: [0]]]
+ ifFalse:
+ [isVar
+ ifTrue: [isWords ifTrue: [12] ifFalse: [16]]
+ ifFalse: [7]]].
+ ^(instSpec bitShift: 16) + nInstVars!
- ifTrue:[4]
- ifFalse:[isPointers
- ifTrue: [isVar
- ifTrue: [nInstVars>0 ifTrue: [3] ifFalse: [2]]
- ifFalse: [nInstVars>0 ifTrue: [1] ifFalse: [0]]]
- ifFalse: [isWords ifTrue: [6] ifFalse: [8]]].
- fmt := sizeHiBits.
- fmt := (fmt bitShift: 5) + cClass.
- fmt := (fmt bitShift: 4) + instSpec.
- fmt := (fmt bitShift: 6) + ((nInstVars+1)\\64). "+1 since prim size field includes header"
- fmt := (fmt bitShift: 1). "This shift plus integer bit lets wordSize work like byteSize"
- ^fmt!
Item was added:
+ ----- Method: ClassBuilder>>superclass:immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ superclass: aClass
+ immediateSubclass: t instanceVariableNames: f
+ classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a
+ new immediate class as a subclass of an existing class."
+ | env |
+ aClass instSize > 0
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with named fields'].
+ aClass isVariable
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with indexed instance variables'].
+ aClass isPointers
+ ifFalse: [^self error: 'cannot make an immediate subclass of a class without pointer fields'].
+ "Cope with pre-environment and environment versions. Simplify asap."
+ env := (Smalltalk classNamed: #EnvironmentRequest)
+ ifNil: [aClass environment]
+ ifNotNil: [:erc| erc signal ifNil: [aClass environment]].
+ ^self
+ name: t
+ inEnvironment: env
+ subclassOf: aClass
+ type: #immediate
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>update:to: (in category 'class mutation') -----
update: oldClass to: newClass
+ "Convert oldClass, all its instances and possibly its meta class into newClass,
+ instances of newClass and possibly its meta class. The process is surprisingly
+ simple in its implementation and surprisingly complex in its nuances and potentially
+ bad side effects.
+ We can rely on two assumptions (which are critical):
+ #1: The method #updateInstancesFrom: will not create any lasting pointers to
+ 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do
+ a become of the old vs. the new instances and therefore it will not create
+ pointers to *new* instances before the #become: which are *old* afterwards)
+ #2: The non-preemptive execution of the critical piece of code guarantees that
+ nobody can get a hold by 'other means' (such as process interruption and
+ reflection) on the old instances.
+ Given the above two, we know that after #updateInstancesFrom: there are no pointers
+ to any old instances. After the forwarding become there will be no pointers to the old
+ class or meta class either.
+ Andreas Raab, 2/27/2003 23:42"
- "Convert oldClass, all its instances and possibly its meta class into newClass, instances of newClass and possibly its meta class. The process is surprisingly simple in its implementation and surprisingly complex in its nuances and potentially bad side effects.
- We can rely on two assumptions (which are critical):
- #1: The method #updateInstancesFrom: will not create any lasting pointers to 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do a become of the old vs. the new instances and therefore it will not create pointers to *new* instances before the #become: which are *old* afterwards)
- #2: The non-preemptive execution of the critical piece of code guarantees that nobody can get a hold by 'other means' (such as process interruption and reflection) on the old instances.
- Given the above two, we know that after #updateInstancesFrom: there are no pointer to any old instances. After the forwarding become there will be no pointers to the old class or meta class either. Meaning that if we throw in a nice fat GC at the end of the critical block, everything will be gone (but see the comment right there). There's no need to worry.
- "
| meta |
meta := oldClass isMeta.
"Note: Everything from here on will run without the ability to get interrupted
to prevent any other process to create new instances of the old class."
+ ["Note: The following removal may look somewhat obscure and needs an explanation.
+ When we mutate the class hierarchy we create new classes for any existing subclass.
+ So it may look as if we don't have to remove the old class from its superclass. However,
+ at the top of the hierarchy (the first class we reshape) that superclass itself is not newly
+ created so therefore it will hold both the oldClass and newClass in its (obsolete or not)
+ subclasses. Since the #become: below will transparently replace the pointers to oldClass
+ with newClass the superclass would have newClass in its subclasses TWICE. With rather
+ unclear effects if we consider that we may convert the meta-class hierarchy itself (which
+ is derived from the non-meta class hierarchy).
+ Due to this problem ALL classes are removed from their superclass just prior to converting
+ them. Here, breaking the superclass/subclass invariant really doesn't matter since we will
+ effectively remove the oldClass (becomeForward:) just a few lines below."
- [
- "Note: The following removal may look somewhat obscure and needs an explanation. When we mutate the class hierarchy we create new classes for any existing subclass. So it may look as if we don't have to remove the old class from its superclass. However, at the top of the hierarchy (the first class we reshape) that superclass itself is not newly created so therefore it will hold both the oldClass and newClass in its (obsolete or not) subclasses. Since the #become: below will transparently replace the pointers to oldClass with newClass the superclass would have newClass in its subclasses TWICE. With rather unclear effects if we consider that we may convert the meta-class hierarchy itself (which is derived from the non-meta class hierarchy).
- Due to this problem ALL classes are removed from their superclass just prior to converting them. Here, breaking the superclass/subclass invariant really doesn't matter since we will effectively remove the oldClass (become+GC) just a few lines below."
oldClass superclass removeSubclass: oldClass.
oldClass superclass removeObsoleteSubclass: oldClass.
"make sure that the VM cache is clean"
oldClass methodDict do: [:cm | cm flushCache].
"Convert the instances of oldClass into instances of newClass"
newClass updateInstancesFrom: oldClass.
meta
+ ifTrue:
+ [oldClass becomeForward: newClass.
+ oldClass updateMethodBindingsTo: oldClass binding]
+ ifFalse:
+ [{oldClass. oldClass class} elementsForwardIdentityTo: {newClass. newClass class}.
+ oldClass updateMethodBindingsTo: oldClass binding.
+ oldClass class updateMethodBindingsTo: oldClass class binding].
- ifTrue:[oldClass becomeForward: newClass]
- ifFalse:[(Array with: oldClass with: oldClass class)
- elementsForwardIdentityTo:
- (Array with: newClass with: newClass class)].
+ "eem 5/31/2014 07:22 At this point there used to be a garbage collect whose purpose was
+ to ensure no old instances existed after the becomeForward:. Without the GC it was possible
+ to resurrect old instances using e.g. allInstancesDo:. This was because the becomeForward:
+ updated references from the old objects to new objects but didn't destroy the old objects.
+ But as of late 2013/early 2014 becomeForward: has been modified to free all the old objects."]
+ valueUnpreemptively!
- Smalltalk garbageCollect.
-
- "Warning: Read this before you even think about removing the GC. Yes, it slows us down. Quite heavily if you have a large image. However, there's no good and simple alternative here, since unfortunately, #become: does change class pointers. What happens is that after the above become all of the instances of the old class will have a class pointer identifying them as instances of newClass. If we get our hands on any of these instances we will break immediately since their expected instance layout (that of its class, e.g., newClass) will not match their actual instance layout (that of oldClass). And getting your hands on any of those instances is really simple - just reshaping one class two times in rapid succession will do it. Reflection techniques, interrupts, etc. will only add to this problem. In the case of Metaclass things get even worse since when we recompile the entire class hierarchy we will recompile both, Metaclass and its instances (and some of its instances will have the old and some the new layout).
-
- The only easy solution to this problem would be to 'fix up' the class pointers of the old instances to point to the old class (using primitiveChangeClassTo:). But this won't work either - as we do a one-way become we would have to search the entire object memory for the oldClass and couldn't even clearly identify it unless we give it some 'special token' which sounds quite error-prone. If you really need to get rid of the GC here are some alternatives:
-
- On the image level, one could create a copy of the oldClass before becoming it into the new class and, after becoming it, 'fix up' the old instances. That would certainly work but it sounds quite complex, as we need to make sure we're not breaking any of the superclass/subclass meta/non-meta class variants.
-
- Alternatively, fix up #becomeForward on the VM-level to 'dump the source objects' of #become. This would be quite doable (just 'convert' them into a well known special class such as bitmap) yet it has problems if (accidentally or not) one of the objects in #become: appears on 'both sides of the fence' (right now, this will work ... in a way ... even though the consequences are unclear).
-
- Another alternative is to provide a dedicated primitive for this (instead of using it implicitly in become) which would allow us to dump all the existing instances right here. This is equivalent to a more general primitiveChangeClassTo: and might be worthwhile but it would likely have to keep in mind the differences between bits and pointer thingies etc.
-
- Since all of the alternatives seem rather complex and magical compared to a straight-forward GC it seems best to stick with the GC solution for now. If someone has a real need to fix this problem, that person will likely be motivated enough to check out the alternatives. Personally I'd probably go for #1 (copy the old class and remap the instances to it) since it's a solution that could be easily reverted from within the image if there's any problem with it."
-
- ] valueUnpreemptively.
- !
Item was added:
+ ----- Method: ClassDescription>>updateMethodBindingsTo: (in category 'initialize-release') -----
+ updateMethodBindingsTo: aBinding
+ "ClassBuilder support for maintaining valid method bindings."
+ methodDict do: [:method| method methodClassAssociation: aBinding]!
Item was added:
+ ----- Method: MethodContext>>allInstances (in category 'as yet unclassified') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since this context has been created only to
+ compute the existing instances."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ insts nextPut: inst.
+ inst := next].
+ ^insts contents!
Item was added:
+ ----- Method: MethodContext>>allInstancesDo: (in category 'as yet unclassified') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since evaluation of aBlock will create new contexts."
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
Item was changed:
----- Method: ProtoObject>>scaledIdentityHash (in category 'comparing') -----
scaledIdentityHash
"For identityHash values returned by primitive 75, answer
+ such values times 2^8. Otherwise, match the existing
+ identityHash implementation"
- such values times 2^18. Otherwise, match the existing
- identityHash implementation"
+ ^self identityHash * 256 "bitShift: 8"!
- ^self identityHash * 262144 "bitShift: 18"!
Item was changed:
==== ERROR ===
Error: Unrecognized class type
27 June 2014 1:03:33.028 am
VM: unix - a SmalltalkImage
Image: Squeak3.11alpha [latest update: #8824]
SecurityManager state:
Restricted: false
FileAccess: true
SocketAccess: true
Working Dir /home/squeaksource
Trusted Dir /home/squeaksource/secure
Untrusted Dir /home/squeaksource/My Squeak
MCClassDefinition(Object)>>error:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
aString: 'Unrecognized class type'
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: 'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>kindOfSubclass
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: 'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>printDefinitionOn:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
stream: a WriteStream
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: 'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
Receiver: a MCDiffyTextWriter
Arguments and temporary variables:
definition: a WriteStream
s: a MCClassDefinition(SmallInteger)
Receiver's instance variables:
stream: a WriteStream
initStream: nil
--- The full stack ---
MCClassDefinition(Object)>>error:
MCClassDefinition>>kindOfSubclass
MCClassDefinition>>printDefinitionOn:
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>chunkContents:
MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
MCDiffyTextWriter(MCStWriter)>>visitClassDefinition:
MCClassDefinition>>accept:
[] in MCDiffyTextWriter(MCTextWriter)>>visitInFork:
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>visitInFork:
MCDiffyTextWriter>>writePatchFrom:to:
MCDiffyTextWriter>>writeModification:
[] in MCDiffyTextWriter>>writePatch:
SortedCollection(OrderedCollection)>>do:
MCDiffyTextWriter>>writePatch:
SSDiffyTextWriter>>writePatch:
[] in SSDiffyTextWriter>>writeVersion:for:
BlockClosure>>on:do:
SSDiffyTextWriter>>writeVersion:for:
[] in SSEMailSubscription>>versionAdded:to:
BlockClosure>>on:do:
SSEMailSubscription>>versionAdded:to:
[] in [] in SSProject>>versionAdded:
[] in BlockClosure>>newProcess
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel.spur-dtl.856.mcz
==================== Summary ====================
Name: Kernel.spur-dtl.856
Author: eem
Time: 26 June 2014, 5:27:06.154 pm
UUID: 44b0fd94-e359-498c-b58c-e93d6d0dd9fd
Ancestors: Kernel-dtl.856
Kernel-dtl.856 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
Fix inconsistent image state as reported on squeak-dev:
Date: Wed, 11 Jun 2014 23:44:42 -0400
From: Florin Mateoc
To: The general-purpose Squeak developers list
Subject: [squeak-dev] Class subclasses
I think this is an old bug, presumably since ProtoObject was introduced (and presumably because ObjectTracer was used in the process).
If you ask Class for its subclasses (or if you inspect it) you see that ObjectTracer class is listed along with ProtoObject class, although ObjectTracer's superclass is ProtoObject. This can lead to some funny bugs if you try to write some hierarchy traversing code.
=============== Diff against Kernel-dtl.856 ===============
Item was changed:
----- Method: Behavior>>allInstances (in category 'accessing instances and variables') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ (inst == insts or: [inst == insts originalContents]) ifFalse: [insts nextPut: inst].
+ inst := next].
+ ^insts contents!
- allInstances
- "Answer a collection of all current instances of the receiver."
-
- | all |
- all := OrderedCollection new.
- self allInstancesDo: [:x | x == all ifFalse: [all add: x]].
- ^ all asArray
- !
Item was changed:
----- Method: Behavior>>allInstancesDo: (in category 'enumerating') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst."
- allInstancesDo: aBlock
- "Evaluate the argument, aBlock, for each of the current instances of the
- receiver.
-
- Because aBlock might change the class of inst (for example, using become:),
- it is essential to compute next before aBlock value: inst."
- | inst next |
inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
- [inst == nil]
- whileFalse:
- [
- next := inst nextInstance.
- aBlock value: inst.
- inst := next]!
Item was added:
+ ----- Method: Behavior>>allInstancesOrNil (in category 'as yet unclassified') -----
+ allInstancesOrNil
+ "Answer all instances of the receiver, or nil if the primitive
+ fails, which it may be due to being out of memory."
+ <primitive: 177>
+ ^nil!
Item was changed:
----- Method: Behavior>>basicNew (in category 'instance creation') -----
basicNew
"Primitive. Answer an instance of the receiver (which is a class) with no
+ indexable variables. Fail if the class is indexable. Essential. See Object
+ documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger
+ will run before the method is activated. Check arguments and
+ retry via handleFailingBasicNew if they're OK."
- indexable variables. Fail if the class is indexable. Essential. See Object
- documentation whatIsAPrimitive."
<primitive: 70>
+ self isVariable ifTrue: [^self basicNew: 0].
+ "space must have been low, and the scavenger must have run.
+ retry after the scavenge."
+ ^self handleFailingBasicNew!
- self isVariable ifTrue: [ ^ self basicNew: 0 ].
- "space must be low"
- OutOfMemory signal.
- ^ self basicNew "retry if user proceeds"
- !
Item was changed:
----- Method: Behavior>>basicNew: (in category 'instance creation') -----
basicNew: sizeRequested
+ "Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger will run before the
+ method is activated. Check args and retry via handleFailingBasicNew: if they're OK."
- "Primitive. Answer an instance of this class with the number
- of indexable variables specified by the argument, sizeRequested.
- Fail if this class is not indexable or if the argument is not a
- positive Integer, or if there is not enough memory available.
- Essential. See Object documentation whatIsAPrimitive."
<primitive: 71>
self isVariable ifFalse:
[self error: self printString, ' cannot have variable sized instances'].
(sizeRequested isInteger and: [sizeRequested >= 0]) ifTrue:
+ ["arg okay; space must have been low, and the scavenger must have run.
+ retry after the scavenge"
+ ^self handleFailingBasicNew: sizeRequested].
- ["arg okay; space must be low."
- OutOfMemory signal.
- ^ self basicNew: sizeRequested "retry if user proceeds"].
self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstance (in category 'as yet unclassified') -----
+ byteSizeOfInstance
+ "Answer the total memory size of an instance of the receiver."
+
+ <primitive: 181>
+ self isVariable ifTrue:
+ [^self byteSizeOfInstanceOfSize: 0].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstanceOfSize: (in category 'as yet unclassified') -----
+ byteSizeOfInstanceOfSize: basicSize
+ "Answer the total memory size of an instance of the receiver
+ with the given number of indexable instance variables."
+
+ <primitive: 181>
+ self isVariable ifFalse:
+ [basicSize = 0 ifTrue:
+ [^self byteSizeOfInstance]].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>elementSize (in category 'as yet unclassified') -----
+ elementSize
+ "Answer the size in bytes of an element in the receiver. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ instSpec < 9 ifTrue: [^Smalltalk wordSize].
+ instSpec >= 16 ifTrue: [^1].
+ instSpec >= 12 ifTrue: [^2].
+ instSpec >= 10 ifTrue: [^4].
+ ^8!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingBasicNew
+ "handleFailingBasicNew gets sent after basicNew has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew. If
+ handleFailingBasicNew fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ Smalltalk garbageCollect < 1048576 ifTrue:
+ [Smalltalk growMemoryByAtLeast: 1048576].
+ ^self handleFailingFailingBasicNew "retry after global garbage collect"!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingBasicNew: sizeRequested
+ "handleFailingBasicNew: gets sent after basicNew: has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew:. If
+ handleFailingBasicNew: fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ | bytesRequested |
+ bytesRequested := self byteSizeOfInstanceOfSize: sizeRequested.
+ Smalltalk garbageCollect < bytesRequested ifTrue:
+ [Smalltalk growMemoryByAtLeast: bytesRequested].
+ "retry after global garbage collect and possible grow"
+ ^self handleFailingFailingBasicNew: sizeRequested!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew
+ "This basicNew gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ "space must be low"
+ OutOfMemory signal.
+ ^self basicNew "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew: sizeRequested
+ "This basicNew: gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew: fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ "space must be low."
+ OutOfMemory signal.
+ ^self basicNew: sizeRequested "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>identityHash (in category 'as yet unclassified') -----
+ identityHash
+ "Answer a SmallInteger whose value is related to the receiver's identity.
+ Behavior implements identityHash to allow the VM to use an object representation which
+ does not include a direct reference to an object's class in an object. If the VM is using
+ this implementation then classes are held in a class table and instances contain the index
+ of their class in the table. A class's class table index is its identityHash so that an instance
+ can be created without searching the table for a class's index. The VM uses this primitive
+ to enter the class into the class table, assigning its identityHash with an as yet unused
+ class table index. If this primitive fails it means that the class table is full. In Spur as of
+ 2014 there are 22 bits of classTable index and 22 bits of identityHash per object.
+
+ Primitive. Essential. Do not override. See Object documentation whatIsAPrimitive."
+
+ <primitive: 175>
+ self primitiveFailed!
Item was changed:
----- Method: Behavior>>instSize (in category 'testing') -----
instSize
"Answer the number of named instance variables
+ (as opposed to indexed variables) of the receiver.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>"
+ ^format bitAnd: 16rFFFF!
- (as opposed to indexed variables) of the receiver."
-
- self flag: #instSizeChange. "Smalltalk browseAllCallsOn: #instSizeChange"
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- When we revise the image format, it should become...
- ^ ((format bitShift: -1) bitAnd: 16rFF) - 1
- Note also that every other method in this category will require
- 2 bits more of right shift after the change.
- "
- ^ ((format bitShift: -10) bitAnd: 16rC0) + ((format bitShift: -1) bitAnd: 16r3F) - 1!
Item was changed:
----- Method: Behavior>>instSpec (in category 'testing') -----
instSpec
+ "Answer the instance specification part of the format that defines what kind of object
+ an instance of the receiver is. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^(format bitShift: -16) bitAnd: 16r1F!
- ^ (format bitShift: -7) bitAnd: 16rF!
Item was changed:
----- Method: Behavior>>isBits (in category 'testing') -----
isBits
+ "Answer whether the receiver contains just bits (not pointers).
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 7!
- "Answer whether the receiver contains just bits (not pointers)."
-
- ^ self instSpec >= 6!
Item was changed:
----- Method: Behavior>>isBytes (in category 'testing') -----
isBytes
+ "Answer whether the receiver has 8-bit instance variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 16!
- "Answer whether the receiver has 8-bit instance variables."
-
- ^ self instSpec >= 8!
Item was added:
+ ----- Method: Behavior>>isEphemeronClass (in category 'as yet unclassified') -----
+ isEphemeronClass
+ "Answer whether the receiver has ephemeral instance variables. The garbage collector will
+ fire (queue for finalization) any ephemeron whose first instance variable is not referenced
+ other than from the transitive closure of references from ephemerons. Hence referring to
+ an object from the first inst var of an ephemeron will cause the ephemeron to fire when
+ the rest of the system does not refer to the object and that object is ready to be collected.
+ Since references from the remaining inst vars of an ephemeron will not prevent the ephemeron
+ from firing, ephemerons may act as the associations in weak dictionaries such that the value
+ (e.g. properties attached to the key) will not prevent firing when the key is no longer referenced
+ other than from ephemerons. Ephemerons can therefore be used to implement instance-based
+ pre-mortem finalization."
+ ^self instSpec = 5!
Item was added:
+ ----- Method: Behavior>>isImmediateClass (in category 'as yet unclassified') -----
+ isImmediateClass
+ "Answer whether the receiver has immediate instances. Immediate instances
+ store their value in their object pointer, not in an object body. Hence immediates
+ take no space and are immutable. The immediates are distinguished by tag bits
+ in the pointer. They include SmallIntegers and Characters. Hence in the 32-bit
+ system SmallIntegers are 31-bit signed integers and Characters are 30-bit
+ unsigned character codes."
+ ^self instSpec = 7!
Item was changed:
----- Method: Behavior>>isVariable (in category 'testing') -----
isVariable
+ "Answer whether the receiver has indexable variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ ^instSpec >= 2 and: [instSpec <= 4 or: [instSpec >= 9]]!
- "Answer whether the receiver has indexable variables."
-
- ^ self instSpec >= 2!
Item was changed:
----- Method: Behavior>>kindOfSubclass (in category 'testing class hierarchy') -----
kindOfSubclass
+ "Answer a String that is the keyword that describes the receiver's kind of subclass,
+ either a regular subclass, a variableSubclass, a variableByteSubclass,
+ a variableWordSubclass, a weakSubclass, an ephemeronSubclass or an immediateSubclass.
+ c.f. typeOfClass"
+ ^self isVariable
+ ifTrue:
+ [self isBits
+ ifTrue:
+ [self isBytes
+ ifTrue: [' variableByteSubclass: ']
+ ifFalse: [' variableWordSubclass: ']]
+ ifFalse:
+ [self isWeak
+ ifTrue: [' weakSubclass: ']
+ ifFalse: [' variableSubclass: ']]]
+ ifFalse:
+ [self isImmediateClass
+ ifTrue: [' immediateSubclass: ']
+ ifFalse:
+ [self isEphemeronClass
+ ifTrue: [' ephemeronSubclass: ']
+ ifFalse: [' subclass: ']]]!
- "Answer a String that is the keyword that describes the receiver's kind
- of subclass, either a regular subclass, a variableSubclass, a
- variableByteSubclass, a variableWordSubclass, or a weakSubclass."
- self isWeak
- ifTrue: [^ ' weakSubclass: '].
- ^ self isVariable
- ifTrue: [self isBits
- ifTrue: [self isBytes
- ifTrue: [ ' variableByteSubclass: ']
- ifFalse: [ ' variableWordSubclass: ']]
- ifFalse: [ ' variableSubclass: ']]
- ifFalse: [ ' subclass: ']!
Item was changed:
----- Method: Behavior>>shouldNotBeRedefined (in category 'testing') -----
shouldNotBeRedefined
+ "Answer if the receiver should not be redefined.
+ The assumption is that classes in Smalltalk specialObjects and
+ instance-specific Behaviors should not be redefined"
- "Return true if the receiver should not be redefined.
- The assumption is that compact classes,
- classes in Smalltalk specialObjects and
- Behaviors should not be redefined"
+ ^(Smalltalk specialObjectsArray
+ identityIndexOf: self
+ ifAbsent: [(self isKindOf: self) ifTrue: [1] ifFalse: [0]]) ~= 0!
- ^(Smalltalk compactClassesArray includes: self)
- or:[(Smalltalk specialObjectsArray includes: self)
- or:[self isKindOf: self]]!
Item was changed:
----- Method: Behavior>>typeOfClass (in category 'accessing') -----
typeOfClass
+ "Answer a symbol uniquely describing the type of the receiver. c.f. kindOfSubclass"
+ self isBytes ifTrue:
+ [^self instSpec = CompiledMethod instSpec
+ ifTrue: [#compiledMethod] "Very special!!"
+ ifFalse: [#bytes]].
+ (self isWords and: [self isPointers not]) ifTrue:
+ [^self instSpec = SmallInteger instSpec
+ ifTrue: [#immediate] "Very special!!"
+ ifFalse: [#words]].
+ self isWeak ifTrue: [^#weak].
+ self isVariable ifTrue: [^#variable].
+ self isEphemeronClass ifTrue: [^#ephemeron].
+ ^#normal!
- "Answer a symbol uniquely describing the type of the receiver"
- self instSpec = CompiledMethod instSpec ifTrue:[^#compiledMethod]. "Very special!!"
- self isBytes ifTrue:[^#bytes].
- (self isWords and:[self isPointers not]) ifTrue:[^#words].
- self isWeak ifTrue:[^#weak].
- self isVariable ifTrue:[^#variable].
- ^#normal.!
Item was added:
+ ----- Method: Class>>immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ immediateSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a new
+ immediate class as a subclass of an existing class (the receiver)."
+ ^ClassBuilder new
+ superclass: self
+ immediateSubclass: t
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>computeFormat:instSize:forSuper:ccIndex: (in category 'class format') -----
computeFormat: type instSize: newInstSize forSuper: newSuper ccIndex: ccIndex
"Compute the new format for making oldClass a subclass of newSuper.
+ Answer the format or nil if there is any problem."
- Return the format or nil if there is any problem."
| instSize isVar isWords isPointers isWeak |
type == #compiledMethod ifTrue:
+ [newInstSize > 0 ifTrue:
+ [self error: 'A compiled method class cannot have named instance variables'.
+ ^nil].
+ ^CompiledMethod format].
- [^(CompiledMethod format
- bitClear: (16r1F bitShift: 11))
- bitOr: (ccIndex bitShift: 11)].
instSize := newInstSize + (newSuper ifNil:[0] ifNotNil:[newSuper instSize]).
+ instSize > 65535 ifTrue:
- instSize > 254 ifTrue:
[self error: 'Class has too many instance variables (', instSize printString,')'.
^nil].
type == #normal ifTrue:[isVar := isWeak := false. isWords := isPointers := true].
type == #bytes ifTrue:[isVar := true. isWords := isPointers := isWeak := false].
type == #words ifTrue:[isVar := isWords := true. isPointers := isWeak := false].
type == #variable ifTrue:[isVar := isPointers := isWords := true. isWeak := false].
type == #weak ifTrue:[isVar := isWeak := isWords := isPointers := true].
+ type == #ephemeron ifTrue:[isVar := false. isWeak := isWords := isPointers := true].
+ type == #immediate ifTrue:[isVar := isWeak := isPointers := false. isWords := true].
+ (isPointers not and: [instSize > 0]) ifTrue:
+ [self error: 'A non-pointer class cannot have named instance variables'.
- (isPointers not and:[instSize > 0]) ifTrue:
- [self error:'A non-pointer class cannot have instance variables'.
^nil].
+ ^self format: instSize variable: isVar words: isWords pointers: isPointers weak: isWeak!
- ^(self format: instSize
- variable: isVar
- words: isWords
- pointers: isPointers
- weak: isWeak) + (ccIndex bitShift: 11).!
Item was changed:
----- Method: ClassBuilder>>format:variable:words:pointers:weak: (in category 'class format') -----
format: nInstVars variable: isVar words: isWords pointers: isPointers weak: isWeak
+ "Compute the format for the given instance specfication.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = reserved for 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
- "Compute the format for the given instance specfication."
- | cClass instSpec sizeHiBits fmt |
- self flag: #instSizeChange.
- "
- Smalltalk browseAllCallsOn: #instSizeChange.
- Smalltalk browseAllImplementorsOf: #fixedFieldsOf:.
- Smalltalk browseAllImplementorsOf: #instantiateClass:indexableSize:.
- "
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- For now the format word is...
- <2 bits=instSize//64><5 bits=cClass><4 bits=instSpec><6 bits=instSize\\64><1 bit=0>
- But when we revise the image format, it should become...
- <5 bits=cClass><4 bits=instSpec><8 bits=instSize><1 bit=0>
- "
- sizeHiBits := (nInstVars+1) // 64.
- cClass := 0. "for now"
instSpec := isWeak
+ ifTrue:
+ [isVar
+ ifTrue: [4]
+ ifFalse: [5]]
+ ifFalse:
+ [isPointers
+ ifTrue:
+ [isVar
+ ifTrue: [nInstVars > 0 ifTrue: [3] ifFalse: [2]]
+ ifFalse: [nInstVars > 0 ifTrue: [1] ifFalse: [0]]]
+ ifFalse:
+ [isVar
+ ifTrue: [isWords ifTrue: [12] ifFalse: [16]]
+ ifFalse: [7]]].
+ ^(instSpec bitShift: 16) + nInstVars!
- ifTrue:[4]
- ifFalse:[isPointers
- ifTrue: [isVar
- ifTrue: [nInstVars>0 ifTrue: [3] ifFalse: [2]]
- ifFalse: [nInstVars>0 ifTrue: [1] ifFalse: [0]]]
- ifFalse: [isWords ifTrue: [6] ifFalse: [8]]].
- fmt := sizeHiBits.
- fmt := (fmt bitShift: 5) + cClass.
- fmt := (fmt bitShift: 4) + instSpec.
- fmt := (fmt bitShift: 6) + ((nInstVars+1)\\64). "+1 since prim size field includes header"
- fmt := (fmt bitShift: 1). "This shift plus integer bit lets wordSize work like byteSize"
- ^fmt!
Item was added:
+ ----- Method: ClassBuilder>>superclass:immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ superclass: aClass
+ immediateSubclass: t instanceVariableNames: f
+ classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a
+ new immediate class as a subclass of an existing class."
+ | env |
+ aClass instSize > 0
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with named fields'].
+ aClass isVariable
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with indexed instance variables'].
+ aClass isPointers
+ ifFalse: [^self error: 'cannot make an immediate subclass of a class without pointer fields'].
+ "Cope with pre-environment and environment versions. Simplify asap."
+ env := (Smalltalk classNamed: #EnvironmentRequest)
+ ifNil: [aClass environment]
+ ifNotNil: [:erc| erc signal ifNil: [aClass environment]].
+ ^self
+ name: t
+ inEnvironment: env
+ subclassOf: aClass
+ type: #immediate
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>update:to: (in category 'class mutation') -----
update: oldClass to: newClass
+ "Convert oldClass, all its instances and possibly its meta class into newClass,
+ instances of newClass and possibly its meta class. The process is surprisingly
+ simple in its implementation and surprisingly complex in its nuances and potentially
+ bad side effects.
+ We can rely on two assumptions (which are critical):
+ #1: The method #updateInstancesFrom: will not create any lasting pointers to
+ 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do
+ a become of the old vs. the new instances and therefore it will not create
+ pointers to *new* instances before the #become: which are *old* afterwards)
+ #2: The non-preemptive execution of the critical piece of code guarantees that
+ nobody can get a hold by 'other means' (such as process interruption and
+ reflection) on the old instances.
+ Given the above two, we know that after #updateInstancesFrom: there are no pointers
+ to any old instances. After the forwarding become there will be no pointers to the old
+ class or meta class either.
+ Andreas Raab, 2/27/2003 23:42"
- "Convert oldClass, all its instances and possibly its meta class into newClass, instances of newClass and possibly its meta class. The process is surprisingly simple in its implementation and surprisingly complex in its nuances and potentially bad side effects.
- We can rely on two assumptions (which are critical):
- #1: The method #updateInstancesFrom: will not create any lasting pointers to 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do a become of the old vs. the new instances and therefore it will not create pointers to *new* instances before the #become: which are *old* afterwards)
- #2: The non-preemptive execution of the critical piece of code guarantees that nobody can get a hold by 'other means' (such as process interruption and reflection) on the old instances.
- Given the above two, we know that after #updateInstancesFrom: there are no pointer to any old instances. After the forwarding become there will be no pointers to the old class or meta class either. Meaning that if we throw in a nice fat GC at the end of the critical block, everything will be gone (but see the comment right there). There's no need to worry.
- "
| meta |
meta := oldClass isMeta.
"Note: Everything from here on will run without the ability to get interrupted
to prevent any other process to create new instances of the old class."
+ ["Note: The following removal may look somewhat obscure and needs an explanation.
+ When we mutate the class hierarchy we create new classes for any existing subclass.
+ So it may look as if we don't have to remove the old class from its superclass. However,
+ at the top of the hierarchy (the first class we reshape) that superclass itself is not newly
+ created so therefore it will hold both the oldClass and newClass in its (obsolete or not)
+ subclasses. Since the #become: below will transparently replace the pointers to oldClass
+ with newClass the superclass would have newClass in its subclasses TWICE. With rather
+ unclear effects if we consider that we may convert the meta-class hierarchy itself (which
+ is derived from the non-meta class hierarchy).
+ Due to this problem ALL classes are removed from their superclass just prior to converting
+ them. Here, breaking the superclass/subclass invariant really doesn't matter since we will
+ effectively remove the oldClass (becomeForward:) just a few lines below."
- [
- "Note: The following removal may look somewhat obscure and needs an explanation. When we mutate the class hierarchy we create new classes for any existing subclass. So it may look as if we don't have to remove the old class from its superclass. However, at the top of the hierarchy (the first class we reshape) that superclass itself is not newly created so therefore it will hold both the oldClass and newClass in its (obsolete or not) subclasses. Since the #become: below will transparently replace the pointers to oldClass with newClass the superclass would have newClass in its subclasses TWICE. With rather unclear effects if we consider that we may convert the meta-class hierarchy itself (which is derived from the non-meta class hierarchy).
- Due to this problem ALL classes are removed from their superclass just prior to converting them. Here, breaking the superclass/subclass invariant really doesn't matter since we will effectively remove the oldClass (become+GC) just a few lines below."
oldClass superclass removeSubclass: oldClass.
oldClass superclass removeObsoleteSubclass: oldClass.
"make sure that the VM cache is clean"
oldClass methodDict do: [:cm | cm flushCache].
"Convert the instances of oldClass into instances of newClass"
newClass updateInstancesFrom: oldClass.
meta
ifTrue:
[oldClass becomeForward: newClass.
oldClass updateMethodBindingsTo: oldClass binding]
ifFalse:
[{oldClass. oldClass class} elementsForwardIdentityTo: {newClass. newClass class}.
oldClass updateMethodBindingsTo: oldClass binding.
oldClass class updateMethodBindingsTo: oldClass class binding].
+ "eem 5/31/2014 07:22 At this point there used to be a garbage collect whose purpose was
+ to ensure no old instances existed after the becomeForward:. Without the GC it was possible
+ to resurrect old instances using e.g. allInstancesDo:. This was because the becomeForward:
+ updated references from the old objects to new objects but didn't destroy the old objects.
+ But as of late 2013/early 2014 becomeForward: has been modified to free all the old objects."]
+ valueUnpreemptively!
- Smalltalk garbageCollect.
-
- "Warning: Read this before you even think about removing the GC. Yes, it slows us down. Quite heavily if you have a large image. However, there's no good and simple alternative here, since unfortunately, #become: does change class pointers. What happens is that after the above become all of the instances of the old class will have a class pointer identifying them as instances of newClass. If we get our hands on any of these instances we will break immediately since their expected instance layout (that of its class, e.g., newClass) will not match their actual instance layout (that of oldClass). And getting your hands on any of those instances is really simple - just reshaping one class two times in rapid succession will do it. Reflection techniques, interrupts, etc. will only add to this problem. In the case of Metaclass things get even worse since when we recompile the entire class hierarchy we will recompile both, Metaclass and its instances (and some of its instances will have the old and some the new layout).
-
- The only easy solution to this problem would be to 'fix up' the class pointers of the old instances to point to the old class (using primitiveChangeClassTo:). But this won't work either - as we do a one-way become we would have to search the entire object memory for the oldClass and couldn't even clearly identify it unless we give it some 'special token' which sounds quite error-prone. If you really need to get rid of the GC here are some alternatives:
-
- On the image level, one could create a copy of the oldClass before becoming it into the new class and, after becoming it, 'fix up' the old instances. That would certainly work but it sounds quite complex, as we need to make sure we're not breaking any of the superclass/subclass meta/non-meta class variants.
-
- Alternatively, fix up #becomeForward on the VM-level to 'dump the source objects' of #become. This would be quite doable (just 'convert' them into a well known special class such as bitmap) yet it has problems if (accidentally or not) one of the objects in #become: appears on 'both sides of the fence' (right now, this will work ... in a way ... even though the consequences are unclear).
-
- Another alternative is to provide a dedicated primitive for this (instead of using it implicitly in become) which would allow us to dump all the existing instances right here. This is equivalent to a more general primitiveChangeClassTo: and might be worthwhile but it would likely have to keep in mind the differences between bits and pointer thingies etc.
-
- Since all of the alternatives seem rather complex and magical compared to a straight-forward GC it seems best to stick with the GC solution for now. If someone has a real need to fix this problem, that person will likely be motivated enough to check out the alternatives. Personally I'd probably go for #1 (copy the old class and remap the instances to it) since it's a solution that could be easily reverted from within the image if there's any problem with it."
-
- ] valueUnpreemptively.
- !
Item was added:
+ ----- Method: MethodContext>>allInstances (in category 'as yet unclassified') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since this context has been created only to
+ compute the existing instances."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ insts nextPut: inst.
+ inst := next].
+ ^insts contents!
Item was added:
+ ----- Method: MethodContext>>allInstancesDo: (in category 'as yet unclassified') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since evaluation of aBlock will create new contexts."
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
Item was changed:
----- Method: ProtoObject>>scaledIdentityHash (in category 'comparing') -----
scaledIdentityHash
"For identityHash values returned by primitive 75, answer
+ such values times 2^8. Otherwise, match the existing
+ identityHash implementation"
- such values times 2^18. Otherwise, match the existing
- identityHash implementation"
+ ^self identityHash * 256 "bitShift: 8"!
- ^self identityHash * 262144 "bitShift: 18"!
Item was changed:
==== ERROR ===
Error: Unrecognized class type
27 June 2014 1:03:33.519 am
VM: unix - a SmalltalkImage
Image: Squeak3.11alpha [latest update: #8824]
SecurityManager state:
Restricted: false
FileAccess: true
SocketAccess: true
Working Dir /home/squeaksource
Trusted Dir /home/squeaksource/secure
Untrusted Dir /home/squeaksource/My Squeak
MCClassDefinition(Object)>>error:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
aString: 'Unrecognized class type'
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>kindOfSubclass
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>printDefinitionOn:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
stream: a WriteStream
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
Receiver: a MCDiffyTextWriter
Arguments and temporary variables:
definition: a WriteStream
s: a MCClassDefinition(SmallInteger)
Receiver's instance variables:
stream: a WriteStream
initStream: nil
--- The full stack ---
MCClassDefinition(Object)>>error:
MCClassDefinition>>kindOfSubclass
MCClassDefinition>>printDefinitionOn:
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>chunkContents:
MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
MCDiffyTextWriter(MCStWriter)>>visitClassDefinition:
MCClassDefinition>>accept:
[] in MCDiffyTextWriter(MCTextWriter)>>visitInFork:
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>visitInFork:
MCDiffyTextWriter>>writePatchFrom:to:
MCDiffyTextWriter>>writeModification:
[] in MCDiffyTextWriter>>writePatch:
SortedCollection(OrderedCollection)>>do:
MCDiffyTextWriter>>writePatch:
SSDiffyTextWriter>>writePatch:
[] in SSDiffyTextWriter>>writeVersion:for:
BlockClosure>>on:do:
SSDiffyTextWriter>>writeVersion:for:
[] in SSEMailSubscription>>versionAdded:to:
BlockClosure>>on:do:
SSEMailSubscription>>versionAdded:to:
[] in [] in SSProject>>versionAdded:
[] in BlockClosure>>newProcess
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel.spur-cmm.855.mcz
==================== Summary ====================
Name: Kernel.spur-cmm.855
Author: eem
Time: 26 June 2014, 5:26:41.192 pm
UUID: 18461649-5e4b-44dd-9be5-0a5f78b54d76
Ancestors: Kernel-cmm.855
Kernel-cmm.855 patched for Spur by SpurBootstrapMonticelloPackagePatcher Cog-eem.160
- A simple fix for an 8X performance improvement in DateAndTime>>#< as reported by LXTestDateAndTimePerformance.
=============== Diff against Kernel-cmm.855 ===============
Item was changed:
----- Method: Behavior>>allInstances (in category 'accessing instances and variables') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ (inst == insts or: [inst == insts originalContents]) ifFalse: [insts nextPut: inst].
+ inst := next].
+ ^insts contents!
- allInstances
- "Answer a collection of all current instances of the receiver."
-
- | all |
- all := OrderedCollection new.
- self allInstancesDo: [:x | x == all ifFalse: [all add: x]].
- ^ all asArray
- !
Item was changed:
----- Method: Behavior>>allInstancesDo: (in category 'enumerating') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst."
- allInstancesDo: aBlock
- "Evaluate the argument, aBlock, for each of the current instances of the
- receiver.
-
- Because aBlock might change the class of inst (for example, using become:),
- it is essential to compute next before aBlock value: inst."
- | inst next |
inst := self someInstance.
+ [inst == nil] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
- [inst == nil]
- whileFalse:
- [
- next := inst nextInstance.
- aBlock value: inst.
- inst := next]!
Item was added:
+ ----- Method: Behavior>>allInstancesOrNil (in category 'as yet unclassified') -----
+ allInstancesOrNil
+ "Answer all instances of the receiver, or nil if the primitive
+ fails, which it may be due to being out of memory."
+ <primitive: 177>
+ ^nil!
Item was changed:
----- Method: Behavior>>basicNew (in category 'instance creation') -----
basicNew
"Primitive. Answer an instance of the receiver (which is a class) with no
+ indexable variables. Fail if the class is indexable. Essential. See Object
+ documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger
+ will run before the method is activated. Check arguments and
+ retry via handleFailingBasicNew if they're OK."
- indexable variables. Fail if the class is indexable. Essential. See Object
- documentation whatIsAPrimitive."
<primitive: 70>
+ self isVariable ifTrue: [^self basicNew: 0].
+ "space must have been low, and the scavenger must have run.
+ retry after the scavenge."
+ ^self handleFailingBasicNew!
- self isVariable ifTrue: [ ^ self basicNew: 0 ].
- "space must be low"
- OutOfMemory signal.
- ^ self basicNew "retry if user proceeds"
- !
Item was changed:
----- Method: Behavior>>basicNew: (in category 'instance creation') -----
basicNew: sizeRequested
+ "Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive.
+
+ If the primitive fails because space is low then the scavenger will run before the
+ method is activated. Check args and retry via handleFailingBasicNew: if they're OK."
- "Primitive. Answer an instance of this class with the number
- of indexable variables specified by the argument, sizeRequested.
- Fail if this class is not indexable or if the argument is not a
- positive Integer, or if there is not enough memory available.
- Essential. See Object documentation whatIsAPrimitive."
<primitive: 71>
self isVariable ifFalse:
[self error: self printString, ' cannot have variable sized instances'].
(sizeRequested isInteger and: [sizeRequested >= 0]) ifTrue:
+ ["arg okay; space must have been low, and the scavenger must have run.
+ retry after the scavenge"
+ ^self handleFailingBasicNew: sizeRequested].
- ["arg okay; space must be low."
- OutOfMemory signal.
- ^ self basicNew: sizeRequested "retry if user proceeds"].
self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstance (in category 'as yet unclassified') -----
+ byteSizeOfInstance
+ "Answer the total memory size of an instance of the receiver."
+
+ <primitive: 181>
+ self isVariable ifTrue:
+ [^self byteSizeOfInstanceOfSize: 0].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>byteSizeOfInstanceOfSize: (in category 'as yet unclassified') -----
+ byteSizeOfInstanceOfSize: basicSize
+ "Answer the total memory size of an instance of the receiver
+ with the given number of indexable instance variables."
+
+ <primitive: 181>
+ self isVariable ifFalse:
+ [basicSize = 0 ifTrue:
+ [^self byteSizeOfInstance]].
+ self primitiveFailed!
Item was added:
+ ----- Method: Behavior>>elementSize (in category 'as yet unclassified') -----
+ elementSize
+ "Answer the size in bytes of an element in the receiver. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ instSpec < 9 ifTrue: [^Smalltalk wordSize].
+ instSpec >= 16 ifTrue: [^1].
+ instSpec >= 12 ifTrue: [^2].
+ instSpec >= 10 ifTrue: [^4].
+ ^8!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingBasicNew
+ "handleFailingBasicNew gets sent after basicNew has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew. If
+ handleFailingBasicNew fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ Smalltalk garbageCollect < 1048576 ifTrue:
+ [Smalltalk growMemoryByAtLeast: 1048576].
+ ^self handleFailingFailingBasicNew "retry after global garbage collect"!
Item was added:
+ ----- Method: Behavior>>handleFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingBasicNew: sizeRequested
+ "handleFailingBasicNew: gets sent after basicNew: has failed and allowed
+ a scavenging garbage collection to occur. The scavenging collection
+ will have happened as the VM is activating the (failing) basicNew:. If
+ handleFailingBasicNew: fails then the scavenge failed to reclaim sufficient
+ space and a global garbage collection is required. Retry after garbage
+ collecting and growing memory if necessary.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ | bytesRequested |
+ bytesRequested := self byteSizeOfInstanceOfSize: sizeRequested.
+ Smalltalk garbageCollect < bytesRequested ifTrue:
+ [Smalltalk growMemoryByAtLeast: bytesRequested].
+ "retry after global garbage collect and possible grow"
+ ^self handleFailingFailingBasicNew: sizeRequested!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew
+ "This basicNew gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 70>
+ "space must be low"
+ OutOfMemory signal.
+ ^self basicNew "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>handleFailingFailingBasicNew: (in category 'as yet unclassified') -----
+ handleFailingFailingBasicNew: sizeRequested
+ "This basicNew: gets sent after handleFailingBasicNew: has done a full
+ garbage collection and possibly grown memory. If this basicNew: fails
+ then the system really is low on space, so raise the OutOfMemory signal.
+
+ Primitive. Answer an instance of this class with the number of indexable
+ variables specified by the argument, sizeRequested. Fail if this class is not
+ indexable or if the argument is not a positive Integer, or if there is not
+ enough memory available. Essential. See Object documentation whatIsAPrimitive."
+
+ <primitive: 71>
+ "space must be low."
+ OutOfMemory signal.
+ ^self basicNew: sizeRequested "retry if user proceeds"!
Item was added:
+ ----- Method: Behavior>>identityHash (in category 'as yet unclassified') -----
+ identityHash
+ "Answer a SmallInteger whose value is related to the receiver's identity.
+ Behavior implements identityHash to allow the VM to use an object representation which
+ does not include a direct reference to an object's class in an object. If the VM is using
+ this implementation then classes are held in a class table and instances contain the index
+ of their class in the table. A class's class table index is its identityHash so that an instance
+ can be created without searching the table for a class's index. The VM uses this primitive
+ to enter the class into the class table, assigning its identityHash with an as yet unused
+ class table index. If this primitive fails it means that the class table is full. In Spur as of
+ 2014 there are 22 bits of classTable index and 22 bits of identityHash per object.
+
+ Primitive. Essential. Do not override. See Object documentation whatIsAPrimitive."
+
+ <primitive: 175>
+ self primitiveFailed!
Item was changed:
----- Method: Behavior>>instSize (in category 'testing') -----
instSize
"Answer the number of named instance variables
+ (as opposed to indexed variables) of the receiver.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>"
+ ^format bitAnd: 16rFFFF!
- (as opposed to indexed variables) of the receiver."
-
- self flag: #instSizeChange. "Smalltalk browseAllCallsOn: #instSizeChange"
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- When we revise the image format, it should become...
- ^ ((format bitShift: -1) bitAnd: 16rFF) - 1
- Note also that every other method in this category will require
- 2 bits more of right shift after the change.
- "
- ^ ((format bitShift: -10) bitAnd: 16rC0) + ((format bitShift: -1) bitAnd: 16r3F) - 1!
Item was changed:
----- Method: Behavior>>instSpec (in category 'testing') -----
instSpec
+ "Answer the instance specification part of the format that defines what kind of object
+ an instance of the receiver is. The formats are
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^(format bitShift: -16) bitAnd: 16r1F!
- ^ (format bitShift: -7) bitAnd: 16rF!
Item was changed:
----- Method: Behavior>>isBits (in category 'testing') -----
isBits
+ "Answer whether the receiver contains just bits (not pointers).
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 7!
- "Answer whether the receiver contains just bits (not pointers)."
-
- ^ self instSpec >= 6!
Item was changed:
----- Method: Behavior>>isBytes (in category 'testing') -----
isBytes
+ "Answer whether the receiver has 8-bit instance variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ ^self instSpec >= 16!
- "Answer whether the receiver has 8-bit instance variables."
-
- ^ self instSpec >= 8!
Item was added:
+ ----- Method: Behavior>>isEphemeronClass (in category 'as yet unclassified') -----
+ isEphemeronClass
+ "Answer whether the receiver has ephemeral instance variables. The garbage collector will
+ fire (queue for finalization) any ephemeron whose first instance variable is not referenced
+ other than from the transitive closure of references from ephemerons. Hence referring to
+ an object from the first inst var of an ephemeron will cause the ephemeron to fire when
+ the rest of the system does not refer to the object and that object is ready to be collected.
+ Since references from the remaining inst vars of an ephemeron will not prevent the ephemeron
+ from firing, ephemerons may act as the associations in weak dictionaries such that the value
+ (e.g. properties attached to the key) will not prevent firing when the key is no longer referenced
+ other than from ephemerons. Ephemerons can therefore be used to implement instance-based
+ pre-mortem finalization."
+ ^self instSpec = 5!
Item was added:
+ ----- Method: Behavior>>isImmediateClass (in category 'as yet unclassified') -----
+ isImmediateClass
+ "Answer whether the receiver has immediate instances. Immediate instances
+ store their value in their object pointer, not in an object body. Hence immediates
+ take no space and are immutable. The immediates are distinguished by tag bits
+ in the pointer. They include SmallIntegers and Characters. Hence in the 32-bit
+ system SmallIntegers are 31-bit signed integers and Characters are 30-bit
+ unsigned character codes."
+ ^self instSpec = 7!
Item was changed:
----- Method: Behavior>>isVariable (in category 'testing') -----
isVariable
+ "Answer whether the receiver has indexable variables.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
+ instSpec := self instSpec.
+ ^instSpec >= 2 and: [instSpec <= 4 or: [instSpec >= 9]]!
- "Answer whether the receiver has indexable variables."
-
- ^ self instSpec >= 2!
Item was changed:
----- Method: Behavior>>kindOfSubclass (in category 'testing class hierarchy') -----
kindOfSubclass
+ "Answer a String that is the keyword that describes the receiver's kind of subclass,
+ either a regular subclass, a variableSubclass, a variableByteSubclass,
+ a variableWordSubclass, a weakSubclass, an ephemeronSubclass or an immediateSubclass.
+ c.f. typeOfClass"
+ ^self isVariable
+ ifTrue:
+ [self isBits
+ ifTrue:
+ [self isBytes
+ ifTrue: [' variableByteSubclass: ']
+ ifFalse: [' variableWordSubclass: ']]
+ ifFalse:
+ [self isWeak
+ ifTrue: [' weakSubclass: ']
+ ifFalse: [' variableSubclass: ']]]
+ ifFalse:
+ [self isImmediateClass
+ ifTrue: [' immediateSubclass: ']
+ ifFalse:
+ [self isEphemeronClass
+ ifTrue: [' ephemeronSubclass: ']
+ ifFalse: [' subclass: ']]]!
- "Answer a String that is the keyword that describes the receiver's kind
- of subclass, either a regular subclass, a variableSubclass, a
- variableByteSubclass, a variableWordSubclass, or a weakSubclass."
- self isWeak
- ifTrue: [^ ' weakSubclass: '].
- ^ self isVariable
- ifTrue: [self isBits
- ifTrue: [self isBytes
- ifTrue: [ ' variableByteSubclass: ']
- ifFalse: [ ' variableWordSubclass: ']]
- ifFalse: [ ' variableSubclass: ']]
- ifFalse: [ ' subclass: ']!
Item was changed:
----- Method: Behavior>>shouldNotBeRedefined (in category 'testing') -----
shouldNotBeRedefined
+ "Answer if the receiver should not be redefined.
+ The assumption is that classes in Smalltalk specialObjects and
+ instance-specific Behaviors should not be redefined"
- "Return true if the receiver should not be redefined.
- The assumption is that compact classes,
- classes in Smalltalk specialObjects and
- Behaviors should not be redefined"
+ ^(Smalltalk specialObjectsArray
+ identityIndexOf: self
+ ifAbsent: [(self isKindOf: self) ifTrue: [1] ifFalse: [0]]) ~= 0!
- ^(Smalltalk compactClassesArray includes: self)
- or:[(Smalltalk specialObjectsArray includes: self)
- or:[self isKindOf: self]]!
Item was changed:
----- Method: Behavior>>typeOfClass (in category 'accessing') -----
typeOfClass
+ "Answer a symbol uniquely describing the type of the receiver. c.f. kindOfSubclass"
+ self isBytes ifTrue:
+ [^self instSpec = CompiledMethod instSpec
+ ifTrue: [#compiledMethod] "Very special!!"
+ ifFalse: [#bytes]].
+ (self isWords and: [self isPointers not]) ifTrue:
+ [^self instSpec = SmallInteger instSpec
+ ifTrue: [#immediate] "Very special!!"
+ ifFalse: [#words]].
+ self isWeak ifTrue: [^#weak].
+ self isVariable ifTrue: [^#variable].
+ self isEphemeronClass ifTrue: [^#ephemeron].
+ ^#normal!
- "Answer a symbol uniquely describing the type of the receiver"
- self instSpec = CompiledMethod instSpec ifTrue:[^#compiledMethod]. "Very special!!"
- self isBytes ifTrue:[^#bytes].
- (self isWords and:[self isPointers not]) ifTrue:[^#words].
- self isWeak ifTrue:[^#weak].
- self isVariable ifTrue:[^#variable].
- ^#normal.!
Item was added:
+ ----- Method: Class>>immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ immediateSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a new
+ immediate class as a subclass of an existing class (the receiver)."
+ ^ClassBuilder new
+ superclass: self
+ immediateSubclass: t
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>computeFormat:instSize:forSuper:ccIndex: (in category 'class format') -----
computeFormat: type instSize: newInstSize forSuper: newSuper ccIndex: ccIndex
"Compute the new format for making oldClass a subclass of newSuper.
+ Answer the format or nil if there is any problem."
- Return the format or nil if there is any problem."
| instSize isVar isWords isPointers isWeak |
type == #compiledMethod ifTrue:
+ [newInstSize > 0 ifTrue:
+ [self error: 'A compiled method class cannot have named instance variables'.
+ ^nil].
+ ^CompiledMethod format].
- [^(CompiledMethod format
- bitClear: (16r1F bitShift: 11))
- bitOr: (ccIndex bitShift: 11)].
instSize := newInstSize + (newSuper ifNil:[0] ifNotNil:[newSuper instSize]).
+ instSize > 65535 ifTrue:
- instSize > 254 ifTrue:
[self error: 'Class has too many instance variables (', instSize printString,')'.
^nil].
type == #normal ifTrue:[isVar := isWeak := false. isWords := isPointers := true].
type == #bytes ifTrue:[isVar := true. isWords := isPointers := isWeak := false].
type == #words ifTrue:[isVar := isWords := true. isPointers := isWeak := false].
type == #variable ifTrue:[isVar := isPointers := isWords := true. isWeak := false].
type == #weak ifTrue:[isVar := isWeak := isWords := isPointers := true].
+ type == #ephemeron ifTrue:[isVar := false. isWeak := isWords := isPointers := true].
+ type == #immediate ifTrue:[isVar := isWeak := isPointers := false. isWords := true].
+ (isPointers not and: [instSize > 0]) ifTrue:
+ [self error: 'A non-pointer class cannot have named instance variables'.
- (isPointers not and:[instSize > 0]) ifTrue:
- [self error:'A non-pointer class cannot have instance variables'.
^nil].
+ ^self format: instSize variable: isVar words: isWords pointers: isPointers weak: isWeak!
- ^(self format: instSize
- variable: isVar
- words: isWords
- pointers: isPointers
- weak: isWeak) + (ccIndex bitShift: 11).!
Item was changed:
----- Method: ClassBuilder>>format:variable:words:pointers:weak: (in category 'class format') -----
format: nInstVars variable: isVar words: isWords pointers: isPointers weak: isWeak
+ "Compute the format for the given instance specfication.
+ Above Cog Spur the class format is
+ <5 bits inst spec><16 bits inst size>
+ where the 5-bit inst spec is
+ 0 = 0 sized objects (UndefinedObject True False et al)
+ 1 = non-indexable objects with inst vars (Point et al)
+ 2 = indexable objects with no inst vars (Array et al)
+ 3 = indexable objects with inst vars (MethodContext AdditionalMethodState et al)
+ 4 = weak indexable objects with inst vars (WeakArray et al)
+ 5 = weak non-indexable objects with inst vars (ephemerons) (Ephemeron)
+ 6 = unused
+ 7 = immediates (SmallInteger, Character)
+ 8 = unused
+ 9 = reserved for 64-bit indexable
+ 10-11 = 32-bit indexable (Bitmap)
+ 12-15 = 16-bit indexable
+ 16-23 = 8-bit indexable
+ 24-31 = compiled methods (CompiledMethod)"
+ | instSpec |
- "Compute the format for the given instance specfication."
- | cClass instSpec sizeHiBits fmt |
- self flag: #instSizeChange.
- "
- Smalltalk browseAllCallsOn: #instSizeChange.
- Smalltalk browseAllImplementorsOf: #fixedFieldsOf:.
- Smalltalk browseAllImplementorsOf: #instantiateClass:indexableSize:.
- "
- "
- NOTE: This code supports the backward-compatible extension to 8 bits of instSize.
- For now the format word is...
- <2 bits=instSize//64><5 bits=cClass><4 bits=instSpec><6 bits=instSize\\64><1 bit=0>
- But when we revise the image format, it should become...
- <5 bits=cClass><4 bits=instSpec><8 bits=instSize><1 bit=0>
- "
- sizeHiBits := (nInstVars+1) // 64.
- cClass := 0. "for now"
instSpec := isWeak
+ ifTrue:
+ [isVar
+ ifTrue: [4]
+ ifFalse: [5]]
+ ifFalse:
+ [isPointers
+ ifTrue:
+ [isVar
+ ifTrue: [nInstVars > 0 ifTrue: [3] ifFalse: [2]]
+ ifFalse: [nInstVars > 0 ifTrue: [1] ifFalse: [0]]]
+ ifFalse:
+ [isVar
+ ifTrue: [isWords ifTrue: [12] ifFalse: [16]]
+ ifFalse: [7]]].
+ ^(instSpec bitShift: 16) + nInstVars!
- ifTrue:[4]
- ifFalse:[isPointers
- ifTrue: [isVar
- ifTrue: [nInstVars>0 ifTrue: [3] ifFalse: [2]]
- ifFalse: [nInstVars>0 ifTrue: [1] ifFalse: [0]]]
- ifFalse: [isWords ifTrue: [6] ifFalse: [8]]].
- fmt := sizeHiBits.
- fmt := (fmt bitShift: 5) + cClass.
- fmt := (fmt bitShift: 4) + instSpec.
- fmt := (fmt bitShift: 6) + ((nInstVars+1)\\64). "+1 since prim size field includes header"
- fmt := (fmt bitShift: 1). "This shift plus integer bit lets wordSize work like byteSize"
- ^fmt!
Item was added:
+ ----- Method: ClassBuilder>>superclass:immediateSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (in category 'as yet unclassified') -----
+ superclass: aClass
+ immediateSubclass: t instanceVariableNames: f
+ classVariableNames: d poolDictionaries: s category: cat
+ "This is the standard initialization message for creating a
+ new immediate class as a subclass of an existing class."
+ | env |
+ aClass instSize > 0
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with named fields'].
+ aClass isVariable
+ ifTrue: [^self error: 'cannot make an immediate subclass of a class with indexed instance variables'].
+ aClass isPointers
+ ifFalse: [^self error: 'cannot make an immediate subclass of a class without pointer fields'].
+ "Cope with pre-environment and environment versions. Simplify asap."
+ env := (Smalltalk classNamed: #EnvironmentRequest)
+ ifNil: [aClass environment]
+ ifNotNil: [:erc| erc signal ifNil: [aClass environment]].
+ ^self
+ name: t
+ inEnvironment: env
+ subclassOf: aClass
+ type: #immediate
+ instanceVariableNames: f
+ classVariableNames: d
+ poolDictionaries: s
+ category: cat!
Item was changed:
----- Method: ClassBuilder>>update:to: (in category 'class mutation') -----
update: oldClass to: newClass
+ "Convert oldClass, all its instances and possibly its meta class into newClass,
+ instances of newClass and possibly its meta class. The process is surprisingly
+ simple in its implementation and surprisingly complex in its nuances and potentially
+ bad side effects.
+ We can rely on two assumptions (which are critical):
+ #1: The method #updateInstancesFrom: will not create any lasting pointers to
+ 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do
+ a become of the old vs. the new instances and therefore it will not create
+ pointers to *new* instances before the #become: which are *old* afterwards)
+ #2: The non-preemptive execution of the critical piece of code guarantees that
+ nobody can get a hold by 'other means' (such as process interruption and
+ reflection) on the old instances.
+ Given the above two, we know that after #updateInstancesFrom: there are no pointers
+ to any old instances. After the forwarding become there will be no pointers to the old
+ class or meta class either.
+ Andreas Raab, 2/27/2003 23:42"
- "Convert oldClass, all its instances and possibly its meta class into newClass, instances of newClass and possibly its meta class. The process is surprisingly simple in its implementation and surprisingly complex in its nuances and potentially bad side effects.
- We can rely on two assumptions (which are critical):
- #1: The method #updateInstancesFrom: will not create any lasting pointers to 'old' instances ('old' is quote on quote since #updateInstancesFrom: will do a become of the old vs. the new instances and therefore it will not create pointers to *new* instances before the #become: which are *old* afterwards)
- #2: The non-preemptive execution of the critical piece of code guarantees that nobody can get a hold by 'other means' (such as process interruption and reflection) on the old instances.
- Given the above two, we know that after #updateInstancesFrom: there are no pointer to any old instances. After the forwarding become there will be no pointers to the old class or meta class either. Meaning that if we throw in a nice fat GC at the end of the critical block, everything will be gone (but see the comment right there). There's no need to worry.
- "
| meta |
meta := oldClass isMeta.
"Note: Everything from here on will run without the ability to get interrupted
to prevent any other process to create new instances of the old class."
+ ["Note: The following removal may look somewhat obscure and needs an explanation.
+ When we mutate the class hierarchy we create new classes for any existing subclass.
+ So it may look as if we don't have to remove the old class from its superclass. However,
+ at the top of the hierarchy (the first class we reshape) that superclass itself is not newly
+ created so therefore it will hold both the oldClass and newClass in its (obsolete or not)
+ subclasses. Since the #become: below will transparently replace the pointers to oldClass
+ with newClass the superclass would have newClass in its subclasses TWICE. With rather
+ unclear effects if we consider that we may convert the meta-class hierarchy itself (which
+ is derived from the non-meta class hierarchy).
+ Due to this problem ALL classes are removed from their superclass just prior to converting
+ them. Here, breaking the superclass/subclass invariant really doesn't matter since we will
+ effectively remove the oldClass (becomeForward:) just a few lines below."
- [
- "Note: The following removal may look somewhat obscure and needs an explanation. When we mutate the class hierarchy we create new classes for any existing subclass. So it may look as if we don't have to remove the old class from its superclass. However, at the top of the hierarchy (the first class we reshape) that superclass itself is not newly created so therefore it will hold both the oldClass and newClass in its (obsolete or not) subclasses. Since the #become: below will transparently replace the pointers to oldClass with newClass the superclass would have newClass in its subclasses TWICE. With rather unclear effects if we consider that we may convert the meta-class hierarchy itself (which is derived from the non-meta class hierarchy).
- Due to this problem ALL classes are removed from their superclass just prior to converting them. Here, breaking the superclass/subclass invariant really doesn't matter since we will effectively remove the oldClass (become+GC) just a few lines below."
oldClass superclass removeSubclass: oldClass.
oldClass superclass removeObsoleteSubclass: oldClass.
"make sure that the VM cache is clean"
oldClass methodDict do: [:cm | cm flushCache].
"Convert the instances of oldClass into instances of newClass"
newClass updateInstancesFrom: oldClass.
meta
ifTrue:
[oldClass becomeForward: newClass.
oldClass updateMethodBindingsTo: oldClass binding]
ifFalse:
[{oldClass. oldClass class} elementsForwardIdentityTo: {newClass. newClass class}.
oldClass updateMethodBindingsTo: oldClass binding.
oldClass class updateMethodBindingsTo: oldClass class binding].
+ "eem 5/31/2014 07:22 At this point there used to be a garbage collect whose purpose was
+ to ensure no old instances existed after the becomeForward:. Without the GC it was possible
+ to resurrect old instances using e.g. allInstancesDo:. This was because the becomeForward:
+ updated references from the old objects to new objects but didn't destroy the old objects.
+ But as of late 2013/early 2014 becomeForward: has been modified to free all the old objects."]
+ valueUnpreemptively!
- Smalltalk garbageCollect.
-
- "Warning: Read this before you even think about removing the GC. Yes, it slows us down. Quite heavily if you have a large image. However, there's no good and simple alternative here, since unfortunately, #become: does change class pointers. What happens is that after the above become all of the instances of the old class will have a class pointer identifying them as instances of newClass. If we get our hands on any of these instances we will break immediately since their expected instance layout (that of its class, e.g., newClass) will not match their actual instance layout (that of oldClass). And getting your hands on any of those instances is really simple - just reshaping one class two times in rapid succession will do it. Reflection techniques, interrupts, etc. will only add to this problem. In the case of Metaclass things get even worse since when we recompile the entire class hierarchy we will recompile both, Metaclass and its instances (and some of its instances will have the old and some the new layout).
-
- The only easy solution to this problem would be to 'fix up' the class pointers of the old instances to point to the old class (using primitiveChangeClassTo:). But this won't work either - as we do a one-way become we would have to search the entire object memory for the oldClass and couldn't even clearly identify it unless we give it some 'special token' which sounds quite error-prone. If you really need to get rid of the GC here are some alternatives:
-
- On the image level, one could create a copy of the oldClass before becoming it into the new class and, after becoming it, 'fix up' the old instances. That would certainly work but it sounds quite complex, as we need to make sure we're not breaking any of the superclass/subclass meta/non-meta class variants.
-
- Alternatively, fix up #becomeForward on the VM-level to 'dump the source objects' of #become. This would be quite doable (just 'convert' them into a well known special class such as bitmap) yet it has problems if (accidentally or not) one of the objects in #become: appears on 'both sides of the fence' (right now, this will work ... in a way ... even though the consequences are unclear).
-
- Another alternative is to provide a dedicated primitive for this (instead of using it implicitly in become) which would allow us to dump all the existing instances right here. This is equivalent to a more general primitiveChangeClassTo: and might be worthwhile but it would likely have to keep in mind the differences between bits and pointer thingies etc.
-
- Since all of the alternatives seem rather complex and magical compared to a straight-forward GC it seems best to stick with the GC solution for now. If someone has a real need to fix this problem, that person will likely be motivated enough to check out the alternatives. Personally I'd probably go for #1 (copy the old class and remap the instances to it) since it's a solution that could be easily reverted from within the image if there's any problem with it."
-
- ] valueUnpreemptively.
- !
Item was added:
+ ----- Method: MethodContext>>allInstances (in category 'as yet unclassified') -----
+ allInstances
+ "Answer all instances of the receiver."
+ <primitive: 177>
+ "The primitive can fail because memory is low. If so, fall back on the old
+ enumeration code, which gives the system a chance to GC and/or grow.
+ Because aBlock might change the class of inst (for example, using become:),
+ it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since this context has been created only to
+ compute the existing instances."
+ | inst insts next |
+ insts := WriteStream on: (Array new: 64).
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ insts nextPut: inst.
+ inst := next].
+ ^insts contents!
Item was added:
+ ----- Method: MethodContext>>allInstancesDo: (in category 'as yet unclassified') -----
+ allInstancesDo: aBlock
+ "Evaluate aBlock with each of the current instances of the receiver."
+ | instances inst next |
+ instances := self allInstancesOrNil.
+ instances ifNotNil:
+ [instances do: aBlock.
+ ^self].
+ "allInstancesOrNil can fail because memory is low. If so, fall back on the old
+ enumeration code. Because aBlock might change the class of inst (for example,
+ using become:), it is essential to compute next before aBlock value: inst.
+ Only count until thisContext since evaluation of aBlock will create new contexts."
+ inst := self someInstance.
+ [inst == thisContext or: [inst == nil]] whileFalse:
+ [next := inst nextInstance.
+ aBlock value: inst.
+ inst := next]!
Item was changed:
----- Method: ProtoObject>>scaledIdentityHash (in category 'comparing') -----
scaledIdentityHash
"For identityHash values returned by primitive 75, answer
+ such values times 2^8. Otherwise, match the existing
+ identityHash implementation"
- such values times 2^18. Otherwise, match the existing
- identityHash implementation"
+ ^self identityHash * 256 "bitShift: 8"!
- ^self identityHash * 262144 "bitShift: 18"!
Item was changed:
==== ERROR ===
Error: Unrecognized class type
27 June 2014 1:02:12.208 am
VM: unix - a SmalltalkImage
Image: Squeak3.11alpha [latest update: #8824]
SecurityManager state:
Restricted: false
FileAccess: true
SocketAccess: true
Working Dir /home/squeaksource
Trusted Dir /home/squeaksource/secure
Untrusted Dir /home/squeaksource/My Squeak
MCClassDefinition(Object)>>error:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
aString: 'Unrecognized class type'
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>kindOfSubclass
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
MCClassDefinition>>printDefinitionOn:
Receiver: a MCClassDefinition(SmallInteger)
Arguments and temporary variables:
stream: a WriteStream
Receiver's instance variables:
name: #SmallInteger
superclassName: #Integer
variables: an OrderedCollection()
category: #'Kernel-Numbers'
type: #immediate
comment: 'My instances are 31-bit numbers, stored in twos complement form. The ...etc...
commentStamp: '<historical>'
traitComposition: nil
classTraitComposition: nil
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
Receiver: a MCDiffyTextWriter
Arguments and temporary variables:
definition: a WriteStream
s: a MCClassDefinition(SmallInteger)
Receiver's instance variables:
stream: a WriteStream
initStream: nil
--- The full stack ---
MCClassDefinition(Object)>>error:
MCClassDefinition>>kindOfSubclass
MCClassDefinition>>printDefinitionOn:
[] in MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>chunkContents:
MCDiffyTextWriter(MCStWriter)>>writeClassDefinition:
MCDiffyTextWriter(MCStWriter)>>visitClassDefinition:
MCClassDefinition>>accept:
[] in MCDiffyTextWriter(MCTextWriter)>>visitInFork:
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
MCDiffyTextWriter(MCTextWriter)>>visitInFork:
MCDiffyTextWriter>>writePatchFrom:to:
MCDiffyTextWriter>>writeModification:
[] in MCDiffyTextWriter>>writePatch:
SortedCollection(OrderedCollection)>>do:
MCDiffyTextWriter>>writePatch:
SSDiffyTextWriter>>writePatch:
[] in SSDiffyTextWriter>>writeVersion:for:
BlockClosure>>on:do:
SSDiffyTextWriter>>writeVersion:for:
[] in SSEMailSubscription>>versionAdded:to:
BlockClosure>>on:do:
SSEMailSubscription>>versionAdded:to:
[] in [] in SSProject>>versionAdded:
[] in BlockClosure>>newProcess