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

commits at source.squeak.org commits at source.squeak.org
Tue Dec 31 03:25:27 UTC 2019


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

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

Name: VMMaker.oscog-eem.2649
Author: eem
Time: 30 December 2019, 7:25:12.571432 pm
UUID: b9c447b7-95f3-471f-9235-c30a764b9281
Ancestors: VMMaker.oscog-eem.2648

SImulation:
Nil localFP when entering the CoInterpreter through a run-time call.
Add a flag so that run-time calls can be leak checked.
C;lean ups to printing so that the CogOopOnspector doesn't get interrupted with halts and doesn't see "VMObjectProxy for" noise.
Abstract forwarder printing, and use it when printing a dead object in new space (a forwarded corpse).

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

Item was changed:
  ----- Method: CoInterpreter>>assertValidExternalStackPointers (in category 'debug support') -----
  assertValidExternalStackPointers
+ 	"For use *ONLY* by routines coming in to the VM,
+ 	 i.e. handleCallOrJumpSimulationTrap:.  This is because it nils localFP as a side-effect."
  	self assert: framePointer < stackPage baseAddress.
  	self assert: stackPointer < framePointer.
  	self assert: framePointer > stackPointer.
+ 	self assert: stackPointer >= (stackPage realStackLimit - self stackLimitOffset).
+ 	localFP := nil!
- 	self assert: stackPointer >= (stackPage realStackLimit - self stackLimitOffset)!

Item was changed:
  ----- Method: Cogit>>handleCallOrJumpSimulationTrap: (in category 'simulation only') -----
  handleCallOrJumpSimulationTrap: aProcessorSimulationTrap
  	<doNotGenerate>
  	| evaluable function memory result savedFramePointer savedStackPointer savedArgumentCount leaf retpc |
+ 	objectMemory maybeLeakCheckForRuntimeCall.
  	evaluable := simulatedTrampolines
  					at: aProcessorSimulationTrap address
  					ifAbsent: [self errorProcessingSimulationTrap: aProcessorSimulationTrap
  								in: simulatedTrampolines].
  	function := evaluable isBlock
  					ifTrue: ['aBlock; probably some plugin primitive']
  					ifFalse:
  						[evaluable receiver == backEnd ifTrue:
  							[^self handleABICallOrJumpSimulationTrap: aProcessorSimulationTrap evaluable: evaluable].
  						 evaluable selector].
  	function ~~ #ceBaseFrameReturn: ifTrue:
  		[coInterpreter assertValidExternalStackPointers].
  	(backEnd wantsNearAddressFor: function) ifTrue:
  		[^self perform: function with: aProcessorSimulationTrap].
  	memory := coInterpreter memory.
  	aProcessorSimulationTrap type == #call
  		ifTrue:
  			[(leaf := coInterpreter mcprims includes: function)
  				ifTrue:
  					[processor
  						simulateLeafCallOf: aProcessorSimulationTrap address
  						nextpc: aProcessorSimulationTrap nextpc
  						memory: memory.
  					 retpc := processor leafRetpcIn: memory]
  				ifFalse:
  					[processor
  						simulateCallOf: aProcessorSimulationTrap address
  						nextpc: aProcessorSimulationTrap nextpc
  						memory: memory.
  					 retpc := processor retpcIn: memory].
  			 self recordInstruction: {'(simulated call of '. aProcessorSimulationTrap address. '/'. function. ')'}]
  		ifFalse:
  			[leaf := false.
  			 processor
  				simulateJumpCallOf: aProcessorSimulationTrap address
  				memory: memory.
  			 retpc := processor retpcIn: memory. "sideways call; the primitive has pushed a return address."
  			 self recordInstruction: {'(simulated jump to '. aProcessorSimulationTrap address. '/'. function. ')'}].
  	savedFramePointer := coInterpreter framePointer.
  	savedStackPointer := coInterpreter stackPointer.
  	savedArgumentCount := coInterpreter argumentCount.
  	result := ["self halt: evaluable selector."
  		   	   clickConfirm ifTrue:
  			 	[(self confirm: 'skip run-time call?') ifFalse:
  					[clickConfirm := false. self halt]].
  			   evaluable valueWithArguments: (processor
  												postCallArgumentsNumArgs: evaluable numArgs
  												in: memory)]
  				on: ReenterMachineCode
  				do: [:ex| ex return: ex returnValue].
  			
  	coInterpreter assertValidExternalStackPointers.
