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

commits at source.squeak.org commits at source.squeak.org
Mon Jun 27 21:02:44 UTC 2022


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

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

Name: VMMaker.oscog.seperateMarking-eem.3206
Author: eem
Time: 27 June 2022, 2:02:30.233921 pm
UUID: 6a678af5-a05b-463c-8db1-946cb5495ca5
Ancestors: VMMaker.oscog.seperateMarking-eem.3205

Redo the refactoring of markAndTrace: using the 
<doNotGenerate> forwarding technique.  This way SpurMarker implements markAndTrace: in exactly the same way as SpurMemoryManager used to, and SpurMemoryManager's markAndTrace: is invisible to the C translator.  So we get the same code generated as previously, whereas with SpurMarker>>doMarkAndTrace: we get different inlining decisions.

Make sure that SpurMarker has the same type for no-return methods as SpurMemoryManager.

Make sure SpurMarker methods are categoriuzed appropriately.

=============== Diff against VMMaker.oscog.seperateMarking-eem.3205 ===============

Item was added:
+ ----- Method: SpurMarker class>>implicitReturnTypeFor: (in category 'translation') -----
+ implicitReturnTypeFor: aSelector
+ 	"Answer the return type for methods that don't have an explicit return."
+ 	^#void!

Item was removed:
- ----- Method: SpurMarker>>doMarkAndTrace: (in category 'as yet unclassified') -----
- doMarkAndTrace: objOop
- 	"Mark the argument, and all objects reachable from it, and any remaining objects
- 	 on the mark stack. Follow forwarding pointers in the scan."
- 	
- 	<inline: true>
- 	"if markAndTrace: is to follow and eliminate forwarding pointers
- 	 in its scan it cannot be handed an r-value which is forwarded.
- 	 The assert for this is in markAndShouldScan:"
- 	(self markAndShouldScan: objOop) ifFalse:
- 		[^self].
- 
- 	"Now scan the object, and any remaining objects on the mark stack."
- 	self markLoopFrom: objOop!

Item was changed:
+ ----- Method: SpurMarker>>initialize (in category 'instance initialization') -----
- ----- Method: SpurMarker>>initialize (in category 'as yet unclassified') -----
  initialize
  
  	marking := false!

Item was changed:
+ ----- Method: SpurMarker>>markAccessibleObjectsAndFireEphemerons (in category 'marking') -----
- ----- Method: SpurMarker>>markAccessibleObjectsAndFireEphemerons (in category 'as yet unclassified') -----
  markAccessibleObjectsAndFireEphemerons
  	self assert: marking.
  	self assert: manager validClassTableRootPages.
  	self assert: manager segmentManager allBridgesMarked.
  	self cCode: [] "for debugging markAndTrace: set (MarkStackRecord := OrderedCollection new)"
  		inSmalltalk: [MarkStackRecord ifNotNil: [MarkStackRecord resetTo: 1]].
  
  	"This must come first to enable stack page reclamation.  It clears
  	  the trace flags on stack pages and so must precede any marking.
  	  Otherwise it will clear the trace flags of reached pages."
  	coInterpreter initStackPageGC.
  	self markAndTraceHiddenRoots.
  	self markAndTraceExtraRoots.
  	self assert: manager validClassTableRootPages.
  	coInterpreter markAndTraceInterpreterOops: true.
  	self assert: manager validObjStacks.
  	self markWeaklingsAndMarkAndFireEphemerons.
  	self assert: manager validObjStacks!

Item was changed:
  ----- Method: SpurMarker>>markAllUnscannedEphemerons (in category 'weakness and ephemerality') -----
  markAllUnscannedEphemerons
  	"After firing the unscanned ephemerons we must scan-mark them.
  	 The wrinkle is that doing so may add more ephemerons to the set.
  	 So we remove the first element, by overwriting it with the last element,
  	 and decrementing the top, and then markAndTrace its contents."
  	self assert: (manager noUnscannedEphemerons) not.
  	self assert: manager allUnscannedEphemeronsAreActive.
  	[manager unscannedEphemerons top > manager unscannedEphemerons start] whileTrue:
  		[| ephemeron key lastptr |
  		 ephemeron := manager longAt: manager unscannedEphemerons start.
  		 lastptr := manager unscannedEphemerons top - manager bytesPerOop.
  		 lastptr > manager unscannedEphemerons start ifTrue:
  			[manager longAt: manager unscannedEphemerons start put: (manager longAt: lastptr)].
  		 manager unscannedEphemerons top: lastptr.
  		 key := manager followedKeyOfMaybeFiredEphemeron: ephemeron.
  		 manager setIsMarkedOf: ephemeron to: false. "to get it to be fully scanned in markAndTrace:"
  		 self
+ 			markAndTrace: key;
+ 			markAndTrace: ephemeron]!
- 			doMarkAndTrace: key;
- 			doMarkAndTrace: ephemeron]!

