[Vm-dev] VM Maker: VMMaker.oscog-eem.512.mcz

commits at source.squeak.org commits at source.squeak.org
Sat Nov 16 16:49:40 UTC 2013


Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.512.mcz

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

Name: VMMaker.oscog-eem.512
Author: eem
Time: 16 November 2013, 8:46:30.121 am
UUID: e67f6750-242d-43e3-8a3b-681b3b617e38
Ancestors: VMMaker.oscog-eem.511

A Ferrari commit? A power-of-two commit? :-)

Change endOfMemory to include last bridge (too hard to get the
memory size right otherwise).

Change the enumerators to use endOfMemory instead of freeOldSpaceStart (which I'd like to get rid of sometime).

Move isValidSegmentBridge: to SpurSegMgr.

Include segLimit in SpurSegInfo printing.

Finally the shootout tests run to completion.

=============== Diff against VMMaker.oscog-eem.511 ===============

Item was changed:
  ----- Method: Spur32BitMMLESimulator>>longAt:put: (in category 'memory access') -----
  longAt: byteAddress put: a32BitValue
  	"Note: Adjusted for Smalltalk's 1-based array indexing."
+ 	"(byteAddress = 16r183FB00 and: [a32BitValue = 16r3FFFFC]) ifTrue:
- 	"(byteAddress = 16r1614CB8 and: [a32BitValue = 16rA000035]) ifTrue:
  		[self halt]."
  	"(byteAddress between: 16r33FBB8 and: 16r33FBCF) ifTrue:
  		[self halt]."
  	byteAddress \\ 4 ~= 0 ifTrue: [self unalignedAccessError].
  	^memory at: byteAddress // 4 + 1 put: a32BitValue!

Item was changed:
  ----- Method: SpurMemoryManager>>accessibleObjectAfter: (in category 'object enumeration') -----
  accessibleObjectAfter: objOop
  	"Answer the accessible object following the given object or 
  	free chunk in the heap. Return nil when heap is exhausted.
  	 This is for primitiveNextObject subsequent to primtiiveSomeObject."
  	<inline: false>
  	| objAfter |
  	objAfter := objOop.
+ 	[objAfter := self objectAfter: objAfter limit: endOfMemory.
+ 	 objAfter = endOfMemory ifTrue:
- 	[objAfter := self objectAfter: objAfter limit: freeOldSpaceStart.
- 	 objAfter = freeOldSpaceStart ifTrue:
  		[^nil].
  	 (self isNormalObject: objAfter) ifTrue:
  		[^objAfter]] repeat!

Item was changed:
  ----- Method: SpurMemoryManager>>adjustAllOopsBy: (in category 'snapshot') -----
  adjustAllOopsBy: bytesToShift
  	"Adjust all oop references by the given number of bytes. This is
  	 done just after reading in an image when the new base address
  	 of the object heap is different from the base address in the image,
  	 or when loading multiple segments that have been coalesced.  Also
  	 set bits in the classTableBitmap corresponding to used classes."
  
  	| obj |
  	self countNumClassPagesPreSwizzle: bytesToShift;
  		ensureAdequateClassTableBitmap.
  	(bytesToShift ~= 0
  	 or: [segmentManager numSegments > 1])
  		ifTrue:
  			[self assert: self newSpaceIsEmpty.
  			 obj := self objectStartingAt: newSpaceLimit.
+ 			 [self oop: obj isLessThan: endOfMemory] whileTrue:
- 			 [self oop: obj isLessThan: freeOldSpaceStart] whileTrue:
  				[(self isFreeObject: obj)
  					ifTrue: [self swizzleFieldsOfFreeChunk: obj]
  					ifFalse:
  						[self inClassTableBitmapSet: (self classIndexOf: obj).
  						 self swizzleFieldsOfObject: obj].
  				 obj := self objectAfter: obj]]
  		ifFalse:
  			[self assert: self newSpaceIsEmpty.
  			 obj := self objectStartingAt: newSpaceLimit.
+ 			 [self oop: obj isLessThan: endOfMemory] whileTrue:
- 			 [self oop: obj isLessThan: freeOldSpaceStart] whileTrue:
  				[(self isFreeObject: obj) ifFalse:
  					[self inClassTableBitmapSet: (self classIndexOf: obj)].
  				 obj := self objectAfter: obj]]!

Item was changed:
  ----- Method: SpurMemoryManager>>allExistingOldSpaceObjectsDo: (in category 'object enumeration') -----
  allExistingOldSpaceObjectsDo: aBlock
  	"Enumerate all old space objects, excluding any objects created
  	 during the execution of allExistingOldSpaceObjectsDo:."
  	<inline: true>
  	| oldSpaceLimit prevObj prevPrevObj objOop |
  	prevPrevObj := prevObj := nil.
  	objOop := self firstObject.
+ 	oldSpaceLimit := endOfMemory.
- 	oldSpaceLimit := freeOldSpaceStart.
  	[self assert: objOop \\ self allocationUnit = 0.
  	 self oop: objOop isLessThan: oldSpaceLimit] whileTrue:
  		[self assert: (self longLongAt: objOop) ~= 0.
  		 (self isEnumerableObject: objOop) ifTrue:
  			[aBlock value: objOop].
  		 prevPrevObj := prevObj.
  		 prevObj := objOop.
+ 		 objOop := self objectAfter: objOop limit: oldSpaceLimit].
- 		 objOop := self objectAfter: objOop limit: freeOldSpaceStart].
  	self touch: prevPrevObj.
  	self touch: prevObj!

Item was changed:
  ----- Method: SpurMemoryManager>>allOldSpaceEntitiesForCoalescingDo: (in category 'object enumeration') -----
  allOldSpaceEntitiesForCoalescingDo: aBlock
  	<inline: true>
  	| prevObj prevPrevObj objOop rawNumSlots rawNumSlotsAfter |
  	prevPrevObj := prevObj := nil.
  	objOop := self firstObject.
  	[self assert: objOop \\ self allocationUnit = 0.
+ 	 self oop: objOop isLessThan: endOfMemory] whileTrue:
- 	 self oop: objOop isLessThan: freeOldSpaceStart] whileTrue:
  		[self assert: (self longLongAt: objOop) ~= 0.
  		 rawNumSlots := self rawNumSlotsOf: objOop.
  		 aBlock value: objOop.
  		 "If the number of slot changes coalescing changed an object from a single to a double header."
  		 rawNumSlotsAfter := self rawNumSlotsOf: objOop.
  		 (rawNumSlotsAfter ~= rawNumSlots
  		  and: [rawNumSlotsAfter = self numSlotsMask]) ifTrue:
  			[objOop := objOop + self baseHeaderSize.
+ 			 self assert: (self objectAfter: prevObj limit: endOfMemory) = objOop].
- 			 self assert: (self objectAfter: prevObj limit: freeOldSpaceStart) = objOop].
  		 prevPrevObj := prevObj.
  		 prevObj := objOop.
