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

commits at source.squeak.org commits at source.squeak.org
Tue Nov 19 03:09:30 UTC 2013


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

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

Name: VMMaker.oscog-eem.515
Author: eem
Time: 18 November 2013, 7:06:41.755 pm
UUID: 168ec040-51cd-4d3d-9b60-7dc3a981beaa
Ancestors: VMMaker.oscog-eem.514

Make the Spur Cog VM compilable, marking the relevant
SpurMemMgr methods <api>, and implementing missing
CogObjectRepresentationForSpur methods.

Rename CogObjectRepresentation>>remapObj: to remapObject: to
avoid conflict with Objmem/SpurMemMgr>>remapObj:.

Add SpurMemMgr>>isYoungObject: and use it and isYoungObject:
appropriately.

Fix checkOkayFields: given that Spur objects don't directly refer to
classes.

Fix uninitialization of newTargetMethodOrNil & errorSelectorOrNil
in ceCPICMiss:receiver:.

Add an analysis routine and support to Cogit to check that indeed
super sends don't have their selector rewritten when linked.

Rewrite markLiteralsAndUnlinkIfUnmarkedSend:pc:method: &
markLiteralsAndUnlinkIfUnmarkedSendOrPushImplicit:pc:method:
so that markAndTraceLiteral: is only invoked with literal args and
cacheTagIsMarked: is only applied to cache tags.  This allows Spur
to answer true for cacheTagIsMarked:.

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

Item was changed:
  ----- Method: CoInterpreter>>checkOkayFields: (in category 'debug support') -----
  checkOkayFields: oop
  	"Check if the argument is an ok object.
  	 If this is a pointers object, check that its fields are all okay oops."
  
  	| hasYoung i fieldOop |
  	(oop = nil or: [oop = 0]) ifTrue: [ ^true ]. "?? eem 1/16/2013"
  	(objectMemory isIntegerObject: oop) ifTrue: [ ^true ].
  	(objectMemory checkOkayOop: oop) ifFalse: [ ^false ].
  	(objectMemory checkOopHasOkayClass: oop) ifFalse: [ ^false ].
  	((objectMemory isPointersNonImm: oop) or: [objectMemory isCompiledMethod: oop]) ifFalse: [ ^true ].
+ 	hasYoung := objectMemory hasSpurMemoryManagerAPI not
+ 				  and: [objectMemory isYoungObject: (objectMemory fetchClassOfNonImm: oop)].
- 	hasYoung := objectMemory isYoung: (objectMemory fetchClassOfNonImm: oop).
  	(objectMemory isCompiledMethod: oop)
  		ifTrue:
  			[i := (self literalCountOf: oop) + LiteralStart - 1]
  		ifFalse:
  			[(objectMemory isContext: oop)
  				ifTrue: [i := CtxtTempFrameStart + (self fetchStackPointerOf: oop) - 1]
  				ifFalse: [i := (objectMemory lengthOf: oop) - 1]].
  	[i >= 0] whileTrue:
  		[fieldOop := objectMemory fetchPointer: i ofObject: oop.
  		(objectMemory isNonIntegerObject: fieldOop) ifTrue:
  			[(i = 0 and: [objectMemory isCompiledMethod: oop])
  				ifTrue:
  					[(cogMethodZone methodFor: (self pointerForOop: fieldOop)) = 0 ifTrue:
  						[self print: 'method '; printHex: oop; print: ' has an invalid cog method reference'.
  						^false]]
  				ifFalse:
  					[hasYoung := hasYoung or: [objectMemory isYoung: fieldOop].
  					(objectMemory checkOkayOop: fieldOop) ifFalse: [ ^false ].
  					(self checkOopHasOkayClass: fieldOop) ifFalse: [ ^false ]]].
  		i := i - 1].
  	hasYoung ifTrue:
  		[^objectMemory checkOkayYoungReferrer: oop].
  	^true!

Item was changed:
  ----- Method: CoInterpreter>>mapStackPages (in category 'object memory support') -----
  mapStackPages
  	<inline: false>
  	<var: #thePage type: #'StackPage *'>
  	<var: #theSP type: #'char *'>
  	<var: #theFP type: #'char *'>
  	<var: #frameRcvrOffset type: #'char *'>
  	<var: #callerFP type: #'char *'>
  	<var: #theIPPtr type: #'char *'>
  	0 to: numStackPages - 1 do:
  		[:i| | thePage theSP theFP frameRcvrOffset callerFP theIPPtr theIP oop |
  		thePage := stackPages stackPageAt: i.
  		thePage isFree ifFalse:
  			[theSP := thePage headSP.
  			 theFP := thePage  headFP.
  			 "Skip the instruction pointer on top of stack of inactive pages."
  			 thePage = stackPage
  				ifTrue: [theIPPtr := ((self isMachineCodeFrame: theFP)
  									or: [(self iframeSavedIP: theFP) = 0])
  										ifTrue: [0]
  										ifFalse: [theFP + FoxIFSavedIP]]
  				ifFalse:
  					[theIPPtr := theSP.
  					 theSP := theSP + BytesPerWord].
  			[self assert: (thePage addressIsInPage: theFP).
  			 self assert: (thePage addressIsInPage: theSP).
  			 self assert: (theIPPtr = 0 or: [thePage addressIsInPage: theIPPtr]).
  			 frameRcvrOffset := self frameReceiverOffset: theFP.
  	 		  [theSP <= frameRcvrOffset] whileTrue:
  				[oop := stackPages longAt: theSP.
  				 (objectMemory shouldRemapOop: oop) ifTrue:
  					[stackPages longAt: theSP put: (objectMemory remapObj: oop)].
  				 theSP := theSP + BytesPerWord].
  			 (self frameHasContext: theFP) ifTrue:
  				[(objectMemory shouldRemapObj: (self frameContext: theFP)) ifTrue:
  					[stackPages
  						longAt: theFP + FoxThisContext
  						put: (objectMemory remapObj: (self frameContext: theFP))].
+ 				 "forwarding scheme in SqueakV3 obj rep makes this hard to check."
+ 				 objectMemory hasSpurMemoryManagerAPI ifTrue:
+ 					[self assert: ((self isMarriedOrWidowedContext: (self frameContext: theFP))
+ 								and: [(self frameOfMarriedContext: (self frameContext: theFP)) = theFP])]].
- 				 self assert: ((self isMarriedOrWidowedContext: (self frameContext: theFP))
- 							and: [(self frameOfMarriedContext: (self frameContext: theFP)) = theFP])].
  			(self isMachineCodeFrame: theFP) ifFalse:
  				[(objectMemory shouldRemapObj: (self iframeMethod: theFP)) ifTrue:
  					[theIPPtr ~= 0 ifTrue:
  						[theIP := stackPages longAt: theIPPtr.
  						 theIP = cogit ceReturnToInterpreterPC
  							ifTrue:
  								[self assert: (self iframeSavedIP: theFP) > (self iframeMethod: theFP).
  								 theIPPtr := theFP + FoxIFSavedIP.
  								 theIP := stackPages longAt: theIPPtr]
  							ifFalse:
  								[self assert: theIP > (self iframeMethod: theFP)].
  						 theIP := theIP - (self iframeMethod: theFP)].
  					 stackPages
  						longAt: theFP + FoxMethod
  						put: (objectMemory remapObj: (self iframeMethod: theFP)).
  					 theIPPtr ~= 0 ifTrue:
  						[stackPages longAt: theIPPtr put: theIP + (self iframeMethod: theFP)]]].
  			 (callerFP := self frameCallerFP: theFP) ~= 0] whileTrue:
  				[theSP := (theIPPtr := theFP + FoxCallerSavedIP) + BytesPerWord.
  				 theFP := callerFP].
  			 theSP := theFP + FoxCallerSavedIP + BytesPerWord.
  			 [theSP <= thePage baseAddress] whileTrue:
  				[oop := stackPages longAt: theSP.
  				 (objectMemory shouldRemapOop: oop) ifTrue:
  					[stackPages longAt: theSP put: (objectMemory remapObj: oop)].
  				 theSP := theSP + BytesPerWord]]]!

Item was added:
+ ----- Method: CogObjectRepresentation>>allYoungObjectsAgeInFullGC (in category 'garbage collection') -----
+ allYoungObjectsAgeInFullGC
+ 	^self subclassResponsibility!

Item was added:
+ ----- Method: CogObjectRepresentation>>markAndTraceLiteral: (in category 'garbage collection') -----
+ markAndTraceLiteral: literal
+ 	self subclassResponsibility!

Item was added:
+ ----- Method: CogObjectRepresentation>>markAndTraceLiteralIfYoung: (in category 'garbage collection') -----
+ markAndTraceLiteralIfYoung: literal
+ 	self subclassResponsibility!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>allYoungObjectsAgeInFullGC (in category 'garbage collection') -----
+ allYoungObjectsAgeInFullGC
+ 	^false!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>cacheTagIsMarked: (in category 'garbage collection') -----
+ cacheTagIsMarked: cacheTag
+ 	"Answer if the cacheTag is not unmarked, i.e. answer true for compact class
+ 	 indices and immediates; only answer false for unmarked objects.  In Spur
+ 	 linked send cache tags are class indices so effectively they're always marked."
+ 	^true!

Item was changed:
+ ----- Method: CogObjectRepresentationForSpur>>couldBeObject: (in category 'garbage collection') -----
+ couldBeObject: literal
+ 	^objectMemory isNonImmediate: literal!
- ----- Method: CogObjectRepresentationForSpur>>couldBeObject: (in category 'debug support') -----
- couldBeObject: oop
- 	^objectMemory addressCouldBeObj: oop!

Item was changed:
+ ----- Method: CogObjectRepresentationForSpur>>inlineCacheTagIsYoung: (in category 'garbage collection') -----
+ inlineCacheTagIsYoung: cacheTag
+ 	"Since all cache tags in Spur are class indices none of
+ 	 them are young or have to be updated in a scavenge."
- ----- Method: CogObjectRepresentationForSpur>>inlineCacheTagIsYoung: (in category 'in-line cacheing') -----
- inlineCacheTagIsYoung: anInteger
- 	"classIndices are not objects, heh, heh, heh..."
  	^false!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>markAndTraceLiteral: (in category 'garbage collection') -----