Item was changed:
+ ----- Method: SpurMarker>>markAndShouldScan: (in category 'marking') -----
- ----- Method: SpurMarker>>markAndShouldScan: (in category 'as yet unclassified') -----
  markAndShouldScan: objOop
  	"Helper for markAndTrace:.
  	 Mark the argument, and answer if its fields should be scanned now.
  	 Immediate objects don't need to be marked.
  	 Already marked objects have already been processed.
  	 Pure bits objects don't need scanning, although their class does.
  	 Weak objects should be pushed on the weakling stack.
  	 Anything else need scanning."
  	| format |
  	<inline: true>
  	(manager isImmediate: objOop) ifTrue:
  		[^false].
  	"if markAndTrace: is to follow and eliminate forwarding pointers
  	 in its scan it cannot be handed an r-value which is forwarded."
  	self assert: (manager isForwarded: objOop) not.
  	(manager isMarked: objOop) ifTrue:
  		[^false].
  	manager setIsMarkedOf: objOop to: true.
  	format := manager formatOf: objOop.
  	(manager isPureBitsFormat: format) ifTrue: "avoid pushing non-pointer objects on the markStack."
  		["Avoid tracing classes of non-objects on the heap, e.g. IRC caches, Sista counters."
  		 (manager classIndexOf: objOop) > manager lastClassIndexPun ifTrue:
  			[self markAndTraceClassOf: objOop].
  		 ^false].
  	format = manager weakArrayFormat ifTrue: "push weaklings on the weakling stack to scan later"
  		[manager push: objOop onObjStack: manager weaklingStack.
  		 ^false].
  	(format = manager ephemeronFormat
  	 and: [manager activeAndDeferredScan: objOop]) ifTrue:
  		[^false].
  	^true!

Item was added:
+ ----- Method: SpurMarker>>markAndTrace: (in category 'marking') -----
+ 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>
+ 	<inline: #never>
+ 	"if markAndTrace: is to follow and eliminate forwarding pointers
+ 	 in its scan it cannot be handed an r-value which is forwarded.
+ 	 The assert for this is in markAndShouldScan:"
+ 	(self markAndShouldScan: objOop) ifFalse:
+ 		[^self].
+ 
+ 	"Now scan the object, and any remaining objects on the mark stack."
+ 	self markLoopFrom: objOop!

Item was changed:
+ ----- Method: SpurMarker>>markAndTraceClassOf: (in category 'marking') -----
- ----- Method: SpurMarker>>markAndTraceClassOf: (in category 'as yet unclassified') -----
  markAndTraceClassOf: objOop
  	"Ensure the class of the argument is marked, pushing it on the markStack if not already marked.
  	 And for one-way become, which can create duplicate entries in the class table, make sure
  	 objOop's classIndex refers to the classObj's actual classIndex.
  	 Note that this is recursive, but the metaclass chain should terminate quickly."
  	<inline: false>
  	| classIndex classObj realClassIndex |
  	classIndex := manager classIndexOf: objOop.
  	classObj := manager classOrNilAtIndex: classIndex.
  	self assert: (coInterpreter objCouldBeClassObj: classObj).
  	realClassIndex := manager rawHashBitsOf: classObj.
  	(classIndex ~= realClassIndex
  	 and: [classIndex > manager lastClassIndexPun]) ifTrue:
  		[manager setClassIndexOf: objOop to: realClassIndex].
  	(manager isMarked: classObj) ifFalse:
  		[manager setIsMarkedOf: classObj to: true.
  		 self markAndTraceClassOf: classObj.
  		 manager push: classObj onObjStack: manager markStack]!