+ 		 objOop := self objectAfter: objOop limit: endOfMemory].
- 		 objOop := self objectAfter: objOop limit: freeOldSpaceStart].
  	self touch: prevPrevObj.
  	self touch: prevObj!

Item was changed:
  ----- Method: SpurMemoryManager>>allOldSpaceEntitiesFrom:do: (in category 'object enumeration') -----
  allOldSpaceEntitiesFrom: initialObject do: aBlock
  	<inline: true>
  	| prevObj prevPrevObj objOop |
  	prevPrevObj := prevObj := nil.
  	objOop := initialObject.
  	[self assert: objOop \\ self allocationUnit = 0.
+ 	 self oop: objOop isLessThan: endOfMemory] whileTrue:
- 	 self oop: objOop isLessThan: freeOldSpaceStart] whileTrue:
  		[self assert: (self longLongAt: objOop) ~= 0.
  		 aBlock value: objOop.
  		 prevPrevObj := prevObj.
  		 prevObj := objOop.
+ 		 objOop := self objectAfter: objOop limit: endOfMemory].
- 		 objOop := self objectAfter: objOop limit: freeOldSpaceStart].
  	self touch: prevPrevObj.
  	self touch: prevObj!

Item was changed:
  ----- Method: SpurMemoryManager>>allocateMemoryOfSize:newSpaceSize:stackSize:codeSize: (in category 'spur bootstrap') -----
  allocateMemoryOfSize: memoryBytes newSpaceSize: newSpaceBytes stackSize: stackBytes codeSize: codeBytes
  	"Intialize the receiver for bootsraping an image.
  	 Set up a large oldSpace and an empty newSpace and set-up freeStart and scavengeThreshold
  	 to allocate in oldSpace.  Later on (in initializePostBootstrap) freeStart and scavengeThreshold
  	 will be set to sane values."
  	<doNotGenerate>
  	self assert: (memoryBytes \\ self allocationUnit = 0
  				and: [newSpaceBytes \\ self allocationUnit = 0
  				and: [codeBytes \\ self allocationUnit = 0]]).
  	memory := (self endianness == #little
  					ifTrue: [LittleEndianBitmap]
  					ifFalse: [Bitmap]) new: (memoryBytes + newSpaceBytes + codeBytes + stackBytes) // 4.
  	startOfMemory := codeBytes + stackBytes.
+ 	endOfMemory := freeOldSpaceStart := memoryBytes + newSpaceBytes + codeBytes + stackBytes.
- 	endOfMemory := freeOldSpaceStart := memoryBytes + newSpaceBytes + codeBytes + stackBytes - self bridgeSize.
  	"leave newSpace empty for the bootstrap"
  	freeStart := newSpaceBytes + startOfMemory.
  	newSpaceLimit := newSpaceBytes + startOfMemory.
  	scavengeThreshold := memory size * 4. "Bitmap is a 4-byte per word array"
  	scavenger := SpurGenerationScavengerSimulator new
  					manager: self
  					newSpaceStart: startOfMemory
  					newSpaceBytes: newSpaceBytes
  					edenBytes: newSpaceBytes * self scavengerDenominator - self numSurvivorSpaces // self scavengerDenominator!