+ 	objectMemory maybeLeakCheckForRuntimeCall.
  	"Verify the stack layout assumption compileInterpreterPrimitive: makes, provided we've
  	 not called something that has built a frame, such as closure value or evaluate method, or
  	 switched frames, such as primitiveSignal, primitiveWait, primitiveResume, primitiveSuspend et al."
  	(function beginsWith: 'primitive') ifTrue:
  		[coInterpreter checkForLastObjectOverwrite.
  		 coInterpreter primFailCode = 0
  			ifTrue: [(#(	primitiveClosureValue primitiveClosureValueWithArgs primitiveClosureValueNoContextSwitch
  						primitiveFullClosureValue primitiveFullClosureValueWithArgs primitiveFullClosureValueNoContextSwitch
  						primitiveSignal primitiveWait primitiveResume primitiveSuspend primitiveYield
  						primitiveExecuteMethodArgsArray primitiveExecuteMethod
  						primitivePerform primitivePerformWithArgs primitivePerformInSuperclass
  						primitiveTerminateTo primitiveStoreStackp primitiveDoPrimitiveWithArgs)
  							includes: function) ifFalse:
  						["This is a rare case (e.g. in Scorch where a married context's sender is set to nil on trapTrpped and hence the stack layout is altered."
  						 (function == #primitiveSlotAtPut and: [objectMemory isContext: (coInterpreter frameReceiver: coInterpreter framePointer)]) ifFalse:
  							[self assert: savedFramePointer = coInterpreter framePointer.
  							 self assert: savedStackPointer + (savedArgumentCount * objectMemory wordSize)
  									= coInterpreter stackPointer]]]
  			ifFalse:
  				[self assert: savedFramePointer = coInterpreter framePointer.
  				 self assert: savedStackPointer = coInterpreter stackPointer]].
  	result ~~ #continueNoReturn ifTrue:
  		[self recordInstruction: {'(simulated return to '. processor retpcIn: memory. ')'}.
  		 leaf
  			ifTrue: [processor simulateLeafReturnIn: memory]
  			ifFalse: [processor simulateReturnIn: memory].
  		 self assert: processor pc = retpc.
  		 processor smashCallerSavedRegistersWithValuesFrom: 16r80000000 by: objectMemory wordSize in: memory].
  	self assert: (result isInteger "an oop result"
  			or: [result == coInterpreter
  			or: [result == objectMemory
  			or: [#(nil continue continueNoReturn) includes: result]]]).
  	processor cResultRegister: (result
  							ifNil: [0]
  							ifNotNil: [result isInteger
  										ifTrue: [result]
  										ifFalse: [16rF00BA222]])
  
  	"coInterpreter cr.
  	 processor sp + 32 to: processor sp - 32 by: -4 do:
  		[:sp|
  		 sp = processor sp
  			ifTrue: [coInterpreter print: 'sp->'; tab]
  			ifFalse: [coInterpreter printHex: sp].
  		 coInterpreter tab; printHex: (coInterpreter longAt: sp); cr]"!

Item was added:
+ ----- Method: NewObjectMemory>>leakCheckRuntimeCalls (in category 'debug support') -----
+ leakCheckRuntimeCalls
+ 	<doNotGenerate>
+ 	^(checkForLeaks bitAnd: 32) ~= 0!

Item was added:
+ ----- Method: NewObjectMemory>>maybeLeakCheckForRuntimeCall (in category 'debug support') -----
+ maybeLeakCheckForRuntimeCall
+ 	<doNotGenerate>
+ 	(checkForLeaks bitAnd: 32) ~= 0 ifTrue:
+ 		[coInterpreter runLeakChecker]!

Item was changed:
  ----- Method: NewObjectMemory>>setCheckForLeaks: (in category 'debug support') -----
  setCheckForLeaks: integerFlags
+ 	" 0 = do nothing.
+ 	  1 = check for leaks on fullGC (GCModeFull).
+ 	  2 = check for leaks on scavenger (GCModeNewSpace).
+ 	  4 = check for leaks on incremental (GCModeIncremental)
+ 	  8 = check for leaks on become (GCModeBecome)
+ 	 16 = check for leaks on image segments (GCModeImageSegment)
+ 	 32 = check for leaks on simulated run-time call."
- 	"0 = do nothing.
- 	 1 = check for leaks on fullGC.
- 	 2 = check for leaks on incrementalGC.
- 	 8 = check for leaks on become"
  	checkForLeaks := integerFlags!

Item was added:
+ ----- Method: SpurMemoryManager>>leakCheckRuntimeCalls (in category 'debug support') -----
+ leakCheckRuntimeCalls
+ 	<doNotGenerate>
+ 	^(checkForLeaks bitAnd: 32) ~= 0!

Item was added:
+ ----- Method: SpurMemoryManager>>maybeLeakCheckForRuntimeCall (in category 'debug support') -----
+ maybeLeakCheckForRuntimeCall
+ 	<doNotGenerate>
+ 	(checkForLeaks bitAnd: 32) ~= 0 ifTrue:
+ 		[coInterpreter runLeakChecker]!

Item was changed:
  ----- Method: SpurMemoryManager>>setCheckForLeaks: (in category 'spur bootstrap') -----
  setCheckForLeaks: integerFlags
  	" 0 = do nothing.
  	  1 = check for leaks on fullGC (GCModeFull).
  	  2 = check for leaks on scavenger (GCModeNewSpace).
  	  4 = check for leaks on incremental (GCModeIncremental)
  	  8 = check for leaks on become (GCModeBecome)
+ 	 16 = check for leaks on image segments (GCModeImageSegment)
+ 	 32 = check for leaks on simulated run-time call."
- 	 16 = check for leaks on image segments (GCModeImageSegment)"
  	checkForLeaks := integerFlags!

Item was changed:
  ----- Method: StackInterpreter>>printActivationNameFor:receiver:isBlock:firstTemporary: (in category 'debug printing') -----
  printActivationNameFor: aMethod receiver: anObject isBlock: isBlock firstTemporary: maybeMessage
  	| methClass methodSel classObj |
  	<inline: false>
  	isBlock ifTrue:
  		[self print: '[] in '].
  	methClass := self findClassOfMethod: aMethod forReceiver: anObject.
  	methodSel := self findSelectorOfMethod: aMethod.
  	((objectMemory addressCouldBeOop: anObject)
  	 and: [(objectMemory isOopForwarded: anObject) not
  	 and: [self addressCouldBeClassObj: (classObj := objectMemory fetchClassOf: anObject)]])
  		ifTrue:
  			[(classObj = methClass or: [methClass isNil or: [methClass = objectMemory nilObject] "i.e. doits"])
  				ifTrue: [self printNameOfClass: classObj count: 5]
  				ifFalse:
  					[self printNameOfClass: classObj count: 5.
  					 self print: '('.
  					 self printNameOfClass: methClass count: 5.
  					 self print: ')']]
  		ifFalse:
+ 			[self print: 'INVALID RECEIVER'].
- 			[self cCode: '' inSmalltalk: [self halt].
- 			 self print: 'INVALID RECEIVER'].
  	self print: '>'.
  	(objectMemory addressCouldBeOop: methodSel)
  		ifTrue:
  			[methodSel = objectMemory nilObject
  				ifTrue: [self print: '(nil)']
  				ifFalse: [self printStringOf: methodSel]]
  		ifFalse: [self print: 'INVALID SELECTOR'].
  	(methodSel = (objectMemory splObj: SelectorDoesNotUnderstand)
  	and: [(objectMemory addressCouldBeObj: maybeMessage)
  	and: [(objectMemory fetchClassOfNonImm: maybeMessage) = (objectMemory splObj: ClassMessage)]]) ifTrue:
  		["print arg message selector"
  		methodSel := objectMemory fetchPointer: MessageSelectorIndex ofObject: maybeMessage.
  		self print: ' '.
  		self printStringOf: methodSel]!

Item was added:
+ ----- Method: StackInterpreter>>printForwarder: (in category 'debug printing') -----
+ printForwarder: oop
+ 	<inline: false>
+ 	self
+ 		print: ' is a forwarded object to '; printHex: (objectMemory followForwarded: oop);
+ 		print: ' of slot size '; printNum: (objectMemory numSlotsOfAny: oop).
+ 	 objectMemory printHeaderTypeOf: oop.
+ 	 self cr!

Item was changed:
  ----- Method: StackInterpreter>>printOop: (in category 'debug printing') -----
  printOop: oop
  	| cls fmt lastIndex startIP bytecodesPerLine column |
  	<inline: false>
  	(objectMemory isImmediate: oop) ifTrue:
  		[^self shortPrintOop: oop].
  	self printHex: oop.
  	(objectMemory addressCouldBeObj: oop) ifFalse:
+ 		[(oop bitAnd: objectMemory allocationUnit - 1) ~= 0 ifTrue: [^self print: ' is misaligned'; cr].
+ 		 ((objectMemory isInNewSpace: oop)
+ 		  and: [objectMemory isForwarded: oop]) ifTrue:
+ 			[self printForwarder: oop].
+ 		 ^self print: (self whereIs: oop); cr].
- 		[^self print: ((oop bitAnd: objectMemory allocationUnit - 1) ~= 0
- 						ifTrue: [' is misaligned']
- 						ifFalse: [self whereIs: oop]); cr].
  	(objectMemory isFreeObject: oop) ifTrue:
  		[self print: ' is a free chunk of size '; printNum: (objectMemory sizeOfFree: oop).
  		 objectMemory hasSpurMemoryManagerAPI ifTrue:
  			[self print: ' 0th: '; printHex: (objectMemory fetchPointer: 0 ofFreeChunk: oop).
  			 objectMemory printHeaderTypeOf: oop].
  		 ^self cr].
  	(objectMemory isForwarded: oop) ifTrue:
+ 		[^self printForwarder: oop].
- 		[self
- 			print: ' is a forwarded object to '; printHex: (objectMemory followForwarded: oop);
- 			print: ' of slot size '; printNum: (objectMemory numSlotsOfAny: oop).
- 		 objectMemory printHeaderTypeOf: oop.
- 		 ^self cr].
  	self print: ': a(n) '.
  	self printNameOfClass: (cls := objectMemory fetchClassOfNonImm: oop) count: 5.
  	cls = (objectMemory splObj: ClassFloat) ifTrue:
  		[^self cr; printFloat: (objectMemory dbgFloatValueOf: oop); cr].
  	fmt := objectMemory formatOf: oop.
  	fmt > objectMemory lastPointerFormat ifTrue:
  		[self print: ' nbytes '; printNum: (objectMemory numBytesOf: oop)].
  	self cr.
  	(fmt between: objectMemory firstLongFormat and: objectMemory firstCompiledMethodFormat - 1) ifTrue:
  		["This will answer false if splObj: ClassAlien is nilObject"
  		 (self is: oop KindOfClass: (objectMemory splObj: ClassAlien)) ifTrue:
  			[self print: ' datasize '; printNum: (self sizeOfAlienData: oop).
  			self print: ((self isIndirectAlien: oop)
  							ifTrue: [' indirect @ ']
  							ifFalse:
  								[(self isPointerAlien: oop)
  									ifTrue: [' pointer @ ']
  									ifFalse: [' direct @ ']]).
  			 ^self printHex: (self startOfAlienData: oop) asUnsignedInteger; cr].
  		 (objectMemory isWordsNonImm: oop) ifTrue:
  			[lastIndex := 64 min: ((objectMemory numBytesOf: oop) / objectMemory wordSize).
  			 lastIndex > 0 ifTrue:
  				[1 to: lastIndex do:
  					[:index|
  					self space; printHex: (self cCoerceSimple: (objectMemory fetchLong32: index - 1 ofObject: oop)
  											to: #'unsigned int').
  					(index \\ self elementsPerPrintOopLine) = 0 ifTrue:
  						[self cr]].
  				(lastIndex \\ self elementsPerPrintOopLine) = 0 ifFalse:
  					[self cr]].
  			^self].
  		^self printStringOf: oop; cr].
  	"this is nonsense.  apologies."
  	startIP := (objectMemory lastPointerOf: oop) + objectMemory bytesPerOop - objectMemory baseHeaderSize / objectMemory bytesPerOop.
  	lastIndex := 256 min: startIP.
  	lastIndex > 0 ifTrue:
  		[1 to: lastIndex do:
  			[:index|
  			self cCode: [self printHex: (objectMemory fetchPointer: index - 1 ofObject: oop); space]
  				inSmalltalk: [self space; printHex: (objectMemory fetchPointer: index - 1 ofObject: oop); space.
  							 self print: (self shortPrint: (objectMemory fetchPointer: index - 1 ofObject: oop))].
  			(index \\ self elementsPerPrintOopLine) = 0 ifTrue:
  				[self cr]].
  		(lastIndex \\ self elementsPerPrintOopLine) = 0 ifFalse:
  			[self cr]].
  	(objectMemory isCompiledMethod: oop)
  		ifFalse:
  			[startIP > 64 ifTrue: [self print: '...'; cr]]
  		ifTrue:
  			[startIP := startIP * objectMemory wordSize + 1.
  			 lastIndex := objectMemory lengthOf: oop.
  			 lastIndex - startIP > 100 ifTrue:
  				[lastIndex := startIP + 100].
  			 bytecodesPerLine := 8.
  			 column := 1.
  			 startIP to: lastIndex do:
  				[:index| | byte |
  				column = 1 ifTrue:
  					[self cCode: 'printf("0x%08" PRIxSQPTR ": ", (usqIntptr_t)(oop+BaseHeaderSize+index-1))'
  						inSmalltalk: [self print: (oop+objectMemory baseHeaderSize+index-1) hex; print: ': ']].
  				byte := objectMemory fetchByte: index - 1 ofObject: oop.
  				self cCode: 'printf(" %02x/%-3d", (int)byte,(int)byte)'
  					inSmalltalk: [self space; print: (byte radix: 16); printChar: $/; printNum: byte].
  				column := column + 1.
  				column > bytecodesPerLine ifTrue:
  					[column := 1. self cr]].
  			column = 1 ifFalse:
  				[self cr]]!

Item was changed:
  ----- Method: VMCompiledMethodProxy>>literalAt: (in category 'literals') -----
  literalAt: index 
  	^VMObjectProxy new
  		for: (coInterpreter literal: index - 1 ofMethod: oop)
  		coInterpreter: coInterpreter
+ 		objectMemory: objectMemory;
+ 		printPretty: printPretty;
+ 		yourself!
- 		objectMemory: objectMemory!

Item was changed:
  Object subclass: #VMObjectProxy
+ 	instanceVariableNames: 'coInterpreter oop objectMemory printPretty'
- 	instanceVariableNames: 'coInterpreter oop objectMemory'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'VMMaker-Support'!
  
  !VMObjectProxy commentStamp: 'eem 8/6/2014 14:46' prior: 0!
  A VMObjectProxy is a wraper for an oop in the VM, that provides limited access to that oop as an object.
  !

Item was changed:
+ ----- Method: VMObjectProxy>>for:coInterpreter:objectMemory: (in category 'initialization') -----
- ----- Method: VMObjectProxy>>for:coInterpreter:objectMemory: (in category 'initialize-release') -----
  for: aCompiledMethodOop coInterpreter: aCoInterpreter objectMemory: anObjectMemory
  	oop := aCompiledMethodOop.
  	coInterpreter := aCoInterpreter.
+ 	objectMemory := anObjectMemory.
+ 	printPretty := false!
- 	objectMemory := anObjectMemory!

Item was changed:
  ----- Method: VMObjectProxy>>printOn: (in category 'printing') -----
  printOn: aStream
  	| shortPrint |
+ 	 printPretty ifTrue:
+ 		[[aStream nextPutAll: (coInterpreter shortPrint: oop)]
+ 			on: Error
+ 			do: [:ex| oop printOn: aStream base: 16].
+ 		 ^self].
  	shortPrint := [coInterpreter shortPrint: oop]
  				on: Error
  				do: [:ex| ^super printOn: aStream].
  	super printOn: aStream.
  	shortPrint first = $= ifTrue:
  		[shortPrint := shortPrint allButFirst].
  	aStream nextPutAll: ' for '; nextPutAll: shortPrint!

Item was added:
+ ----- Method: VMObjectProxy>>printPretty (in category 'accessing') -----
+ printPretty
+ 	^printPretty!

Item was added:
+ ----- Method: VMObjectProxy>>printPretty: (in category 'accessing') -----
+ printPretty: aBoolean
+ 	printPretty := aBoolean!



More information about the Vm-dev mailing list