Item was changed:
+ ----- Method: SpurMarker>>markAndTraceExtraRoots (in category 'marking') -----
- ----- Method: SpurMarker>>markAndTraceExtraRoots (in category 'as yet unclassified') -----
  markAndTraceExtraRoots
  	| oop |
  	self assert: manager remapBufferCount = 0.
  
  	1 to: manager extraRootCount do:
  		[:i|
  		oop := (manager extraRoots at: i) at: 0.
  		((manager isImmediate: oop) or: [manager isFreeObject: oop]) ifFalse:
+ 			[self markAndTrace: oop]]!
- 			[self doMarkAndTrace: oop]]!

Item was changed:
+ ----- Method: SpurMarker>>markAndTraceHiddenRoots (in category 'marking') -----
- ----- Method: SpurMarker>>markAndTraceHiddenRoots (in category 'as yet unclassified') -----
  markAndTraceHiddenRoots
  	"The hidden roots hold both the class table pages and the obj stacks,
  	 and hence need special treatment.  The obj stacks must be marked
  	 specially; their pages must be marked, but only the contents of the
  	 mournQueue should be marked.
  
  	 If a class table page is weak we can mark and trace the hiddenRoots,
  	 which will not trace through class table pages because they are weak.
  	 But if class table pages are strong, we must mark the pages and *not*
  	 trace them so that only classes reachable from the true roots will be
  	 marked, and unreachable classes will be left unmarked."
  
  	self markAndTraceObjStack: manager markStack andContents: false.
  	self markAndTraceObjStack: manager weaklingStack andContents: false.
  	self markAndTraceObjStack: manager mournQueue andContents: true.
  
  	manager setIsMarkedOf: manager rememberedSetObj to: true.
  	manager setIsMarkedOf: manager freeListsObj to: true.
  
  	(manager isWeakNonImm: manager classTableFirstPage) ifTrue:
+ 		[^self markAndTrace: manager hiddenRootsObj].
- 		[^self doMarkAndTrace: manager hiddenRootsObj].
  
  	manager setIsMarkedOf: manager hiddenRootsObj to: true.
+ 	self markAndTrace: manager classTableFirstPage.
- 	self doMarkAndTrace: manager classTableFirstPage.
  	1 to: manager numClassTablePages - 1 do:
  		[:i| manager setIsMarkedOf: (manager fetchPointer: i ofObject: manager hiddenRootsObj)
  				to: true]!

Item was changed:
+ ----- Method: SpurMarker>>markAndTraceObjStack:andContents: (in category 'marking') -----
- ----- Method: SpurMarker>>markAndTraceObjStack:andContents: (in category 'as yet unclassified') -----
  markAndTraceObjStack: stackOrNil andContents: markAndTraceContents
  	"An obj stack is a stack of objects stored in a hidden root slot, such
  	 as the markStack or the ephemeronQueue.  It is a linked list of
  	 segments, with the hot end at the head of the list.  It is a word object.
  	 The stack pointer is in ObjStackTopx and 0 means empty."
  	<inline: false>
  	| index field |
  	stackOrNil = manager nilObj ifTrue:
  		[^self].
  	manager setIsMarkedOf: stackOrNil to: true.
  	self assert: (manager numSlotsOfAny: stackOrNil) = ObjStackPageSlots.
  	field := manager fetchPointer: ObjStackNextx ofObject: stackOrNil.
  	field ~= 0 ifTrue:
  		[self markAndTraceObjStack: field andContents: markAndTraceContents].
  	field := stackOrNil.
  	[field := manager fetchPointer: ObjStackFreex ofObject: field.
  	 field ~= 0] whileTrue:
  		[manager setIsMarkedOf: field to: true].
  	markAndTraceContents ifFalse:
  		[^self].
  	"There are four fixed slots in an obj stack, and a Topx of 0 indicates empty, so
  	  if there were 6 slots in an oop stack, full would be 2, and the last 0-rel index is 5."
  	index := (manager fetchPointer: ObjStackTopx ofObject: stackOrNil) + ObjStackNextx.
  	[index >= ObjStackFixedSlots] whileTrue:
  		[field := manager followObjField: index ofObject: stackOrNil.
  		 (manager isImmediate: field) ifFalse:
+ 			[self markAndTrace: field].
- 			[self doMarkAndTrace: field].
  		 index := index - 1]!