Item was changed:
  ----- Method: SpurMemoryManager>>cheapAddressCouldBeInHeap: (in category 'debug support') -----
  cheapAddressCouldBeInHeap: address 
  	^(address bitAnd: self wordSize - 1) = 0
  	  and: [(self oop: address isGreaterThanOrEqualTo: startOfMemory)
+ 	  and: [self oop: address isLessThan: endOfMemory]]!
- 	  and: [self oop: address isLessThan: freeOldSpaceStart]]!

Item was changed:
  ----- Method: SpurMemoryManager>>checkOkayOop: (in category 'debug support') -----
  checkOkayOop: oop
  	"Verify that the given oop is legitimate. Check address, header, and size but not class.
  	 Answer true if OK.  Otherwise print reason and answer false."
  	<api>
  	<var: #oop type: #usqInt>
  	| classIndex fmt unusedBits unusedBitsInYoungObjects |
  	<var: #unusedBits type: #usqLong>
  
  	"address and size checks"
  	(self isImmediate: oop) ifTrue: [^true].
  	(self addressCouldBeObjWhileScavenging: oop) ifFalse:
  		[self print: 'oop '; printHex: oop; print: ' is not a valid address'. ^false].
  
+ 	(self oop: (self addressAfter: oop) isLessThanOrEqualTo: endOfMemory) ifFalse:
- 	(self oop: (self addressAfter: oop) isLessThanOrEqualTo: freeOldSpaceStart) ifFalse:
  		[self print: 'oop '; printHex: oop; print: ' size would make it extend beyond the end of memory'. ^false].
  
  	"header type checks"
  	(classIndex := self classIndexOf: oop) >= self firstClassIndexPun ifFalse:
  		[self print: 'oop '; printHex: oop; print: ' is a free chunk, or bridge, not an object'. ^false].
  	((self rawNumSlotsOf: oop) = self numSlotsMask
  	 and: [(self rawNumSlotsOf: oop - self baseHeaderSize) ~= self numSlotsMask]) ifTrue:
  		[self print: 'oop '; printHex: oop; print: ' header has overflow header word, but overflow word does not have a saturated numSlots field'. ^false].
  
  	"format check"
  	fmt := self formatOf: oop.
  	(fmt = 6) | (fmt = 8) ifTrue:
  		[self print: 'oop '; printHex: oop; print: ' has an unknown format type'. ^false].
  	(fmt = self forwardedFormat) ~= (classIndex = self isForwardedObjectClassIndexPun) ifTrue:
  		[self print: 'oop '; printHex: oop; print: ' has mis-matched format/classIndex fields; only one of them is the isForwarded value'. ^false].
  
  	"specific header bit checks"
  	unusedBits := (1 << self classIndexFieldWidth)
  				   | (1 << (self identityHashFieldWidth + 32)).
  	((self longLongAt: oop) bitAnd: unusedBits) ~= 0 ifTrue:
  		[self print: 'oop '; printHex: oop; print: ' has some unused header bits set; should be zero'. ^false].
  
  	unusedBitsInYoungObjects := self newSpaceRefCountMask.
  	((self longAt: oop) bitAnd: unusedBitsInYoungObjects) ~= 0 ifTrue:
  		[self print: 'oop '; printHex: oop; print: ' has some header bits unused in young objects set; should be zero'. ^false].
  	^true!

Item was added:
+ ----- Method: SpurMemoryManager>>computeFreeSpacePostSwizzle (in category 'free space') -----
+ computeFreeSpacePostSwizzle
+ 	totalFreeOldSpace := self totalFreeListBytes.
+ 	self checkFreeSpace!

Item was changed:
  ----- Method: SpurMemoryManager>>countNumClassPagesPreSwizzle: (in category 'class table') -----
  countNumClassPagesPreSwizzle: bytesToShift
  	"Compute the used size of the class table before swizzling.  Needed to
  	 initialize the classTableBitmap which is populated during adjustAllOopsBy:"
  	| firstObj classTableRoot nilObjPreSwizzle |
  	firstObj := self objectStartingAt: newSpaceLimit. "a.k.a. nilObj"
  	"first five objects are nilObj, falseObj, trueObj, freeListsObj, classTableRootObj"
  	classTableRoot := self objectAfter:
  							(self objectAfter:
  									(self objectAfter:
  											(self objectAfter: firstObj
+ 												limit: endOfMemory)
+ 										limit: endOfMemory)
+ 								limit: endOfMemory)
+ 							limit: endOfMemory.
- 												limit: freeOldSpaceStart)
- 										limit: freeOldSpaceStart)
- 								limit: freeOldSpaceStart)
- 							limit: freeOldSpaceStart.
  	nilObjPreSwizzle := newSpaceLimit - bytesToShift.
  	numClassTablePages := self numSlotsOf: classTableRoot.
  	self assert: numClassTablePages = (self classTableRootSlots + self hiddenRootSlots).
  	2 to: numClassTablePages - 1 do:
  		[:i|
  		(self fetchPointer: i ofObject: classTableRoot) = nilObjPreSwizzle ifTrue:
  			[numClassTablePages := i.
  			 ^self]]
  	!

Item was changed:
  ----- Method: SpurMemoryManager>>endOfMemory (in category 'accessing') -----
  endOfMemory