+ markAndTraceLiteral: literal
+ 	(self couldBeObject: literal) ifTrue:
+ 		[self assert: (objectMemory addressCouldBeObj: literal).
+ 		 objectMemory markAndTrace: literal]!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>markAndTraceLiteralIfYoung: (in category 'garbage collection') -----
+ markAndTraceLiteralIfYoung: literal
+ 	self shouldNotImplement.  "sumpin' wrong surely ;-)"
+ 	((self couldBeObject: literal)
+ 	 and: [objectMemory isYoungObject: literal]) ifTrue:
+ 		[self assert: (objectMemory addressCouldBeObj: literal).
+ 		 objectMemory markAndTrace: literal]!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>remapObject: (in category 'garbage collection') -----
+ remapObject: objOop
+ 	^(objectMemory shouldRemapObj: objOop)
+ 		ifTrue: [objectMemory remapObj: objOop]
+ 		ifFalse: [objOop]!

Item was added:
+ ----- Method: CogObjectRepresentationForSpur>>remapOop: (in category 'garbage collection') -----
+ remapOop: objOop
+ 	^(objectMemory shouldRemapOop: objOop)
+ 		ifTrue: [objectMemory remapObj: objOop]
+ 		ifFalse: [objOop]!

Item was changed:
  ----- Method: CogObjectRepresentationForSqueakV3>>couldBeObject: (in category 'garbage collection') -----
  couldBeObject: oop
+ 	"Note this version filters-out compact class indices via the >= nilObj clause"
  	^(objectMemory isNonIntegerObject: oop)
  	  and: [self oop: oop isGreaterThanOrEqualTo: objectMemory nilObject]!

Item was changed:
  ----- Method: CogObjectRepresentationForSqueakV3>>markAndTraceLiteralIfYoung: (in category 'garbage collection') -----
  markAndTraceLiteralIfYoung: literal
  	((self couldBeObject: literal)
+ 	 and: [objectMemory isYoungObject: literal]) ifTrue:
- 	 and: [objectMemory isYoung: literal]) ifTrue:
  		[self assert: (objectMemory addressCouldBeObj: literal).
  		 objectMemory markAndTrace: literal]!

Item was removed:
- ----- Method: CogObjectRepresentationForSqueakV3>>remapObj: (in category 'garbage collection') -----
- remapObj: oop
- 	^objectMemory remap: oop!

Item was added:
+ ----- Method: CogObjectRepresentationForSqueakV3>>remapObject: (in category 'garbage collection') -----
+ remapObject: oop
+ 	^objectMemory remap: oop!

Item was changed:
  ----- Method: Cogit>>annotate:objRef: (in category 'method map') -----
  annotate: abstractInstruction objRef: anOop
  	<var: #abstractInstruction type: #'AbstractInstruction *'>
  	<returnTypeC: #'AbstractInstruction *'>
  	(objectRepresentation shouldAnnotateObjectReference: anOop) ifTrue:
+ 		[(objectMemory isYoungObject: anOop) ifTrue:
- 		[(objectMemory isYoung: anOop) ifTrue:
  			[hasYoungReferent := true].
  		^self annotate: abstractInstruction with: IsObjectReference].
  	^abstractInstruction!

Item was changed:
  ----- Method: Cogit>>ceCPICMiss:receiver: (in category 'in-line cacheing') -----
  ceCPICMiss: cPIC receiver: receiver
  	"Code entry closed PIC miss.  A send has fallen
  	 through a closed (finite) polymorphic inline cache.
  	 Either extend it or patch the send site to an open PIC.
  	 The stack looks like:
  			receiver
  			args
  	  sp=>	sender return address"
  	<var: #cPIC type: #'CogMethod *'>
  	<api>
  	| outerReturn newTargetMethodOrNil errorSelectorOrNil cacheTag result |
  	self cCode: ''
  		inSmalltalk:
  			[cPIC isInteger ifTrue:
  				[^self ceCPICMiss: (self cogMethodSurrogateAt: cPIC) receiver: receiver]].
  	outerReturn := coInterpreter stackTop.
+ 	cPIC cPICNumCases < numPICCases
+ 		ifTrue:
+ 			[self lookup: cPIC selector
+ 				for: receiver
+ 				methodAndErrorSelectorInto:
+ 					[:method :errsel|
+ 					newTargetMethodOrNil := method.
+ 					errorSelectorOrNil := errsel]]
+ 		ifFalse: [newTargetMethodOrNil := errorSelectorOrNil := nil].
- 	cPIC cPICNumCases < numPICCases ifTrue:
- 		[self lookup: cPIC selector
- 			for: receiver
- 			methodAndErrorSelectorInto:
- 				[:method :errsel|
- 				newTargetMethodOrNil := method.
- 				errorSelectorOrNil := errsel]].
  	"We assume lookupAndCog:for: will *not* reclaim the method zone"
  	self assert: outerReturn = coInterpreter stackTop.
  	cacheTag := objectRepresentation inlineCacheTagForInstance: receiver.
  	(cPIC cPICNumCases >= numPICCases
  	 or: [(errorSelectorOrNil notNil and: [errorSelectorOrNil ~= SelectorDoesNotUnderstand])
  	 or: [(objectRepresentation inlineCacheTagIsYoung: cacheTag)
  	 or: [newTargetMethodOrNil isNil
  	 or: [objectMemory isYoung: newTargetMethodOrNil]]]]) ifTrue:
  		[result := self patchToOpenPICFor: cPIC selector
  					numArgs: cPIC cmNumArgs
  					receiver: receiver.
  		 self assert: result not. "If patchToOpenPICFor:.. returns we're out of code memory"
  		 ^coInterpreter ceSendFromInLineCacheMiss: cPIC].
  	"Now extend the PIC with the new case."
  	self cogExtendPIC: cPIC
  		CaseNMethod: newTargetMethodOrNil
  		tag: cacheTag
  		isMNUCase: errorSelectorOrNil = SelectorDoesNotUnderstand.
  	"Jump back into the pic at its entry in case this is an MNU."
  	coInterpreter
  		executeCogMethodFromLinkedSend: cPIC
  		withReceiver: receiver
  		andCacheTag: (backEnd inlineCacheTagAt: outerReturn).
  	"NOTREACHED"
  	^nil!

Item was changed:
  ----- Method: Cogit>>checkIntegrityOfObjectReferencesInCode: (in category 'debugging') -----
  checkIntegrityOfObjectReferencesInCode: fullGCFlag
  	<api>
  	"Answer if all references to objects in machine-code are valid."	
  	| cogMethod ok count |
  	<var: #cogMethod type: #'CogMethod *'>
  	cogMethod := self cCoerceSimple: methodZoneBase to: #'CogMethod *'.
  	ok := true.
  	[cogMethod < methodZone limitZony] whileTrue:
  		[cogMethod cmType ~= CMFree ifTrue:
  			[cogMethod cmRefersToYoung ifTrue:
  				[(count := methodZone occurrencesInYoungReferrers: cogMethod) ~= 1 ifTrue:
  					[coInterpreter print: 'young referrer CM '; printHex: cogMethod asInteger.
  					 count = 0
  						ifTrue: [coInterpreter print: ' is not in youngReferrers'; cr]
  						ifFalse: [coInterpreter print: ' is in youngReferrers '; printNum: count; print: ' times!!'; cr].
  					 ok := false]].
  			 (objectRepresentation checkValidObjectReference: cogMethod selector) ifFalse:
  				[coInterpreter print: 'object leak in CM '; printHex: cogMethod asInteger; print: ' selector'; cr.
  				 ok := false].
  			 cogMethod cmType = CMMethod
  				ifTrue:
  					[self assert: cogMethod objectHeader = objectMemory nullHeaderForMachineCodeMethod.
  					 (objectRepresentation checkValidObjectReference: cogMethod methodObject) ifFalse:
  						[coInterpreter print: 'object leak in CM '; printHex: cogMethod asInteger; print: ' methodObject'; cr.
  						 ok := false].
  					 (self mapFor: cogMethod
  						 performUntil: #checkIfValidObjectRef:pc:cogMethod:
  						 arg: cogMethod asInteger) ~= 0
  							ifTrue: [ok := false].
  					 fullGCFlag ifFalse:
+ 						[(((objectMemory isYoungObject: cogMethod methodObject)
- 						[(((objectMemory isYoung: cogMethod methodObject)
  						    or: [objectMemory isYoung: cogMethod selector])
  						   and: [cogMethod cmRefersToYoung not]) ifTrue:
  							[coInterpreter print: 'CM '; printHex: cogMethod asInteger; print: ' refers to young but not marked as such'; cr.
  							 ok := false]]]
  				ifFalse:
  					[cogMethod cmType = CMClosedPIC
  						ifTrue:
  							[(self checkValidObjectReferencesInClosedPIC: cogMethod) ifFalse:
  								[ok := false]]
  						ifFalse:
  							[cogMethod cmType = CMOpenPIC
  								ifTrue:
  									[(self mapFor: cogMethod
  										performUntil: #checkIfValidObjectRef:pc:cogMethod:
  										arg: cogMethod asInteger) ~= 0
  											ifTrue: [ok := false]]]]].
  		cogMethod := methodZone methodAfter: cogMethod].
  	^ok!

Item was changed:
  ----- Method: Cogit>>compileCPIC:Case0:Case1Method:tag:isMNUCase:numArgs: (in category 'in-line cacheing') -----
  compileCPIC: cPIC Case0: case0CogMethod Case1Method: case1Method tag: case1Tag isMNUCase: isMNUCase numArgs: numArgs
  	"Compile the code for a two-case PIC for case0CogMethod and  case1Method,case1Tag.
  	 The tag for case0CogMethod is at the send site and so doesn't need to be generated.
  	 case1Method may be any of
  		- a Cog method; jump to its unchecked entry-point
  		- a CompiledMethod; jump to the ceInterpretFromPIC trampoline
  		- nil; call ceMNUFromPIC"
  	<var: #cPIC type: #'CogMethod *'>
  	| operand targetEntry jumpNext |
  	<var: #case0CogMethod type: #'CogMethod *'>
  	<var: #targetEntry type: #'void *'>
  	<var: #jumpNext type: #'AbstractInstruction *'>
  	self assert: case1Method notNil.
  	self compilePICProlog: numArgs.
  	self assert: (objectRepresentation inlineCacheTagIsYoung: case1Tag) not.
  	(isMNUCase not
  	 and: [coInterpreter methodHasCogMethod: case1Method])
  		ifTrue:
  			[operand := 0.
  			 targetEntry := ((coInterpreter cogMethodOf: case1Method) asInteger + cmNoCheckEntryOffset) asVoidPointer]
  		ifFalse:
+ 			[self assert: (case1Method isNil or: [(objectMemory isYoungObject: case1Method) not]).
- 			[self assert: (case1Method isNil or: [(objectMemory isYoung: case1Method) not]).
  			 operand := case1Method.
  			 targetEntry := case1Method isNil ifTrue: [mnuCall] ifFalse: [interpretCall]].
  
  	jumpNext := self compileCPICEntry.
  	self MoveCw: 0 R: SendNumArgsReg.
  	self JumpLong: case0CogMethod asInteger + cmNoCheckEntryOffset.
  	endCPICCase0 := self CmpCw: case1Tag R: TempReg.
  	jumpNext jmpTarget: endCPICCase0.
  	self MoveCw: operand R: SendNumArgsReg.
  	self JumpLongZero: (isMNUCase ifTrue: [mnuCall] ifFalse: [targetEntry]) asInteger.
  	endCPICCase1 := self MoveCw: cPIC asInteger R: ClassReg.
  	self JumpLong: (self cPICMissTrampolineFor: numArgs).
  	^0
  !

Item was changed:
  ----- Method: Cogit>>compileCogMethod: (in category 'compile abstract instructions') -----
  compileCogMethod: selector
  	<returnTypeC: #'CogMethod *'>
  	| numBytecodes numBlocks numCleanBlocks result extra |
+ 	hasYoungReferent := (objectMemory isYoungObject: methodObj)
- 	hasYoungReferent := (objectMemory isYoung: methodObj)
  						  or: [objectMemory isYoung: selector].
  	methodOrBlockNumArgs := coInterpreter argumentCountOf: methodObj.
  	inBlock := false.
  	primInvokeLabel := nil.
  	postCompileHook := nil.
  	maxLitIndex := -1.
  	extra := ((primitiveIndex := coInterpreter primitiveIndexOf: methodObj) > 0
  			and: [(coInterpreter isQuickPrimitiveIndex: primitiveIndex) not])
  				ifTrue: [30]
  				ifFalse: [10].
  	initialPC := coInterpreter startPCOfMethod: methodObj.
  	"initial estimate.  Actual endPC is determined in scanMethod."
  	endPC := (coInterpreter isQuickPrimitiveIndex: primitiveIndex)
  					ifTrue: [initialPC - 1]
  					ifFalse: [objectMemory byteLengthOf: methodObj].
  	numBytecodes := endPC - initialPC + 1.
  	self allocateOpcodes: (numBytecodes + extra) * 10
  		bytecodes: numBytecodes
  		ifFail: [^coInterpreter cCoerceSimple: MethodTooBig to: #'CogMethod *'].
  	(numBlocks := self scanMethod) < 0 ifTrue:
  		[^coInterpreter cCoerceSimple: numBlocks to: #'CogMethod *'].
  	numCleanBlocks := self scanForCleanBlocks.
  	self allocateBlockStarts: numBlocks + numCleanBlocks.
  	blockCount := 0.
  	numCleanBlocks > 0 ifTrue:
  		[self addCleanBlockStarts].
  	self maybeAllocAndInitCounters.
  	blockEntryLabel := nil.
  	methodLabel dependent: nil.
  	(result := self compileEntireMethod) < 0 ifTrue:
  		[^coInterpreter cCoerceSimple: result to: #'CogMethod *'].
  	^self generateCogMethod: selector!

Item was added:
+ ----- Method: Cogit>>linkedSuperSendCacheTags (in category 'analysis') -----
+ linkedSuperSendCacheTags
+ 	"An example; answer the cache tags for linked super sends.  They should all be
+ 	 selectors because super sends don't have their cache tag rewritten when linked."
+ 	<doNotGenerate>
+ 	| cacheTags |
+ 	cacheTags := Set new.
+ 	methodZone methodsDo:
+ 		[:m|
+ 		 m cmType = CMMethod ifTrue:
+ 			[self sendSitesIn: m do:
+ 				[:a :mcpc| | entryPoint |
+ 				 entryPoint := backEnd callTargetFromReturnAddress: mcpc.
+ 				 entryPoint > methodZoneBase ifTrue:
+ 					[self offsetAndSendTableFor: entryPoint
+ 						annotation: a
+ 						into:
+ 							[:off :table|
+ 							 off = cmNoCheckEntryOffset ifTrue:
+ 								[cacheTags add: (backEnd inlineCacheTagAt: mcpc)]]]]]].
+ 	^cacheTags!

Item was changed:
  ----- Method: Cogit>>mapObjectReferencesInGeneratedRuntime (in category 'garbage collection') -----
  mapObjectReferencesInGeneratedRuntime
  	"Update all references to objects in the generated runtime."
  	0 to: runtimeObjectRefIndex - 1 do:
  		[:i| | mcpc literal mappedLiteral |
  		 mcpc := objectReferencesInRuntime at: i.
  		 literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
+ 		 mappedLiteral := objectRepresentation remapObject: literal.
- 		 mappedLiteral := objectRepresentation remapObj: literal.
  		 mappedLiteral ~= literal ifTrue:
  			[backEnd storeLiteral: mappedLiteral beforeFollowingAddress: mcpc.
  			 codeModified := true]]!

Item was changed:
  ----- Method: Cogit>>markLiteralsAndUnlinkIfUnmarkedSend:pc:method: (in category 'garbage collection') -----
  markLiteralsAndUnlinkIfUnmarkedSend: annotation pc: mcpc method: cogMethod
  	"Mark and trace literals.  Unlink sends that have unmarked cache tags or targets."
  	<var: #mcpc type: #'char *'>
  	| literal cacheTag cacheTagMarked entryPoint targetMethod offset sendTable unlinkedRoutine |
  	<var: #targetMethod type: #'CogMethod *'>
  	<var: #sendTable type: #'sqInt *'>
  	annotation = IsObjectReference ifTrue:
  		[literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
  		 objectRepresentation markAndTraceLiteral: literal].
  	(self isSendAnnotation: annotation) ifTrue:
  		[cacheTag := backEnd inlineCacheTagAt: mcpc asInteger.
- 		 cacheTagMarked := objectRepresentation cacheTagIsMarked: cacheTag.
- 		 objectRepresentation markAndTraceLiteral: cacheTag.
  		 entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
+ 		 entryPoint > methodZoneBase
+ 			ifTrue: "It's a linked send."
+ 				[self
+ 					offsetAndSendTableFor: entryPoint
+ 					annotation: annotation
+ 					into: [:off :table| offset := off. sendTable := table].
+ 				targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
+ 				offset = cmNoCheckEntryOffset
+ 					ifTrue: [objectRepresentation markAndTraceLiteral: cacheTag. "cacheTag is selector"
+ 							cacheTagMarked := true]
+ 					ifFalse: [cacheTagMarked := objectRepresentation cacheTagIsMarked: cacheTag].
+ 				(cacheTagMarked not
+ 				 or: [self markAndTraceOrFreeCogMethod: targetMethod
+ 						firstVisit: targetMethod asUnsignedInteger > mcpc asUnsignedInteger]) ifTrue:
+ 					["Either the cacheTag is unmarked (e.g. new class) or the target
+ 					  has been freed (because it is unmarked) so unlink the send."
+ 					 unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
+ 					 backEnd
+ 						rewriteInlineCacheAt: mcpc asInteger
+ 						tag: targetMethod selector
+ 						target: unlinkedRoutine.
+ 					 codeModified := true.
+ 					 objectRepresentation markAndTraceLiteral: targetMethod selector]]
+ 			ifFalse:
+ 				[objectRepresentation markAndTraceLiteral: cacheTag]].
- 		 entryPoint > methodZoneBase ifTrue: "It's a linked send."
- 			[self
- 				offsetAndSendTableFor: entryPoint
- 				annotation: annotation
- 				into: [:off :table| offset := off. sendTable := table].
- 			targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
- 			(cacheTagMarked not
- 			 or: [self markAndTraceOrFreeCogMethod: targetMethod firstVisit: targetMethod asUnsignedInteger > mcpc asUnsignedInteger]) ifTrue:
- 				["Either the cacheTag is unmarked (e.g. new class) or the target
- 				  has been freed (because it is unmarked) so unlink the send."
- 				 unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
- 				 backEnd
- 					rewriteInlineCacheAt: mcpc asInteger
- 					tag: targetMethod selector
- 					target: unlinkedRoutine.
- 				 codeModified := true.
- 				 objectRepresentation markAndTraceLiteral: targetMethod selector]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>markLiteralsAndUnlinkIfUnmarkedSendOrPushImplicit:pc:method: (in category 'garbage collection') -----
  markLiteralsAndUnlinkIfUnmarkedSendOrPushImplicit: annotation pc: mcpc method: cogMethod
  	<option: #NewspeakVM>
  	"Mark and trace literals.  Unlink sends that have unmarked cache tags or targets."
  	<var: #mcpc type: #'char *'>
  	| literal cacheTag cacheTagMarked entryPoint targetMethod offset sendTable unlinkedRoutine |
  	<var: #targetMethod type: #'CogMethod *'>
  	<var: #sendTable type: #'sqInt *'>
  	annotation = IsObjectReference ifTrue:
  		[literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
  		 objectRepresentation markAndTraceLiteral: literal].
  	(self isSendAnnotation: annotation) ifTrue:
  		[entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 cacheTag := backEnd inlineCacheTagAt: mcpc asInteger.
  		 cacheTagMarked := objectRepresentation cacheTagIsMarked: cacheTag.
- 		 objectRepresentation markAndTraceLiteral: cacheTag.
  		 entryPoint = ceImplicitReceiverTrampoline
  			ifTrue:
  				[| classpc mixinpc class mixin |
+ 				 objectRepresentation markAndTraceLiteral: cacheTag.  "cacheTag is selector"
- 				 self assert: cacheTagMarked.  "cacheTag is selector"
  				 classpc := mcpc asInteger + backEnd jumpShortByteSize.
  				 mixinpc := mcpc asInteger + backEnd jumpShortByteSize + BytesPerOop.
  				 class := backEnd unalignedLongAt: classpc.
  				 class ~= 0
  					ifTrue:
  						[self assert: (objectMemory addressCouldBeObj: class).
  						 (objectRepresentation cacheTagIsMarked: class)
  							ifTrue:
  								[(mixin := backEnd unalignedLongAt: mixinpc) ~= 0 ifTrue:
  									[objectRepresentation markAndTraceLiteral: mixin]]
  							ifFalse:
  								[backEnd
  									unalignedLongAt: classpc put: 0;
  									unalignedLongAt: mixinpc put: 0.
  								 codeModified := true]]
  					ifFalse:
  						[self assert: (backEnd unalignedLongAt: mixinpc) = 0]]
  			ifFalse:
+ 				[entryPoint > methodZoneBase
+ 					ifTrue: "It's a linked send."
+ 						[self
+ 							offsetAndSendTableFor: entryPoint
+ 							annotation: annotation
+ 							into: [:off :table| offset := off. sendTable := table].
+ 						offset = cmNoCheckEntryOffset
+ 							ifTrue: [objectRepresentation markAndTraceLiteral: cacheTag. "cacheTag is selector"
+ 									cacheTagMarked := true]
+ 							ifFalse: [cacheTagMarked := objectRepresentation cacheTagIsMarked: cacheTag].
+ 						targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
+ 						(cacheTagMarked not
+ 						 or: [self markAndTraceOrFreeCogMethod: targetMethod firstVisit: targetMethod asUnsignedInteger > mcpc asUnsignedInteger]) ifTrue:
+ 							["Either the cacheTag is unmarked (e.g. new class) or the target
+ 							  has been freed (because it is unmarked) so unlink the send."
+ 							 unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
+ 							 backEnd
+ 								rewriteInlineCacheAt: mcpc asInteger
+ 								tag: targetMethod selector
+ 								target: unlinkedRoutine.
+ 							 codeModified := true.
+ 							 objectRepresentation markAndTraceLiteral: targetMethod selector]]
+ 					ifFalse:
+ 						[objectRepresentation markAndTraceLiteral: cacheTag]]].
- 				[entryPoint > methodZoneBase ifTrue: "It's a linked send."
- 					[self
- 						offsetAndSendTableFor: entryPoint
- 						annotation: annotation
- 						into: [:off :table| offset := off. sendTable := table].
- 					targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
- 					(cacheTagMarked not
- 					 or: [self markAndTraceOrFreeCogMethod: targetMethod firstVisit: targetMethod asUnsignedInteger > mcpc asUnsignedInteger]) ifTrue:
- 						["Either the cacheTag is unmarked (e.g. new class) or the target
- 						  has been freed (because it is unmarked) so unlink the send."
- 						 unlinkedRoutine := sendTable at: (targetMethod cmNumArgs min: NumSendTrampolines - 1).
- 						 backEnd
- 							rewriteInlineCacheAt: mcpc asInteger
- 							tag: targetMethod selector
- 							target: unlinkedRoutine.
- 						 codeModified := true.
- 						 objectRepresentation markAndTraceLiteral: targetMethod selector]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>remapIfObjectRef:pc:hasYoung: (in category 'garbage collection') -----
  remapIfObjectRef: annotation pc: mcpc hasYoung: hasYoungPtr
  	<var: #mcpc type: #'char *'>
  	<var: #targetMethod type: #'CogMethod *'>
  	annotation = IsObjectReference ifTrue:
  		[| literal mappedLiteral |
  		 literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
  		 (objectRepresentation couldBeObject: literal) ifTrue:
+ 			[mappedLiteral := objectRepresentation remapObject: literal.
- 			[mappedLiteral := objectRepresentation remapObj: literal.
  			 literal ~= mappedLiteral ifTrue:
  				[backEnd storeLiteral: mappedLiteral beforeFollowingAddress: mcpc asInteger.
  				 codeModified := true].
  			 (hasYoungPtr ~= 0
  			  and: [objectMemory isYoung: mappedLiteral]) ifTrue:
  				[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true]]].
  	(self isSendAnnotation: annotation) ifTrue:
  		[| cacheTag mappedCacheTag |
  		 cacheTag := backEnd inlineCacheTagAt: mcpc asInteger.
  		 (objectRepresentation couldBeObject: cacheTag) ifTrue:
+ 			[mappedCacheTag := objectRepresentation remapObject: cacheTag.
- 			[mappedCacheTag := objectRepresentation remapObj: cacheTag.
  			 cacheTag ~= mappedCacheTag ifTrue:
  				[backEnd rewriteInlineCacheTag: mappedCacheTag at: mcpc asInteger.
  				 codeModified := true].
  			 (hasYoungPtr ~= 0
  			  and: [objectMemory isYoung: mappedCacheTag]) ifTrue:
  				[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true]].
  		 hasYoungPtr ~= 0 ifTrue:
  			[| entryPoint offset targetMethod |
  			 "Since the unlinking routines may rewrite the cacheTag to the send's selector, and
  			  since they don't have the cogMethod to hand and can't add it to youngReferrers,
  			  the method must remain in youngReferrers if the targetMethod's selector is young."
  			 entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  			 entryPoint > methodZoneBase ifTrue: "It's a linked send."
  				[offset := (entryPoint bitAnd: entryPointMask) = checkedEntryAlignment
  							ifTrue: [cmEntryOffset]
  							ifFalse: [cmNoCheckEntryOffset].
  				targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
  				(objectMemory isYoung: targetMethod selector) ifTrue:
  					[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true]]]].
  	^0 "keep scanning"!

Item was changed:
  ----- Method: Cogit>>remapNSIfObjectRef:pc:hasYoung: (in category 'garbage collection') -----
  remapNSIfObjectRef: annotation pc: mcpc hasYoung: hasYoungPtr
  	<option: #NewspeakVM>
  	<var: #mcpc type: #'char *'>
  	<var: #targetMethod type: #'CogMethod *'>
  	annotation = IsObjectReference ifTrue:
  		[| literal mappedLiteral |
  		 literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
  		 (objectRepresentation couldBeObject: literal) ifTrue:
+ 			[mappedLiteral := objectRepresentation remapObject: literal.
- 			[mappedLiteral := objectRepresentation remapObj: literal.
  			 literal ~= mappedLiteral ifTrue:
  				[backEnd storeLiteral: mappedLiteral beforeFollowingAddress: mcpc asInteger.
  				 codeModified := true].
  			 (hasYoungPtr ~= 0
  			  and: [objectMemory isYoung: mappedLiteral]) ifTrue:
  				[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true]]].
  	(self isSendAnnotation: annotation) ifTrue:
  		[| cacheTag mappedCacheTag entryPoint |
  		 cacheTag := backEnd inlineCacheTagAt: mcpc asInteger.
  		 (objectRepresentation couldBeObject: cacheTag) ifTrue:
+ 			[mappedCacheTag := objectRepresentation remapObject: cacheTag.
- 			[mappedCacheTag := objectRepresentation remapObj: cacheTag.
  			 cacheTag ~= mappedCacheTag ifTrue:
  				[backEnd rewriteInlineCacheTag: mappedCacheTag at: mcpc asInteger.
  				 codeModified := true].
  			 (hasYoungPtr ~= 0
  			  and: [objectMemory isYoung: mappedCacheTag]) ifTrue:
  				[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true]].
  		 entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
  		 entryPoint = ceImplicitReceiverTrampoline
  			ifTrue:
  				[| pc oop mappedOop |
  				 pc := mcpc asInteger + backEnd jumpShortByteSize.
  				 (oop := backEnd unalignedLongAt: pc) ~= 0 ifTrue:
  					[mappedOop := objectRepresentation remapOop: oop.
  					 mappedOop ~= oop ifTrue:
  						[backEnd unalignedLongAt: pc put: mappedOop].
  					 (hasYoungPtr ~= 0
  					  and: [objectMemory isYoung: mappedOop]) ifTrue:
  						[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true].
  					 pc := mcpc asInteger + backEnd jumpShortByteSize + BytesPerOop.
  					 (oop := backEnd unalignedLongAt: pc) ~= 0 ifTrue:
  						[mappedOop := objectRepresentation remapOop: oop.
  						 mappedOop ~= oop ifTrue:
  							[backEnd unalignedLongAt: pc put: mappedOop].
  					 (hasYoungPtr ~= 0
  					  and: [objectMemory isYoung: mappedOop]) ifTrue:
  						[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true]]]]
  			ifFalse:
  				[hasYoungPtr ~= 0 ifTrue:
  					[| offset targetMethod |
  					 "Since the unlinking routines may rewrite the cacheTag to the send's selector, and
  					  since they don't have the cogMethod to hand and can't add it to youngReferrers,
  					  the method must remain in youngReferrers if the targetMethod's selector is young."
  					 entryPoint > methodZoneBase ifTrue: "It's a linked send."
  						[offset := (entryPoint bitAnd: entryPointMask) = checkedEntryAlignment
  									ifTrue: [cmEntryOffset]
  									ifFalse: [cmNoCheckEntryOffset].
  						targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
  						(objectMemory isYoung: targetMethod selector) ifTrue:
  							[(self cCoerceSimple: hasYoungPtr to: #'sqInt *') at: 0 put: true]]]]].
  	^0 "keep scanning"!

Item was added:
+ ----- Method: Cogit>>sendSitesIn:do: (in category 'analysis') -----
+ sendSitesIn: cogMethod do: binaryBlock
+ 	"Evaluate binaryBlock with the annotation and mcpc for each send site in cogMethod"
+ 	<doNotGenerate>
+ 	self mapFor: cogMethod
+ 		 performUntil: (#withAnnotation:mcpc:evaluate:)
+ 		 arg: [:ann :mcpc | (self isSendAnnotation: ann) ifTrue: [binaryBlock value: ann value: mcpc]]!

Item was added:
+ ----- Method: Cogit>>withAnnotation:mcpc:evaluate: (in category 'analysis') -----
+ withAnnotation: annotation mcpc: mcpc evaluate: binaryBlock
+ 	<doNotGenerate>
+ 	binaryBlock value: annotation value: mcpc.
+ 	^0 "keep scanning"!

Item was changed:
  ----- Method: NewCoObjectMemory>>withoutForwardingOn:and:with:sendToCogit: (in category 'cog jit support') -----
  withoutForwardingOn: obj1 and: obj2 with: aBool sendToCogit: selector
+ 	"For the purposes of become: send selector to the cogit with obj1, obj2 and aBool, and
- 	"For the purposes of become: send selector to the cogit with obj1 and obj2 and
  	 answer the result. Undo forwarding for the selector, but redo forwarding after since
  	 become:'s restoreHeadersAfter*Become* methods expect to be able to restore."
  	<api>
  	<var: #selector declareC: 'sqInt (*selector)(sqInt,sqInt,sqInt)'>
  	| savedHeaderA savedHeaderB result |
  	savedHeaderA := self baseHeader: obj1.
  	self baseHeader: obj1 put: (self headerWhileForwardingOf: obj1).
  	savedHeaderB := self baseHeader: obj2.
  	self baseHeader: obj2 put: (self headerWhileForwardingOf: obj2).
  
  	result := cogit perform: selector with: obj1 with: obj2 with: aBool.
  
  	self baseHeader: obj1 put: savedHeaderA.
  	self baseHeader: obj2 put: savedHeaderB.
  	^result!

Item was changed:
  ----- Method: NewObjectMemory>>isYoungObject: (in category 'memory access') -----
  isYoungObject: obj
  	<api>
  	"Answer if obj is young. Assume obj is non-immediate."
+ 	self assert: (self isNonImmediate: obj).
  	^self oop: obj isGreaterThanOrEqualTo: youngStart!

Item was added:
+ ----- Method: Spur32BitCoMemoryManager>>withoutForwardingOn:and:sendToCogit: (in category 'cog jit support') -----
+ withoutForwardingOn: obj1 and: obj2 sendToCogit: selector
+ 	"For the purposes of become: send selector to the cogit with obj1 and obj2
+ 	 and answer the result.  Undo forwarding for the selector."
+ 	<api>
+ 	<var: #selector declareC: 'sqInt (*selector)(sqInt,sqInt)'>
+ 	| targetA targetB |
+ 	targetA := self followForwarded: obj1.
+ 	targetB := self followForwarded: obj2.
+ 	^cogit perform: selector with: targetA with: targetB!

Item was added:
+ ----- Method: Spur32BitCoMemoryManager>>withoutForwardingOn:and:with:sendToCogit: (in category 'cog jit support') -----
+ withoutForwardingOn: obj1 and: obj2 with: aBool sendToCogit: selector
+ 	"For the purposes of become: send selector to the cogit with obj1, obj2
+ 	 and aBool and answer the result.  Undo forwarding for the selector."
+ 	<api>
+ 	<var: #selector declareC: 'sqInt (*selector)(sqInt,sqInt,sqInt)'>
+ 	| targetA targetB |
+ 	targetA := self followForwarded: obj1.
+ 	targetB := self followForwarded: obj2.
+ 	^cogit perform: selector with: targetA with: targetB with: aBool!

Item was changed:
  ----- Method: Spur32BitMemoryManager>>isMarked: (in category 'header access') -----
  isMarked: objOop
+ 	<api>
  	self flag: #endianness.
  	^((self longAt: objOop + 4) >> self markedBitHalfShift bitAnd: 1) ~= 0!

Item was changed:
  ----- Method: Spur32BitMemoryManager>>numTagBits (in category 'object access') -----
  numTagBits
+ 	<api>
  	^2!

Item was changed:
  ----- Method: Spur32BitMemoryManager>>shiftForWord (in category 'word size') -----
  shiftForWord
+ 	<api>
  	^2!

Item was changed:
  ----- Method: Spur32BitMemoryManager>>tagMask (in category 'word size') -----
  tagMask
+ 	<api>
  	^3!

Item was changed:
  ----- Method: Spur64BitMemoryManager>>isMarked: (in category 'header access') -----
  isMarked: objOop
+ 	<api>
  	^((self longAt: objOop) >> self markedBitFullShift bitAnd: 1) ~= 0!

Item was changed:
  ----- Method: Spur64BitMemoryManager>>numTagBits (in category 'object access') -----
  numTagBits
+ 	<api>
  	"4th bit reserved for object alignment, which could imply e.g. what space the object is in."
  	^3!

Item was changed:
  ----- Method: Spur64BitMemoryManager>>shiftForWord (in category 'word size') -----
  shiftForWord
+ 	<api>
  	^3!

Item was changed:
  ----- Method: Spur64BitMemoryManager>>tagMask (in category 'word size') -----
  tagMask
+ 	<api>
  	^7!

Item was changed:
  ----- Method: SpurGenerationScavenger>>remember: (in category 'store check') -----
  remember: objOop
  	<inline: false>
+ 	self assert: (manager isYoung: objOop) not.
- 	self assert: ((manager isNonImmediate: objOop)
- 				and: [(manager isYoung: objOop) not]).
  	rememberedSetSize < RememberedSetLimit
  		ifTrue:
  			[rememberedSet at: rememberedSetSize put: objOop.
  			 (rememberedSetSize := rememberedSetSize + 1) >= RememberedSetRedZone ifTrue:
  				[manager scheduleScavenge]]
  		ifFalse:
  			[self error: 'remembered set overflow' "for now"]!

Item was changed:
  ----- Method: SpurGenerationScavenger>>scavengeReferentsOf: (in category 'scavenger') -----
  scavengeReferentsOf: referrer
  	"scavengeReferentsOf: referrer inspects all the pointers in referrer.  If
  	 any are new objects, it has them moved to FutureSurvivorSpace, and
  	 answers truth. If there are no new referents, it answers falsity. To handle
  	 weak arrays, if the referrer is weak only scavenge strong slots and answer
  	 true so that it won't be removed from the remembered set until later."
  	| foundNewReferent |
  	"forwarding objects should be followed by callers,
  	 unless the forwarder is a root in the remembered table."
  	self assert: ((manager isForwarded: referrer) not
  				or: [manager isRemembered: referrer]).
  	"unscanned ephemerons should be scanned later."
  	self assert: ((manager isEphemeron: referrer) not
  				or: [(self isScavengeSurvivor: (manager keyOfEphemeron: referrer))
  				or: [self is: referrer onWeaklingList: ephemeronList]]).
  	foundNewReferent := false.
  	0 to: (manager numStrongSlotsOf: referrer ephemeronInactiveIf: #isScavengeSurvivor:) - 1
  	   do: [:i| | referent newLocation |
  		referent := manager fetchPointer: i ofMaybeForwardedObject: referrer.
  		(manager isNonImmediate: referent) ifTrue:
  			["a forwarding pointer could be because of become: or scavenging."
  			 (manager isForwarded: referent) ifTrue:
  				[referent := manager followForwarded: referent].
+ 			 (manager isYoung: referent)
- 			 ((manager isNonImmediate: referent)
- 			  and: [manager isYoung: referent])
  				ifTrue: "if target is already in future space forwarding pointer was due to a become:."
  					[(manager isInFutureSpace: referent)
  						ifTrue: [newLocation := referent. foundNewReferent := true]
  						ifFalse:
  							[newLocation := self copyAndForward: referent.
  							 (manager isYoung: newLocation) ifTrue:
  								[foundNewReferent := true]].
  					 manager storePointerUnchecked: i ofMaybeForwardedObject: referrer withValue: newLocation]
  				ifFalse:
  					[manager storePointerUnchecked: i ofMaybeForwardedObject: referrer withValue: referent]]].
  	^foundNewReferent or: [manager isWeakNonImm: referrer]!

Item was added:
+ ----- Method: SpurMemoryManager>>beRootIfOld: (in category 'store check') -----
+ beRootIfOld: oop 
+ 	"If this object is old, mark it as a root (because a new object
+ 	 may be stored into it)."
+ 	<api>
+ 	<inline: false>
+ 	(self isYoung: oop) ifTrue:"Yes, oop is an old object"
+ 		[self possibleRootStoreInto: oop]!

Item was changed:
  ----- Method: SpurMemoryManager>>byteLengthOf: (in category 'object access') -----
  byteLengthOf: objOop 
  	"Answer the number of indexable bytes in the given object.
+ 	 Does not adjust contexts by stackPointer.
+ 	 This is basically a special copy of lengthOf: for BitBlt. But it is also
+ 	 whoorishly used for the Cogit."
+ 	<api>
- 	 Does not adjust contexts by stackPointer."
  	| fmt numBytes |
  	<inline: true>
  	<asmLabel: false>
  	fmt := self formatOf: objOop.
  	numBytes := (self numSlotsOf: objOop) << self shiftForWord.
  	fmt <= self sixtyFourBitIndexableFormat ifTrue:
  		[^numBytes].
  	fmt >= self firstByteFormat ifTrue: "bytes, including CompiledMethod"
  		[^numBytes - (fmt bitAnd: 7)].
  	fmt >= self firstShortFormat ifTrue:
  		[^numBytes - ((fmt bitAnd: 3) << 1)].
  	"fmt >= self firstLongFormat"
  	^numBytes - ((fmt bitAnd: 1) << 2)!

Item was changed:
  ----- Method: SpurMemoryManager>>characterTag (in category 'object access') -----
  characterTag
+ 	<api>
  	^2!

Item was changed:
  ----- Method: SpurMemoryManager>>checkHeapIntegrity: (in category 'debug support') -----
  checkHeapIntegrity: excludeUnmarkedNewSpaceObjs
  	"Perform an integrity/leak check using the heapMap.  Assume
  	 clearLeakMapAndMapAccessibleObjects has set a bit at each
  	 object's header.  Scan all objects in the heap checking that every
  	 pointer points to a header.  Scan the rootTable, remapBuffer and
  	 extraRootTable checking that every entry is a pointer to a header.
  	 Check that the number of roots is correct and that all rootTable
  	 entries have their rootBit set. Answer if all checks pass."
  	| ok numRememberedRootsInHeap |
  	<inline: false>
  	ok := true.
  	numRememberedRootsInHeap := 0.
  	self allHeapEntitiesDo:
  		[:obj| | containsYoung fieldOop classIndex classOop |
  		((self isFreeObject: obj)
+ 		 or: [(self isYoungObject: obj) and: [(self isMarked: obj) not and: [excludeUnmarkedNewSpaceObjs]]]) ifFalse:
- 		 or: [(self isYoung: obj) and: [(self isMarked: obj) not and: [excludeUnmarkedNewSpaceObjs]]]) ifFalse:
  			[containsYoung := false.
  			 (self isRemembered: obj) ifTrue:
  				[numRememberedRootsInHeap := numRememberedRootsInHeap + 1.
  				 (scavenger isInRememberedSet: obj) ifFalse:
  					[coInterpreter print: 'remembered object '; printHex: obj; print: ' is not in remembered table'; cr.
  					 self eek.
  					 ok := false]].
  			 (self isForwarded: obj)
  				ifTrue:
  					[fieldOop := self fetchPointer: 0 ofMaybeForwardedObject: obj.
  					 (heapMap heapMapAtWord: (self pointerForOop: fieldOop)) = 0 ifTrue:
  						[coInterpreter print: 'object leak in forwarder '; printHex: obj; print: ' to unmapped '; printHex: fieldOop; cr.
  						 self eek.
  						 ok := false].
  					 (self isYoung: fieldOop) ifTrue:
  						[containsYoung := true]]
  				ifFalse:
  					[classOop := self classAtIndex: (classIndex := self classIndexOf: obj).
  					 ((classOop isNil or: [classOop = nilObj])
  					  and: [(self isHiddenObj: obj) not]) ifTrue:
  						[coInterpreter print: 'object leak in '; printHex: obj; print: ' invalid class index '; printHex: classIndex; print: ' -> '; print: (classOop ifNil: ['nil'] ifNotNil: ['nilObj']); cr.
  						 self eek.
  						 ok := false].
  					 self baseHeaderSize to: (self lastPointerOf: obj) by: BytesPerOop do:
  						[:ptr|
  						 fieldOop := self longAt: obj + ptr.
  						 (self isNonImmediate: fieldOop) ifTrue:
  							[| fi |
  							 fi := ptr - self baseHeaderSize / self wordSize.
  							 (fieldOop bitAnd: self wordSize - 1) ~= 0
  								ifTrue:
  									[coInterpreter print: 'misaligned oop in '; printHex: obj; print: ' @ '; printNum: fi; print: ' = '; printHex: fieldOop; cr.
  									 self eek.
  									 ok := false]
  								ifFalse:
  									[(heapMap heapMapAtWord: (self pointerForOop: fieldOop)) = 0 ifTrue:
  										[coInterpreter print: 'object leak in '; printHex: obj; print: ' @ '; printNum: fi; print: ' = '; printHex: fieldOop; cr.
  										 self eek.
  										 ok := false].
  									 "don't be misled by CogMethods; they appear to be young, but they're not"
  									 ((self isYoung: fieldOop)
  									  and: [self oop: fieldOop isGreaterThanOrEqualTo: startOfMemory]) ifTrue:
  										[containsYoung := true]]]]].
  					(containsYoung and: [(self isYoung: obj) not]) ifTrue:
  						[(self isRemembered: obj) ifFalse:
  							[coInterpreter print: 'unremembered object '; printHex: obj; print: ' contains young oop(s)'; cr.
  							 self eek.
  							 ok := false]]]].
  	numRememberedRootsInHeap ~= scavenger rememberedSetSize ifTrue:
  		[coInterpreter
  			print: 'root count mismatch. #heap roots ';
  			printNum: numRememberedRootsInHeap;
  			print: '; #roots ';
  			printNum: scavenger rememberedSetSize;
  			cr.
  		self eek.
  		"But the system copes with overflow..."
  		self flag: 'no support for remembered set overflow yet'.
  		"ok := rootTableOverflowed and: [needGCFlag]"].
  	scavenger rememberedSetWithIndexDo:
  		[:obj :i|
  		(obj bitAnd: self wordSize - 1) ~= 0
  			ifTrue:
  				[coInterpreter print: 'misaligned oop in remembered set @ '; printNum: i; print: ' = '; printHex: obj; cr.
  				 self eek.
  				 ok := false]
  			ifFalse:
  				[(heapMap heapMapAtWord: (self pointerForOop: obj)) = 0
  					ifTrue:
  						[coInterpreter print: 'object leak in remembered set @ '; printNum: i; print: ' = '; printHex: obj; cr.
  						 self eek.
  						 ok := false]
  					ifFalse:
  						[(self isYoung: obj) ifTrue:
  							[coInterpreter print: 'non-root in remembered set @ '; printNum: i; print: ' = '; printHex: obj; cr.
  							 self eek.
  							 ok := false]]]].
  	1 to: remapBufferCount do:
  		[:ri| | obj |
  		obj := remapBuffer at: ri.
  		(obj bitAnd: self wordSize - 1) ~= 0
  			ifTrue:
  				[coInterpreter print: 'misaligned remapRoot @ '; printNum: ri; print: ' = '; printHex: obj; cr.
  				 self eek.
  				 ok := false]
  			ifFalse:
  				[(heapMap heapMapAtWord: (self pointerForOop: obj)) = 0 ifTrue:
  					[coInterpreter print: 'object leak in remapRoots @ '; printNum: ri; print: ' = '; printHex: obj; cr.
  					 self eek.
  					 ok := false]]].
  	1 to: extraRootCount do:
  		[:ri| | obj |
  		obj := (extraRoots at: ri) at: 0.
  		(obj bitAnd: self wordSize - 1) ~= 0
  			ifTrue:
  				[coInterpreter print: 'misaligned extraRoot @ '; printNum: ri; print: ' => '; printHex: obj; cr.
  				 self eek.
  				 ok := false]
  			ifFalse:
  				[(heapMap heapMapAtWord: (self pointerForOop: obj)) = 0 ifTrue:
  					[coInterpreter print: 'object leak in extraRoots @ '; printNum: ri; print: ' => '; printHex: obj; cr.
  					 self eek.
  					 ok := false]]].
  	^ok!

Item was changed:
  ----- Method: SpurMemoryManager>>classAtIndex: (in category 'class table') -----
  classAtIndex: classIndex
+ 	<api>
  	| classTablePage |
  	self assert: (classIndex <= self tagMask or: [classIndex >= self arrayClassIndexPun]).
  	classTablePage := self fetchPointer: classIndex >> self classTableMajorIndexShift
  							ofObject: hiddenRootsObj.
  	classTablePage = nilObj ifTrue:
  		[^nil].
  	^self
  		fetchPointer: (classIndex bitAnd: self classTableMinorIndexMask)
  		ofObject: classTablePage!

Item was changed:
  ----- Method: SpurMemoryManager>>classIndexMask (in category 'header format') -----
  classIndexMask
+ 	<api>
  	"22-bit class mask => ~ 4M classes"
  	^16r3fffff!

Item was changed:
  ----- Method: SpurMemoryManager>>classIndexOf: (in category 'header access') -----
  classIndexOf: objOop
+ 	<api>
  	^(self longAt: objOop) bitAnd: self classIndexMask!

Item was changed:
  ----- Method: SpurMemoryManager>>classTableMajorIndexShift (in category 'class table') -----
  classTableMajorIndexShift
+ 	<api>
  	"1024 entries per page (2^10); 22 bit classIndex implies 2^12 pages"
  	^10!

Item was changed:
  ----- Method: SpurMemoryManager>>classTableMinorIndexMask (in category 'class table') -----
  classTableMinorIndexMask
+ 	<api>
  	"1024 entries per page (2^10); 22 bit classIndex implies 2^12 pages"
  	"self basicNew classTableMinorIndexMask"
  	^1 << self classTableMajorIndexShift - 1!

Item was changed:
  ----- Method: SpurMemoryManager>>classTableRootObj (in category 'accessing') -----
  classTableRootObj
+ 	<api>
  	"For Cogit & bootstrap"
  	^hiddenRootsObj!

Item was changed:
  ----- Method: SpurMemoryManager>>clone: (in category 'allocation') -----
  clone: objOop
  	| numSlots newObj |
  	numSlots := self numSlotsOf: objOop.
  	
  	numSlots > self maxSlotsForNewSpaceAlloc
  		ifTrue:
  			[newObj := self allocateSlotsInOldSpace: numSlots
  							format: (self formatOf: objOop)
  							classIndex: (self classIndexOf: objOop)]
  		ifFalse:
  			[newObj := self allocateSlots: numSlots
  							format: (self formatOf: objOop)
  							classIndex: (self classIndexOf: objOop)].
  	(self isPointersNonImm: objOop)
  		ifTrue:
  			[0 to: numSlots - 1 do:
  				[:i| | oop |
  				oop := self fetchPointer: i ofObject: objOop.
  				((self isNonImmediate: oop)
  				 and: [self isForwarded: oop]) ifTrue:
  					[oop := self followForwarded: oop].
  				self storePointerUnchecked: i
  					ofObject: newObj
  					withValue: oop].
  			((self isRemembered: objOop)
+ 			 and: [(self isYoungObject: newObj) not]) ifTrue:
- 			 and: [(self isYoung: newObj) not]) ifTrue:
  				[scavenger remember: newObj.
  				 self setIsRememberedOf: newObj to: true]]
  		ifFalse:
  			[0 to: numSlots - 1 do:
  				[:i|
  				self storePointerUnchecked: i
  					ofObject: newObj
  					withValue: (self fetchPointer: i ofObject: objOop)]].
  	^newObj!

Item was changed:
  ----- Method: SpurMemoryManager>>compactClassIndexOf: (in category 'object access') -----
  compactClassIndexOf: objOop
+ 	<api>
+ 	<inline: true>
  	^self classIndexOf: objOop!

Item was changed:
  ----- Method: SpurMemoryManager>>eliminateAndFreeForwarders (in category 'gc - global') -----
  eliminateAndFreeForwarders
  	"As the final phase of global garbage collect, sweep
  	 the heap to follow forwarders, then free forwarders"
  	| lowestForwarded firstForwarded lastForwarded |
  	<inline: false>
  	self assert: (self isForwarded: nilObj) not.
  	self assert: (self isForwarded: falseObj) not.
  	self assert: (self isForwarded: trueObj) not.
  	self assert: (self isForwarded: self freeListsObj) not.
  	self assert: (self isForwarded: hiddenRootsObj) not.
  	self assert: (self isForwarded: classTableFirstPage) not.
  	(self isForwarded: specialObjectsOop) ifTrue:
  		[specialObjectsOop := self followForwarded: specialObjectsOop].
  	"N.B. we don't have to explcitly do mapInterpreterOops
  	 since the scavenge below will do it."
  	self followForwardedObjStacks.
  	scavenger followRememberedForwardersAndForgetFreeObjects.
  	self doScavenge: DontTenureButDoUnmark.
  	self checkFreeSpace.
  	lowestForwarded := 0.
  	"sweep, following forwarders in all live objects, and finding the first forwarder."
  	self allOldSpaceObjectsDo:
  		[:o|
  		(self isForwarded: o)
  			ifTrue:
  				[lowestForwarded = 0 ifTrue:
  					[lowestForwarded := o]]
  			ifFalse:
  				[0 to: (self numPointerSlotsOf: o) - 1 do:
  					[:i| | f |
  					f := self fetchPointer: i ofObject: o.
  					(self isOopForwarded: f) ifTrue:
  						[f := self followForwarded: f.
+ 						 self assert: (self isYoung: f) not.
- 						 self assert: ((self isImmediate: f) or: [self isYoung: f]) not.
  						 self storePointerUnchecked: i ofObject: o withValue: f]]]].
  	self checkFreeSpace.
  	firstForwarded := lastForwarded := 0.
  	"sweep from lowest forwarder, coalescing runs of forwarders. perhaps this should
  	 coalewsce free space and forwarders.  the previous loop could reprise the discarding
  	 of free space in freeUnmarkedObjectsAndSortAndCoalesceFreeSpace."
  	self allOldSpaceEntitiesFrom: lowestForwarded do:
  		[:o|
  		(self isForwarded: o)
  			ifTrue:
  				[firstForwarded = 0 ifTrue:
  					[firstForwarded := o].
  				 lastForwarded := o]
  			ifFalse:
  				[firstForwarded ~= 0 ifTrue:
  					[| start bytes |
  					 start := self startOfObject: firstForwarded.
  					 bytes := (self addressAfter: lastForwarded) - start.
  					 self addFreeChunkWithBytes: bytes at: start].
  				 firstForwarded := 0]].
  	firstForwarded ~= 0 ifTrue:
  		[| start bytes |
  		 start := self startOfObject: firstForwarded.
  		 bytes := (self addressAfter: lastForwarded) - start.
  		 self addFreeChunkWithBytes: bytes at: start].
  	self checkFreeSpace!

Item was changed:
  ----- Method: SpurMemoryManager>>firstShortFormat (in category 'header formats') -----
  firstShortFormat
+ 	<api>
  	^12!

Item was changed:
  ----- Method: SpurMemoryManager>>fixedFieldsFieldWidth (in category 'object format') -----
  fixedFieldsFieldWidth
+ 	<api>
  	^16!

Item was changed:
  ----- Method: SpurMemoryManager>>fixedFieldsOfClassFormatMask (in category 'object format') -----
  fixedFieldsOfClassFormatMask
+ 	<api>
  	^1 << self fixedFieldsFieldWidth - 1!

Item was changed:
  ----- Method: SpurMemoryManager>>formatMask (in category 'header format') -----
  formatMask
+ 	<api>
  	"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,7,8 unused
  	 9 (?) 64-bit indexable
  	 10 - 11 32-bit indexable
  	 12 - 15 16-bit indexable
  	 16 - 23 byte indexable
  	 24 - 31 compiled method"
  	^16r1f!

Item was changed:
  ----- Method: SpurMemoryManager>>formatShift (in category 'header format') -----
  formatShift
+ 	<api>
  	^24!

Item was changed:
  ----- Method: SpurMemoryManager>>hasYoungReferents: (in category 'object testing') -----
  hasYoungReferents: objOop
  	0 to: (self numPointerSlotsOf: objOop) - 1 do:
  		[:i| | oop |
  		oop := self fetchPointer: i ofObject: objOop.
+ 		(self isYoung: oop) ifTrue:
- 		((self isNonImmediate: oop)
- 		 and: [self isYoung: oop]) ifTrue:
  			[^true]].
  	^false!

Item was changed:
  ----- Method: SpurMemoryManager>>headerForSlots:format:classIndex: (in category 'header format') -----
  headerForSlots: numSlots format: formatField classIndex: classIndex
+ 	<api>
  	"The header format in LSB is
  	 MSB:	| 8: numSlots		| (on a byte boundary)
  			| 2 bits				|	(msb,lsb = {isMarked,?})
  			| 22: identityHash	| (on a word boundary)
  			| 3 bits				|	(msb <-> lsb = {isGrey,isPinned,isRemembered}
  			| 5: format			| (on a byte boundary)
  			| 2 bits				|	(msb,lsb = {isImmutable,?})
  			| 22: classIndex		| (on a word boundary) : LSB
  	 The remaining bits (7) are used for
  		isImmutable	(bit 23)
  		isRemembered	(bit 29)
  		isPinned		(bit 30)
  		isGrey			(bit 31)
  		isMarked		(bit 55)
  	 leaving 2 unused bits, each next to a 22-bit field, allowing those fields to be
  	 expanded to 23 bits..  The three bit field { isGrey, isPinned, isRemembered }
  	 is for bits that are never set in young objects.  This allows the remembered
  	 table to be pruned when full by using these bits as a reference count of
  	 newSpace objects from the remembered table. Objects with a high count
  	 should be tenured to prune the remembered table."
  	<returnTypeC: #usqLong>
  	<inline: true>
  	^ ((self cCoerceSimple: numSlots to: #usqLong) << self numSlotsFullShift)
  	+ (formatField << self formatShift)
  	+ classIndex!

Item was changed:
  ----- Method: SpurMemoryManager>>identityHashHalfWordMask (in category 'header format') -----
  identityHashHalfWordMask
+ 	<api>
  	^16r3fffff!

Item was changed:
  ----- Method: SpurMemoryManager>>inPlaceBecome:and:copyHashFlag: (in category 'become implementation') -----
  inPlaceBecome: obj1 and: obj2 copyHashFlag: copyHashFlag
  	"Do become in place by swapping object contents."
  	| headerTemp temp1 temp2 o1HasYoung o2HasYoung |
  	self assert: (self numSlotsOf: obj1) = (self numSlotsOf: obj2).
  	"swap headers, but swapping headers swaps remembered bits;
  	 these need to be unswapped."
  	temp1 := self isRemembered: obj1.
  	temp2 := self isRemembered: obj2.
  	headerTemp := self longLongAt: obj1.
  	self longLongAt: obj1 put: (self longLongAt: obj2).
  	self longLongAt: obj2 put: headerTemp.
  	self setIsRememberedOf: obj1 to: temp1.
  	self setIsRememberedOf: obj2 to: temp2.
  	"swapping headers swaps hash; if !!copyHashFlag undo hash copy"
  	copyHashFlag ifFalse:
  		[temp1 := self rawHashBitsOf: obj1.
  		 self setHashBitsOf: obj1 to: (self rawHashBitsOf: obj2).
  		 self setHashBitsOf: obj2 to: temp1].
  	o1HasYoung := o2HasYoung := false.
  	0 to: (self numSlotsOf: obj1) - 1 do:
  		[:i|
  		temp1 := self fetchPointer: i ofObject: obj1.
  		temp2 := self fetchPointer: i ofObject: obj2.
  		self storePointerUnchecked: i
  			ofObject: obj1
  			withValue: temp2.
  		self storePointerUnchecked: i
  			ofObject: obj2
  			withValue: temp1.
+ 		(self isYoung: temp2) ifTrue:
- 		((self isNonImmediate: temp2) and: [self isYoung: temp2]) ifTrue:
  			[o1HasYoung := true].
+ 		(self isYoung: temp1) ifTrue:
- 		((self isNonImmediate: temp1) and: [self isYoung: temp1]) ifTrue:
  			[o2HasYoung := true]].
+ 	(self isYoungObject: obj1) ifFalse:
- 	(self isYoung: obj1) ifFalse:
  		[o1HasYoung ifTrue:
  			[self possibleRootStoreInto: obj1]].
+ 	(self isYoungObject: obj2) ifFalse:
- 	(self isYoung: obj2) ifFalse:
  		[o2HasYoung ifTrue:
  			[self possibleRootStoreInto: obj2]]!

Item was changed:
  ----- Method: SpurMemoryManager>>isForwardedObjectClassIndexPun (in category 'class table puns') -----
  isForwardedObjectClassIndexPun
+ 	<api>
  	^8 "Not to be confused with that of any immediate class"!

Item was changed:
  ----- Method: SpurMemoryManager>>isMarked: (in category 'header access') -----
  isMarked: objOop
+ 	<api>
  	self subclassResponsibility!

Item was changed:
  ----- Method: SpurMemoryManager>>isNonImmediate: (in category 'object testing') -----
+ isNonImmediate: oop
+ 	<api>
- isNonImmediate: oop 
  	^(oop bitAnd: self tagMask) = 0!

Item was added:
+ ----- Method: SpurMemoryManager>>isReallyYoungObject: (in category 'object testing') -----
+ isReallyYoungObject: obj
+ 	<api>
+ 	"Answer if obj is young. This for compatibility with SqueakV3 where
+ 	 the GC makes all objects young during full GC.  Spur doesn't do so."
+ 	^self isYoungObject: obj!

Item was changed:
  ----- Method: SpurMemoryManager>>isYoung: (in category 'object testing') -----
+ isYoung: oop
+ 	<api>
+ 	"Answer if oop is young."
+ 	^(self isNonImmediate: oop)
+ 	 and: [self oop: oop isLessThan: newSpaceLimit]!
- isYoung: objOop
- 	^self oop: objOop isLessThan: newSpaceLimit!

Item was added:
+ ----- Method: SpurMemoryManager>>isYoungObject: (in category 'object testing') -----
+ isYoungObject: objOop
+ 	<api>
+ 	"Answer if obj is young. Assume obj is non-immediate."
+ 	self assert: (self isNonImmediate: objOop).
+ 	^self oop: objOop isLessThan: newSpaceLimit!

Item was changed:
  ----- Method: SpurMemoryManager>>markAndTrace: (in category 'gc - global') -----
  markAndTrace: objOop
+ 	"Mark the argument, and all objects reachable from it, and any remaining objects
+ 	 on the mark stack. Follow forwarding pointers in the scan."
+ 	<api>
- 	"Mark the argument, and all objects reachable from it, and any remaining objects on the mark stack.
- 	 Follow forwarding pointers in the scan."
  	| objToScan numStrongSlots index field |
  	(self markAndShouldScan: objOop) ifFalse:
  		[^self].
  	"if markAndTrace: is to follow and eliminate forwarding pointers
  	 in its scan it cannot be handed an r-value which is forwarded."
  	self assert: (self isForwarded: objOop) not.
  
  	"Now scan the object, and any remaining objects on the mark stack."
  	objToScan := objOop.
  	"To avoid overflowing the mark stack when we encounter large objects, we
  	 push the obj, then its numStrongSlots, and then index the object from the stack."
  	[((self isImmediate: objToScan)
  	  or: [numStrongSlots := self numStrongSlotsOf: objToScan ephemeronInactiveIf: #inactiveOrFailedToDeferScan:.
  		 numStrongSlots > self traceImmediatelySlotLimit])
  		ifTrue: "scanning a large object. scan until hitting an unmarked object, then switch to it, if any."
  			[(self isImmediate: objToScan)
  				ifTrue:
  					[index := self integerValueOf: objToScan.
  					 objToScan := self topOfObjStack: markStack]
  				ifFalse:
  					[index := numStrongSlots.
  					 self markAndTraceClassOf: objToScan].
  			 [index > 0] whileTrue:
  				[index := index - 1.
  				 field := self fetchPointer: index ofObject: objToScan.
  				 (self isOopForwarded: field) ifTrue:
  					[field := self followForwarded: field.
  					 self storePointerUnchecked: index ofObject: objToScan withValue: field].
  				 (self markAndShouldScan: field) ifTrue:
  					[index > 0 ifTrue:
  						[(self topOfObjStack: markStack) ~= objToScan ifTrue: 
  							[self push: objToScan onObjStack: markStack].
  						 self push: (self integerObjectOf: index) onObjStack: markStack].
  					 objToScan := field.
  					 index := -1]].
  			 index >= 0 ifTrue: "if loop terminated without finding an unmarked referent, switch to top of stack."
  				[objToScan := self popObjStack: markStack.
  				 objToScan = objOop ifTrue:
  					[objToScan := self popObjStack: markStack]]]
  		ifFalse: "scanning a small object. scan, marking, pushing unmarked referents, then switch to the top of the stack."
  			[index := numStrongSlots.
  			 self markAndTraceClassOf: objToScan.
  			 [index > 0] whileTrue:
  				[index := index - 1.
  				 field := self fetchPointer: index ofObject: objToScan.
  				 (self isOopForwarded: field) ifTrue:
  					[field := self followForwarded: field.
  					 self storePointerUnchecked: index ofObject: objToScan withValue: field].
  				 (self markAndShouldScan: field) ifTrue:
  					[self push: field onObjStack: markStack.
  					 numStrongSlots := self numStrongSlotsOf: field ephemeronInactiveIf: #inactiveOrFailedToDeferScan:.
  					 numStrongSlots > self traceImmediatelySlotLimit ifTrue:
  						[self push: (self integerObjectOf: numStrongSlots) onObjStack: markStack]]].
  			 objToScan := self popObjStack: markStack].
  	 objToScan notNil] whileTrue!

Item was changed:
  ----- Method: SpurMemoryManager>>nonIndexablePointerFormat (in category 'header formats') -----
  nonIndexablePointerFormat
+ 	<api>
  	^1!

Item was changed:
  ----- Method: SpurMemoryManager>>numSlotsHalfShift (in category 'header format') -----
  numSlotsHalfShift
+ 	<api>
  	^24!

Item was changed:
  ----- Method: SpurMemoryManager>>numSlotsMask (in category 'header format') -----
  numSlotsMask
+ 	<api>
  	"8-bit slot count
  		max 64-bit small obj size 254 * 8 =  2032 bytes
  		max 32-bit small obj size 254 * 4 =   1016 bytes"
  	^255!

Item was changed:
  ----- Method: SpurMemoryManager>>numTagBits (in category 'object access') -----
  numTagBits
+ 	<api>
  	^self subclassResponsibility!

Item was changed:
  ----- Method: SpurMemoryManager>>remapObj: (in category 'gc - scavenging') -----
  remapObj: objOop
  	"Scavenge or simply follow objOop.  Answer the new location of objOop.  The
  	 send should have been guarded by a send of shouldRemapOop: or shouldScavengeObj:.
  	 The method is called remapObj: for compatibility with ObjectMemory."
+ 	<api>
  	<inline: false>
  	| resolvedObj |
  	self assert: (self shouldRemapOop: objOop).
  	(self isForwarded: objOop)
  		ifTrue:
  			[resolvedObj := self followForwarded: objOop.
  			(self isInFutureSpace: resolvedObj) ifTrue: "already scavenged"
  				[^resolvedObj]]
  		ifFalse:
  			[resolvedObj := objOop].
  	(self isYoung: resolvedObj) ifFalse: "a becommed or compacted object whose target is in old space"
  		[^resolvedObj].
  	^scavenger copyAndForward: resolvedObj!

Item was changed:
  ----- Method: SpurMemoryManager>>rememberedBitShift (in category 'header format') -----
  rememberedBitShift
+ 	<api>
  	"bit 0 of 3-bit field above format (little endian)"
  	^29!

Item was changed:
  ----- Method: SpurMemoryManager>>shiftForWord (in category 'word size') -----
  shiftForWord
+ 	<api>
  	^self subclassResponsibility!

Item was changed:
  ----- Method: SpurMemoryManager>>shouldRemapObj: (in category 'gc - scavenging') -----
  shouldRemapObj: objOop
+ 	<api>
  	"Answer if the obj should be scavenged (or simply followed). The method is called
  	 shouldRemapObj: for compatibility with ObjectMemory."
  	^(self isForwarded: objOop)
+ 	  or: [self isYoungObject: objOop]!
- 	  or: [self isYoung: objOop]!

Item was changed:
  ----- Method: SpurMemoryManager>>storePointer:ofForwarder:withValue: (in category 'heap management') -----
  storePointer: fieldIndex ofForwarder: objOop withValue: valuePointer
  
  	self assert: (self isForwarded: objOop).
  	self assert: (self isOopForwarded: valuePointer) not.
  
+ 	(self isYoungObject: objOop) ifFalse: "most stores into young objects"
- 	(self isYoung: objOop) ifFalse: "most stores into young objects"
  		[((self isNonImmediate: valuePointer) and: [self isYoung: valuePointer]) ifTrue:
  			[self possibleRootStoreInto: objOop]].
  
  	^self
  		longAt: objOop + self baseHeaderSize + (fieldIndex << self shiftForWord)
  		put: valuePointer!

Item was changed:
  ----- Method: SpurMemoryManager>>storePointer:ofObject:withValue: (in category 'object access') -----
  storePointer: fieldIndex ofObject: objOop withValue: valuePointer
  	"Note must check here for stores of young objects into old ones."
  	self assert: (self isForwarded: objOop) not.
  
+ 	(self isYoungObject: objOop) ifFalse: "most stores into young objects"
- 	(self isYoung: objOop) ifFalse: "most stores into young objects"
  		[(self isImmediate: valuePointer) ifFalse:
  			[(self isYoung: valuePointer) ifTrue:
  				[self possibleRootStoreInto: objOop]]].
  
  	^self
  		longAt: objOop + self baseHeaderSize + (fieldIndex << self shiftForWord)
  		put: valuePointer!

Item was changed:
  ----- Method: SpurMemoryManager>>storePointerUnchecked:ofObject:withValue: (in category 'object access') -----
  storePointerUnchecked: fieldIndex ofObject: objOop withValue: valuePointer
+ 	<api>
  	self assert: (self isForwarded: objOop) not.
  	^self
  		longAt: objOop + self baseHeaderSize + (fieldIndex << self shiftForWord)
  		put: valuePointer!

Item was changed:
  ----- Method: SpurMemoryManager>>tagMask (in category 'word size') -----
  tagMask
+ 	<api>
  	^self subclassResponsibility!

Item was changed:
  ----- Method: StackInterpreter>>checkOkayFields: (in category 'debug support') -----
  checkOkayFields: oop
  	"Check if the argument is an ok object.
  	 If this is a pointers object, check that its fields are all okay oops."
  
  	| hasYoung i fieldOop |
  	(oop = nil or: [oop = 0]) ifTrue: [ ^true ]. "?? eem 1/16/2013"
  	(objectMemory isIntegerObject: oop) ifTrue: [ ^true ].
  	(objectMemory checkOkayOop: oop) ifFalse: [ ^false ].
  	(objectMemory checkOopHasOkayClass: oop) ifFalse: [ ^false ].
  	((objectMemory isPointersNonImm: oop) or: [objectMemory isCompiledMethod: oop]) ifFalse: [ ^true ].
+ 	hasYoung := objectMemory hasSpurMemoryManagerAPI not
+ 				  and: [objectMemory isYoung: (objectMemory fetchClassOfNonImm: oop)].
- 	hasYoung := objectMemory isYoung: (objectMemory fetchClassOfNonImm: oop).
  	(objectMemory isCompiledMethod: oop)
  		ifTrue:
  			[i := (self literalCountOf: oop) + LiteralStart - 1]
  		ifFalse:
  			[(objectMemory isContext: oop)
  				ifTrue: [i := CtxtTempFrameStart + (self fetchStackPointerOf: oop) - 1]
  				ifFalse: [i := (objectMemory lengthOf: oop) - 1]].
  	[i >= 0] whileTrue:
  		[fieldOop := objectMemory fetchPointer: i ofObject: oop.
  		(objectMemory isIntegerObject: fieldOop) ifFalse:
  			[hasYoung := hasYoung or: [objectMemory isYoung: fieldOop].
  			(objectMemory checkOkayOop: fieldOop) ifFalse: [ ^false ].
  			(self checkOopHasOkayClass: fieldOop) ifFalse: [ ^false ]].
  		i := i - 1].
  	hasYoung ifTrue:
  		[^objectMemory checkOkayYoungReferrer: oop].
  	^true!



More information about the Vm-dev mailing list