Item was changed:
  ----- Method: SpurMarker>>markAndTraceWeaklingsFrom: (in category 'weakness and ephemerality') -----
  markAndTraceWeaklingsFrom: startIndex
  	"Mark weaklings on the weaklingStack, ignoring startIndex
  	 number of elements on the bottom of the stack.  Answer
  	 the size of the stack *before* the enumeration began."
  	^manager objStack: manager weaklingStack from: startIndex do:
  		[:weakling|
  		 self deny: (manager isForwarded: weakling).
  		 self markAndTraceClassOf: weakling.
  		"N.B. generateToByDoLimitExpression:negative:on: guards against (unsigned)0 - 1 going +ve"
  		 0 to: (manager numStrongSlotsOfWeakling: weakling) - 1 do:
  			[:i| | field |
  			field := manager followOopField: i ofObject: weakling.
  			((manager isImmediate: field) or: [manager isMarked: field]) ifFalse:
+ 				[self markAndTrace: field]]]!
- 				[self doMarkAndTrace: field]]]!

Item was changed:
  ----- Method: SpurMarker>>markInactiveEphemerons (in category 'weakness and ephemerality') -----
  markInactiveEphemerons
  	"Go through the unscanned ephemerons, marking the inactive ones, and
  	 removing them from the unscanned ephemerons. Answer if any inactive
  	 ones were found. We cannot fire the ephemerons until all are found to
  	 be active since scan-marking an inactive ephemeron later in the set may
  	 render a previously-observed active ephemeron as inactive."
  	| foundInactive ptr |
  	foundInactive := false.
  	ptr := manager unscannedEphemerons start.
  	[ptr < manager unscannedEphemerons top] whileTrue:
  		[| ephemeron key |
  		 key := manager followedKeyOfEphemeron: (ephemeron := manager longAt: ptr).
  		 ((manager isImmediate: key) or: [manager isMarked: key])
  			ifTrue:
  				[foundInactive := true.
  				 "Now remove the inactive ephemeron from the set, and scan-mark it.
  				  Scan-marking it may add more ephemerons to the set."
  				 manager unscannedEphemerons top: manager unscannedEphemerons top - manager bytesPerOop.
  				 manager unscannedEphemerons top > ptr ifTrue:
  					[manager longAt: ptr put: (manager longAt: manager unscannedEphemerons top)].
+ 				 self markAndTrace: ephemeron]
- 				 self doMarkAndTrace: ephemeron]
  			ifFalse:
  				[ptr := ptr + manager bytesPerOop]].
  	^foundInactive!