+ 	<cmacro: '() GIV(endOfMemory)'>
  	^endOfMemory!

Item was changed:
  ----- Method: SpurMemoryManager>>freeUnmarkedObjectsAndSortAndCoalesceFreeSpace (in category 'gc - global') -----
  freeUnmarkedObjectsAndSortAndCoalesceFreeSpace
  	"Sweep all of old space, freeing unmarked objects, coalescing free chunks, and sorting free space.
  
  	 Small free chunks are sorted in address order on each small list head.  Large free chunks
  	 are sorted on the sortedFreeChunks list.  Record as many of the highest objects as there
  	 is room for in highestObjects, a circular buffer, for the use of exactFitCompact.  Use
  	 unused eden space for highestObjects.  If highestObjects does not wrap, store 0
  	 at highestObjects last.  Record the lowest free object in firstFreeChunk.  Let the
  	 segmentManager mark which segments contain pinned objects via notePinned:."
  
  	| lastLargeFree lastHighest highestObjectsWraps sortedFreeChunks |
  	<var: #lastHighest type: #usqInt>
  	self checkFreeSpace.
  	scavenger forgetUnmarkedRememberedObjects.
  	segmentManager prepareForGlobalSweep."for notePinned:"
  	"for sorting free space throw away the list heads, rebuilding them for small free chunks below."
  	self resetFreeListHeads.
  	highestObjects initializeStart: freeStart limit: scavenger eden limit.
  	lastHighest := highestObjects last "a.k.a. freeStart - wordSize".
  	highestObjectsWraps := 0.
  	self assert: highestObjects limit - highestObjects start // self wordSize >= 1024.
  	firstFreeChunk := sortedFreeChunks := lastLargeFree := 0.
  	"Note that if we were truly striving for performance we could split the scan into
  	 two phases, one up to the first free object and one after, which would remove
  	 the need to test firstFreeChunk when filling highestObjects."
  	self allOldSpaceEntitiesForCoalescingDo:
  		[:o|
  		(self isMarked: o)
  			ifTrue: "forwarders should have been followed in markAndTrace:"
  				[self assert: (self isForwarded: o) not.
  				 self setIsMarkedOf: o to: false. "this will unmark bridges. undo the damage in notePinned:"
  				 (self isPinned: o) ifTrue:
  					[segmentManager notePinned: o].
  				 firstFreeChunk ~= 0 ifTrue:
  					[false "conceptually...: "
  						ifTrue: [highestObjects addLast: o]
  						ifFalse: "but we inline so we can use the local lastHighest"
  							[(lastHighest := lastHighest + self wordSize) >= highestObjects limit ifTrue:
  								[highestObjectsWraps := highestObjectsWraps + 1].
  							 self longAt: lastHighest put: o]]]
  			ifFalse: "unmarked; two cases, an unreachable object or a free chunk."
+ 				[| here limit next |
- 				[| here next |
  				 self assert: (self isRemembered: o) not. "scavenger should have cleared this above"
  				 here := o.
+ 				 limit := endOfMemory - self bridgeSize.
+ 				 next := self objectAfter: here limit: limit.
+ 				 [next = limit or: [self isMarked: next]] whileFalse: "coalescing; rare case"
- 				 next := self objectAfter: here limit: endOfMemory.
- 				 (self isMarked: next) ifFalse: "coalescing; rare case"
  					[self assert: (self isRemembered: o) not.
+ 					 statCoalesces := statCoalesces + 1.
+ 					 here := self coalesce: here and: next.
+ 					 next := self objectAfter: here limit: limit].
- 					 [statCoalesces := statCoalesces + 1.
- 					  here := self coalesce: here and: next.
- 					  next := self objectAfter: here limit: endOfMemory.
- 					  next = endOfMemory or: [self isMarked: next]] whileFalse].
  				 self setFree: here.
  				 firstFreeChunk = 0 ifTrue:
  					[firstFreeChunk := here].
  				 (self isLargeFreeObject: here)
  					ifTrue:
  						[lastLargeFree = 0
  							ifTrue: [sortedFreeChunks := here]
  							ifFalse:
  								[self setFree: here.
  								 self storePointer: self freeChunkNextAddressIndex ofFreeChunk: lastLargeFree withValue: here].
  						 lastLargeFree := here]
  					ifFalse:
  						[self freeSmallObject: here]]].
  	highestObjects last: lastHighest.
  	highestObjectsWraps ~= 0 ifTrue:
  		[highestObjects first: (lastHighest + self wordSize >= highestObjects limit
  								ifTrue: [highestObjects start]
  								ifFalse: [lastHighest + self wordSize])].
  	lastLargeFree ~= 0 ifTrue:
  		[self storePointer: self freeChunkNextAddressIndex ofFreeChunk: lastLargeFree withValue: 0].
  	totalFreeOldSpace := self reverseSmallListHeads.
  	totalFreeOldSpace := totalFreeOldSpace + (self rebuildFreeTreeFrom: sortedFreeChunks).
  	self checkFreeSpace.
  	self touch: highestObjectsWraps!

Item was changed:
  ----- Method: SpurMemoryManager>>initializeFreeSpacePostLoad: (in category 'snapshot') -----
  initializeFreeSpacePostLoad: freeListObj
  	"Reinitialize the free list info.  The freeLists object needs to be swizzled
  	 because its neither a free, nor a pointer object.  Free objects have already
  	 been swizzled in adjustAllOopsBy:"
  	
  	self assert: (self numSlotsOf: freeListObj) = self numFreeLists.
  	self assert: (self formatOf: freeListObj) = (self wordSize = 4
  													ifTrue: [self firstLongFormat]
  													ifFalse: [self sixtyFourBitIndexableFormat]).
  	freeLists := self firstIndexableField: freeListObj.
  	freeListsMask := 0.
  	0 to: self numFreeLists - 1 do:
  		[:i|
  		(freeLists at: i) ~= 0 ifTrue:
  			[freeListsMask := freeListsMask bitOr: (1 << i).
+ 			 freeLists at: i put: (segmentManager swizzleObj: (freeLists at: i))]]!
- 			 freeLists at: i put: (segmentManager swizzleObj: (freeLists at: i))]].
- 	totalFreeOldSpace := self totalFreeListBytes.
- 	self checkFreeSpace!

Item was changed:
  ----- Method: SpurMemoryManager>>initializeNewSpaceVariables (in category 'gc - scavenging') -----
  initializeNewSpaceVariables
- 	startOfMemory ifNotNil: "true in bootstrap"
- 		[^self].
  	freeStart := scavenger eden start.
  	pastSpaceStart := scavenger pastSpace start.
  	scavengeThreshold := scavenger eden limit
  							- (scavenger edenBytes / 64)
  							- coInterpreter interpreterAllocationReserveBytes.
  	startOfMemory := scavenger pastSpace start min: scavenger futureSpace start.
  	self assert: startOfMemory < scavenger eden start.
  	self initSpaceForAllocationCheck: (self addressOf: scavenger eden)!

Item was changed:
  ----- Method: SpurMemoryManager>>initializeObjectMemory: (in category 'initialization') -----
  initializeObjectMemory: bytesToShift
  	"Initialize object memory variables at startup time. Assume endOfMemory is initially set (by the image-reading code) to the end of the last object in the image. Initialization redefines endOfMemory to be the end of the object allocation area based on the total available memory, but reserving some space for forwarding blocks."
  	"Assume: image reader initializes the following variables:
  		memory
  		memoryLimit
  		specialObjectsOop
  		lastHash
  	"
  	<inline: false>
  	| freeListObj |
  	"Catch mis-initializations leading to bad translations to C"
  	self assert: BaseHeaderSize = self baseHeaderSize.
+ 	self bootstrapping ifFalse:
+ 		[self
+ 			initSegmentBridgeWithBytes: self bridgeSize
+ 			at: endOfMemory - self bridgeSize].
- 
  	segmentManager adjustSegmentSwizzlesBy: bytesToShift.
  	"image may be at a different address; adjust oops for new location"
  	self adjustAllOopsBy: bytesToShift.
  	specialObjectsOop := segmentManager swizzleObj: specialObjectsOop.
  
  	"heavily used special objects"
  	nilObj		:= self splObj: NilObject.
  	falseObj	:= self splObj: FalseObject.
  	trueObj		:= self splObj: TrueObject.
  
  	"In Cog we insist that nil, true & false are next to each other (Cogit generates tighter
  	 conditional branch code as a result).  In addition, Spur places the free lists and
  	 class table root page immediately following them."
  	self assert: nilObj = newSpaceLimit.
  	self assert: falseObj = (self objectAfter: nilObj).
  	self assert: trueObj = (self objectAfter: falseObj).
  	freeListObj := self objectAfter: trueObj.
  	self reInitializeClassTablePostLoad: (self objectAfter: freeListObj).
  	markStack := self swizzleObjStackAt: MarkStackRootIndex.
  	weaklingStack := self swizzleObjStackAt: WeaklingStackRootIndex.
  	ephemeronQueue := self swizzleObjStackAt: EphemeronQueueRootIndex.
  
- 	segmentManager collapseSegmentsPostSwizzle.
  	self initializeFreeSpacePostLoad: freeListObj.
+ 	segmentManager collapseSegmentsPostSwizzle.
+ 	self computeFreeSpacePostSwizzle.
+ 	self bootstrapping ifFalse:
+ 		[self initializeNewSpaceVariables].
- 
- 	self initializeNewSpaceVariables.
  	self initializeOldSpaceFirstFree: freeOldSpaceStart. "initializes endOfMemory, freeStart"
+ 	segmentManager checkSegments.
  
  	"These defaults should depend on machine size; e.g. too small on a powerful laptop, too big on a Pi."
  	growHeadroom := 16*1024*1024.		"headroom when growing"
  	shrinkThreshold := 32*1024*1024.		"free space before shrinking"!

Item was changed:
  ----- Method: SpurMemoryManager>>initializeOldSpaceFirstFree: (in category 'free space') -----
  initializeOldSpaceFirstFree: startOfFreeOldSpace
  	<var: 'startOfFreeOldSpace' type: #usqLong>