Item was changed:
+ ----- Method: SpurMarker>>markLoopFrom: (in category 'marking') -----
- ----- Method: SpurMarker>>markLoopFrom: (in category 'as yet unclassified') -----
  markLoopFrom: objOop
  	"Scan objOop and all objects on the mark stack, until the mark stack is empty.
  	 N.B. When the incremental GC is written this will probably be refactored as
  	 markLoopFrom: objOop while: aBlock"
  	<inline: true>
  	| objToScan field index numStrongSlots scanLargeObject |
  
  	"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."
  	[(manager isImmediate: objToScan)
  		ifTrue: [scanLargeObject := true]
  		ifFalse:
  			[numStrongSlots := manager numStrongSlotsOfInephemeral: objToScan.
  			 scanLargeObject := numStrongSlots > self traceImmediatelySlotLimit].
  	 scanLargeObject
  		ifTrue: "scanning a large object. scan until hitting an unmarked object, then switch to it, if any."
  			[(manager isImmediate: objToScan)
  				ifTrue:
  					[index := manager integerValueOf: objToScan.
  					 objToScan := manager topOfObjStack: manager markStack]
  				ifFalse:
  					[index := numStrongSlots.
  					 self markAndTraceClassOf: objToScan].
  			 [index > 0] whileTrue:
  				[index := index - 1.
  				 field := manager fetchPointer: index ofObject: objToScan.
  				 (manager isNonImmediate: field) ifTrue:
  					[(manager isForwarded: field) ifTrue: "fixFollowedField: is /not/ inlined"
  						[field := manager fixFollowedField: index ofObject: objToScan withInitialValue: field].
  					 (self markAndShouldScan: field) ifTrue:
  						[index > 0 ifTrue:
  							[(manager topOfObjStack: manager markStack) ~= objToScan ifTrue: 
  								[manager push: objToScan onObjStack: manager markStack].
  							 manager push: (manager integerObjectOf: index) onObjStack: manager markStack].
  						 objToScan := field.
  						 index := -1]]].
  			 index >= 0 ifTrue: "if loop terminated without finding an unmarked referent, switch to top of stack."
  				[objToScan := manager popObjStack: manager markStack.
  				 objToScan = objOop ifTrue:
  					[objToScan := manager popObjStack: manager 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 := manager fetchPointer: index ofObject: objToScan.
  				 (manager isNonImmediate: field) ifTrue:
  					[(manager isForwarded: field) ifTrue: "fixFollowedField: is /not/ inlined"
  						[field := manager fixFollowedField: index ofObject: objToScan withInitialValue: field].
  					 (self markAndShouldScan: field) ifTrue:
  						[manager push: field onObjStack: manager markStack.
  						 ((manager rawNumSlotsOf: field) > self traceImmediatelySlotLimit
  						  and: [(numStrongSlots := manager numStrongSlotsOfInephemeral: field) > self traceImmediatelySlotLimit]) ifTrue:
  							[manager push: (manager integerObjectOf: numStrongSlots) onObjStack: manager markStack]]]].
  			 objToScan := manager popObjStack: manager markStack].
  	 objToScan notNil] whileTrue!

Item was changed:
+ ----- Method: SpurMarker>>markObjects: (in category 'marking') -----
- ----- Method: SpurMarker>>markObjects: (in category 'as yet unclassified') -----
  markObjects: objectsShouldBeUnmarkedAndUnmarkedClassesShouldBeExpunged
  	<inline: #never> "for profiling"
  	"Mark all accessible objects.  objectsShouldBeUnmarkedAndUnmarkedClassesShouldBeExpunged
  	 is true if all objects are unmarked and/or if unmarked classes shoud be removed from the class table."
  	"If the incremental collector is running mark bits may be set; stop it and clear them if necessary."
  	self cCode: '' inSmalltalk: [coInterpreter transcript nextPutAll: 'marking...'; flush].
  	manager runLeakCheckerFor: GCModeFull.
  
  	manager shutDownGlobalIncrementalGC: objectsShouldBeUnmarkedAndUnmarkedClassesShouldBeExpunged.
  	manager initializeUnscannedEphemerons.
  	manager initializeMarkStack.
  	manager initializeWeaklingStack.
  	marking := true.
  	self markAccessibleObjectsAndFireEphemerons.
  	manager expungeDuplicateAndUnmarkedClasses: objectsShouldBeUnmarkedAndUnmarkedClassesShouldBeExpunged.
  	manager nilUnmarkedWeaklingSlots.
  	marking := false!

Item was changed:
+ ----- Method: SpurMarker>>marking (in category 'marking') -----
- ----- Method: SpurMarker>>marking (in category 'as yet unclassified') -----
  marking 
  
  	^ marking!

Item was changed:
+ ----- Method: SpurMarker>>traceImmediatelySlotLimit (in category 'marking') -----
- ----- Method: SpurMarker>>traceImmediatelySlotLimit (in category 'as yet unclassified') -----
  traceImmediatelySlotLimit
  	"Arbitrary level at which to defer tracing large objects until later.
  	 The average slot size of Smalltalk objects is typically near 8.
  	 We do require traceImmediatelySlotLimit to be < numSlotsMask."
  	^64!

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. This behaviour is now
+ 	 extracted to the SpurMarker hierarchy, so bridge to it."
+ 	<doNotGenerate>
- 	 on the mark stack. Follow forwarding pointers in the scan."
- 	<api>
- 	<inline: #never>
  
+ 	^marker markAndTrace: objOop!
- 	marker doMarkAndTrace: objOop!



More information about the Vm-dev mailing list