+ 	| limit freeOldStart freeChunk |
+ 	<var: 'limit' type: #usqLong>
- 	| freeOldStart freeChunk |
  	<var: 'freeOldStart' type: #usqLong>
+ 	limit := endOfMemory - self bridgeSize.
+ 	limit > startOfFreeOldSpace ifTrue:
+ 		[totalFreeOldSpace := totalFreeOldSpace + (limit - startOfFreeOldSpace).
- 	
- 	endOfMemory > startOfFreeOldSpace ifTrue:
- 		[totalFreeOldSpace := totalFreeOldSpace + (endOfMemory - startOfFreeOldSpace).
  		 freeOldStart := startOfFreeOldSpace.
+ 		 [limit - freeOldStart >= (2 raisedTo: 32)] whileTrue:
- 		 [endOfMemory - freeOldStart >= (2 raisedTo: 32)] whileTrue:
  			[freeChunk := self freeChunkWithBytes: (2 raisedTo: 32) at: freeOldStart.
  			 freeOldStart := freeOldStart + (2 raisedTo: 32).
  			 self assert: freeOldStart = (self addressAfter: freeChunk)].
+ 		freeOldStart < limit ifTrue:
+ 			[freeChunk := self freeChunkWithBytes: limit - freeOldStart at: freeOldStart.
+ 			 self assert: (self addressAfter: freeChunk) = limit]].
- 		freeOldStart < endOfMemory ifTrue:
- 			[freeChunk := self freeChunkWithBytes: endOfMemory - freeOldStart at: freeOldStart.
- 			 self assert: (self addressAfter: freeChunk) = endOfMemory]].
  	freeOldSpaceStart := endOfMemory.
  	self checkFreeSpace!

Item was changed:
  ----- Method: SpurMemoryManager>>instanceAfter: (in category 'object enumeration') -----
  instanceAfter: objOop
  	| actualObj classIndex |
  	actualObj := objOop.
  	classIndex := self classIndexOf: objOop.
  
  	(self isInEden: objOop) ifTrue:
  		[[actualObj := self objectAfter: actualObj limit: freeStart.
  		  self oop: actualObj isLessThan: freeStart] whileTrue:
  			[classIndex = (self classIndexOf: actualObj) ifTrue:
  				[^actualObj]].
  		 actualObj := (self oop: pastSpaceStart isGreaterThan: scavenger pastSpace start)
  						ifTrue: [self objectStartingAt: scavenger pastSpace start]
  						ifFalse: [nilObj]].
  
  	(self isInSurvivorSpace: actualObj) ifTrue:
  		[[actualObj := self objectAfter: actualObj limit: pastSpaceStart.
  		  self oop: actualObj isLessThan: pastSpaceStart] whileTrue:
  			[classIndex = (self classIndexOf: actualObj) ifTrue:
  				[^actualObj]].
  		 actualObj := nilObj].
  
+ 	[actualObj := self objectAfter: actualObj limit: endOfMemory.
+ 	 self oop:actualObj isLessThan: endOfMemory] whileTrue:
- 	[actualObj := self objectAfter: actualObj limit: freeOldSpaceStart.
- 	 self oop:actualObj isLessThan: freeOldSpaceStart] whileTrue:
  		[classIndex = (self classIndexOf: actualObj) ifTrue:
  			[^actualObj]].
  	^nil!

Item was changed:
  ----- Method: SpurMemoryManager>>isInOldSpace: (in category 'object testing') -----
  isInOldSpace: address
  	^self
  		oop: address
  		isGreaterThanOrEqualTo: newSpaceLimit
+ 		andLessThan: endOfMemory!
- 		andLessThan: freeOldSpaceStart!

Item was removed:
- ----- Method: SpurMemoryManager>>isValidSegmentBridge: (in category 'segments') -----
- isValidSegmentBridge: objOop
- 	"Maybe this should be in SpurSegmentManager only"
- 	^(objOop = endOfMemory or: [self addressCouldBeObj: objOop])
- 	 and: [(self isSegmentBridge: objOop)
- 	 and: [self hasOverflowHeader: objOop]]!

Item was changed:
  ----- Method: SpurMemoryManager>>objectAfter: (in category 'object enumeration') -----
  objectAfter: objOop
  	<api>
  	"Object parsing.
  	1. all objects have at least a word following the header, for a forwarding pointer.
  	2. objects with an overflow size have a preceeing word with a saturated slotSize.  If the word following
  	    an object doesn't have a saturated size field it must be a single-header object.  If the word following
  	   does have a saturated slotSize it must be the overflow size word."
  	<inline: false>
  	(self oop: objOop isLessThan: newSpaceLimit) ifTrue:
  		[(self isInEden: objOop) ifTrue:
  			[^self objectAfter: objOop limit: freeStart].
  		 (self isInSurvivorSpace: objOop) ifTrue:
  			[^self objectAfter: objOop limit: pastSpaceStart].
  		 ^self objectAfter: objOop limit: scavenger futureSurvivorStart].
+ 	^self objectAfter: objOop limit: endOfMemory!
- 	^self objectAfter: objOop limit: freeOldSpaceStart!

Item was changed:
  ----- Method: SpurMemoryManager>>okayOop: (in category 'debug support') -----
  okayOop: signedOop
  	"Verify that the given oop is legitimate. Check address, header, and size but not class."
  
  	| oop classIndex fmt unusedBits unusedBitsInYoungObjects |
  	<var: #oop type: #usqInt>
  	<var: #unusedBits type: #usqLong>
  	oop := self cCoerce: signedOop to: #usqInt.
  
  	"address and size checks"
  	(self isImmediate: oop) ifTrue: [^true].
  	(self addressCouldBeObjWhileScavenging: oop) ifFalse:
  		[self error: 'oop is not a valid address'. ^false].
  
+ 	(self oop: (self addressAfter: oop) isLessThanOrEqualTo: endOfMemory) ifFalse:
- 	(self oop: (self addressAfter: oop) isLessThanOrEqualTo: freeOldSpaceStart) ifFalse:
  		[self error: 'oop size would make it extend beyond the end of memory'. ^false].
  
  	"header type checks"
  	(classIndex := self classIndexOf: oop) >= self firstClassIndexPun ifFalse:
  		[self error: 'oop is a free chunk, or bridge, not an object'. ^false].
  	((self rawNumSlotsOf: oop) = self numSlotsMask
  	 and: [(self rawNumSlotsOf: oop - self baseHeaderSize) ~= self numSlotsMask]) ifTrue:
  		[self error: 'oop header has overflow header word, but overflow word does not have a saturated numSlots field'. ^false].
  
  	"format check"
  	fmt := self formatOf: oop.
  	(fmt = 6) | (fmt = 8) ifTrue:
  		[self error: 'oop has an unknown format type'. ^false].
  	(fmt = self forwardedFormat) ~= (classIndex = self isForwardedObjectClassIndexPun) ifTrue:
  		[self error: 'oop has mis-matched format/classIndex fields; only one of them is the isForwarded value'. ^false].
  
  	"specific header bit checks"
  	unusedBits := (1 << self classIndexFieldWidth)
  				   | (1 << (self identityHashFieldWidth + 32)).
  	((self longLongAt: oop) bitAnd: unusedBits) ~= 0 ifTrue:
  		[self error: 'some unused header bits are set; should be zero'. ^false].
  
  	unusedBitsInYoungObjects := (1 << self greyBitShift)
  								   | (1 << self pinnedBitShift)
  								   | (1 << self rememberedBitShift).
  	((self longAt: oop) bitAnd: unusedBitsInYoungObjects) ~= 0 ifTrue:
  		[self error: 'some header bits unused in young objects are set; should be zero'. ^false].
  	^true
  !

Item was changed:
  ----- Method: SpurMemoryManager>>reverseBytesInMemory (in category 'snapshot') -----
  reverseBytesInMemory
+ 	self reverseBytesFrom: newSpaceLimit to: endOfMemory!
- 	self reverseBytesFrom: newSpaceLimit to: freeOldSpaceStart!

Item was changed:
  ----- Method: SpurSegmentInfo>>printOn: (in category 'printing') -----
  printOn: aStream
  	<doNotGenerate>
  	super printOn: aStream.
+ 	(self class instVarNames copyReplaceAll: #('segSize') with: #('segSize' 'segLimit')) do:
- 	self class instVarNames do:
  		[:name| | iv |
+ 		iv := self perform: name asSymbol.
- 		iv := self instVarNamed: name.
  		aStream space; nextPutAll: name; space; print: iv.
  		(iv isInteger and: [iv ~= 0]) ifTrue:
  			[aStream nextPut: $/.  iv storeOn: aStream base: 16]]!

Item was added:
+ ----- Method: SpurSegmentManager>>checkSegments (in category 'debug support') -----
+ checkSegments
+ 	self assert: numSegments >= 1.
+ 	0 to: numSegments - 1 do:
+ 		[:i|
+ 		self assert: (manager addressCouldBeObj: (segments at: i) segStart).
+ 		self assert: (self isValidSegmentBridge: (segments at: i) segLimit - manager baseHeaderSize)].
+ 	self assert: (segments at: numSegments - 1) segLimit = manager endOfMemory!

Item was changed:
  ----- Method: SpurSegmentManager>>collapseSegmentsPostSwizzle (in category 'snapshot') -----
  collapseSegmentsPostSwizzle
  	"The image has been loaded, old segments reconstructed, and the heap
  	 swizzled into a single contiguous segment.  Collapse the segments into one."
  	<inline: false>
  	canSwizzle := false.
  	self cCode: []
  		inSmalltalk:
  			[segments ifNil:
  				[self allocateOrExtendSegmentInfos]].
  	numSegments := 1.
  	(segments at: 0)
  		segStart: manager newSpaceLimit;
+ 		segSize: manager endOfMemory - manager newSpaceLimit.
+ 	manager bootstrapping ifTrue:
+ 		["finally plant a bridge at the end of the coalesced segment and cut back the
+ 		  manager's notion of the end of memory to immediately before the bridge."
+ 		 self assert: manager endOfMemory = (segments at: 0) segLimit.
+ 		 manager
+ 			initSegmentBridgeWithBytes: manager bridgeSize
+ 			at: manager endOfMemory - manager bridgeSize].
+ 	self assert: (self isValidSegmentBridge: manager endOfMemory - manager baseHeaderSize).
+ 	self assert: (manager numSlotsOfAny: manager endOfMemory - manager baseHeaderSize) = 0!
- 		segSize: manager endOfMemory + manager bridgeSize - manager newSpaceLimit.
- 	manager bootstrapping
- 		ifTrue:
- 			["finally plant a bridge at the end of the coalesced segment and cut back the
- 			  manager's notion of the end of memory to immediately before the bridge."
- 			 self assert: manager endOfMemory = ((segments at: 0) segLimit - manager bridgeSize).
- 			 manager initSegmentBridgeWithBytes: manager bridgeSize at: manager endOfMemory]
- 		ifFalse:
- 			[self assert: (manager isValidSegmentBridge: manager endOfMemory).
- 			 self assert: (manager numSlotsOfAny: manager endOfMemory) = 0]!

Item was changed:
  ----- Method: SpurSegmentManager>>initializeFromFreeChunks: (in category 'simulation only') -----
  initializeFromFreeChunks: freeChunks
  	"For testing, create a set of segments using the freeChunks as bridges."
  	numSegments := freeChunks size.
  	freeChunks do:
  		[:f|
  		manager initSegmentBridgeWithBytes: (manager bytesInObject: f) at: (manager startOfObject: f).
  		self assert: (manager isSegmentBridge: f)].
  	segments := (1 to: numSegments) collect:
  					[:i| | bridge start size |
  					bridge := freeChunks at: i.
  					start := i = 1
  								ifTrue: [manager newSpaceLimit]
  								ifFalse: [manager addressAfter: (freeChunks at: i - 1)].
  					size := bridge + manager baseHeaderSize - start.
  					SpurSegmentInfo new
  						segStart: start;
  						segSize: size;
  						yourself].
+ 	manager setEndOfMemory: segments last segLimit.
  	segments := CArrayAccessor on: segments.
+ 	freeChunks do:
+ 		[:bridge| self assert: (self isValidSegmentBridge: bridge)]!
- 	freeChunks allButLast do:
- 		[:bridge| self assert: (manager isValidSegmentBridge: bridge)]!

Item was added:
+ ----- Method: SpurSegmentManager>>isValidSegmentBridge: (in category 'testing') -----
+ isValidSegmentBridge: objOop
+ 	"bridges bridge the gaps between segments. They are the last object in each segment."
+ 	^(manager addressCouldBeObj: objOop)
+ 	 and: [(manager isSegmentBridge: objOop)
+ 	 and: [manager hasOverflowHeader: objOop]]!

Item was changed:
  ----- Method: SpurSegmentManager>>writeImageToFile: (in category 'snapshot') -----
  writeImageToFile: aBinaryStream
  	| total |
  	total := 0.
+ 	self assert: (segments at: numSegments - 1) segLimit = manager endOfMemory.
- 	self assert: (segments at: numSegments - 1) segLimit - manager bridgeSize = manager endOfMemory.
  	firstSegmentSize ifNotNil:
  		[self assert: firstSegmentSize = (segments at: 0) segSize].
  	0 to: numSegments - 1 do:
  		[:i| | nextSegSize |
  		nextSegSize := i = (numSegments - 1)
  							ifTrue: [0]
  							ifFalse: [(segments at: i + 1) segSize].
  		total := total + (self writeSegment: (self addressOf: (segments at: i))
  							nextSegmentSize: nextSegSize
  							toFile: aBinaryStream)].
  	^total!

Item was changed:
  ----- Method: SpurSegmentManager>>writeSegment:nextSegmentSize:toFile: (in category 'snapshot') -----
  writeSegment: aSpurSegmentInfo nextSegmentSize: nextSegSize toFile: aBinaryStream
  	<var: 'aSpurSegmentInfo' type: #'SpurSegmentInfo *'>
  	<var: 'aBinaryStream' type: #'FILE *'>
  	| bridge savedHeader nWritten |
  	<var: 'savedHeader' type: #usqLong>
  	bridge := aSpurSegmentInfo segLimit - manager baseHeaderSize.
  	"last seg may be beyond endOfMemory/freeOldSpaceStart"
+ 	self assert: (self isValidSegmentBridge: bridge).
- 	self assert: ((manager isValidSegmentBridge: bridge) or: [nextSegSize = 0]).
  	savedHeader := manager longLongAt: bridge.
  	manager longLongAt: bridge put: nextSegSize.
  	nWritten := self cCode:
  						[self
  							sq: aSpurSegmentInfo segStart asVoidPointer
  							Image: 1
  							File: aSpurSegmentInfo segSize
  							Write: aBinaryStream]
  					inSmalltalk:
  						[aBinaryStream
  							next: aSpurSegmentInfo segSize / 4
  							putAll: manager memory
  							startingAt: aSpurSegmentInfo segStart / 4 + 1.
  						 aSpurSegmentInfo segSize].
  	manager longLongAt: bridge put: savedHeader.
  	^nWritten!



More information about the Vm-dev mailing list