[Vm-dev] VM Maker: VMMaker.oscog-cb.1812.mcz

commits at source.squeak.org commits at source.squeak.org
Sun Apr 17 20:38:22 UTC 2016


ClementBera uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1812.mcz

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

Name: VMMaker.oscog-cb.1812
Author: cb
Time: 17 April 2016, 1:36:41.145733 pm
UUID: 66d654ed-d03d-469b-a8b5-9b8d35bd885e
Ancestors: VMMaker.oscog-cb.1811

- Fix in in-image compilation when compiling too many methods from the image
- refactored annotateUse in CogSimStackEntry to share code between methods
- tried to make some sense out of the fixup merge logic. Now all return and unconditionnal jumps marked explicitely the execution flow as being deadCode. At each merge point, depending if the execution can fall through or not, handle the merge differently.

I will merge with Nice code later when we will have igured out what to do and what not to do.

=============== Diff against VMMaker.oscog-cb.1811 ===============

Item was changed:
  ----- Method: CogMethodZone>>freeMethod: (in category 'compaction') -----
  freeMethod: cogMethod
  	<api>
  	<var: #cogMethod type: #'CogMethod *'>
  	<inline: false>
  	self assert: cogMethod cmType ~= CMFree.
  	self assert: ((cogit cogMethodDoesntLookKosher: cogMethod) = 0
  				 or: [(cogit cogMethodDoesntLookKosher: cogMethod) = 23
  					 and: [(cogit cCoerceSimple: cogMethod methodObject to: #'CogMethod *') cmType = CMFree]]).
  	cogMethod cmType = CMMethod ifTrue:
  		["For non-Newspeak there should ne a one-to-one mapping between bytecoded and
  		  cog methods.  For Newspeak not necessarily, but only for anonymous accessors."
  		"Only reset the original method's header if it is referring to this CogMethod."
  		 (coInterpreter rawHeaderOf: cogMethod methodObject) asInteger = cogMethod asInteger
  			ifTrue:
  				[coInterpreter rawHeaderOf: cogMethod methodObject put: cogMethod methodHeader.
  				 NewspeakVM ifTrue:
  					[(objectRepresentation canPinObjects and: [cogMethod nextMethodOrIRCs ~= 0]) ifTrue:
  						[objectRepresentation freeIRCs: cogMethod nextMethodOrIRCs]]]
  			ifFalse:
+ 				[self cCode: [self assert: (cogit noAssertMethodClassAssociationOf: cogMethod methodObject) = objectMemory nilObject]
+ 					inSmalltalk: [self assert: ((cogit noAssertMethodClassAssociationOf: cogMethod methodObject) = objectMemory nilObject
+ 											or: [coInterpreter isKindOf: CurrentImageCoInterpreterFacade])].
- 				[self assert: (cogit noAssertMethodClassAssociationOf: cogMethod methodObject) = objectMemory nilObject.
  				 NewspeakVM ifTrue:
  					[self removeFromUnpairedMethodList: cogMethod]].
  		 cogit maybeFreeCountersOf: cogMethod].
  	cogMethod cmType = CMOpenPIC ifTrue:
  		[self removeFromOpenPICList: cogMethod].
  	cogMethod cmRefersToYoung: false.
  	cogMethod cmType: CMFree.
  	methodBytesFreedSinceLastCompaction := methodBytesFreedSinceLastCompaction
  												+ cogMethod blockSize!

Item was added:
+ ----- Method: CogSSBytecodeFixup>>isMergeFixup (in category 'testing') -----
+ isMergeFixup
+ 	<inline: true>
+ 	^ targetInstruction asUnsignedInteger = NeedsMergeFixupFlag!

Item was added:
+ ----- Method: CogSSBytecodeFixup>>isNonMergeFixup (in category 'testing') -----
+ isNonMergeFixup
+ 	<inline: true>
+ 	^ targetInstruction asUnsignedInteger = NeedsNonMergeFixupFlag!

Item was changed:
  ----- Method: CogSimStackEntry>>ensureSpilledAt:from: (in category 'compile abstract instructions') -----
  ensureSpilledAt: baseOffset from: baseRegister
  	| inst |
  	<var: #inst type: #'AbstractInstruction *'>
  	spilled ifTrue:
  		[type = SSSpill ifTrue:
  			[self assert: (offset = baseOffset and: [register = baseRegister]).
  			 ^self]].
  	self assert: type ~= SSSpill.
  	cogit traceSpill: self.
  	type = SSConstant
  		ifTrue:
  			[inst := cogit genPushConstant: constant]
  		ifFalse:
  			[type = SSBaseOffset
  				ifTrue:
  					[cogit MoveMw: offset r: register R: TempReg.
  					 inst := cogit PushR: TempReg]
  				ifFalse:
  					[self assert: type = SSRegister.
  					 inst := cogit PushR: register].
  			 type := SSSpill.
  			 offset := baseOffset.
  			 register := baseRegister].
  	spilled := true.
+ 	self maybeAnnotateUse: inst!
- 	annotateUse ifTrue:
- 		[cogit annotateBytecode: inst.
- 		 annotateUse := false]!

Item was added:
+ ----- Method: CogSimStackEntry>>maybeAnnotateUse: (in category 'compile abstract instructions') -----
+ maybeAnnotateUse: inst
+ 	<inline: true>
+ 	annotateUse ifTrue:
+ 		[inst annotation = 0
+ 			ifTrue: [cogit annotateBytecode: inst]
+ 			ifFalse: [cogit annotateBytecode: cogit Label].
+ 		 annotateUse := false]!

Item was removed:
- ----- Method: CogSimStackEntry>>mergeAt:from: (in category 'compile abstract instructions') -----
- mergeAt: baseOffset from: baseRegister
- 	"Discard type information because of a control-flow merge."
- 	self assert: spilled.
- 	type = SSSpill
- 		ifTrue:
- 			[self assert: (offset = baseOffset and: [register = baseRegister])]
- 		ifFalse:
- 			[type := SSSpill.
- 			 offset := baseOffset.
- 			 register := baseRegister]!

Item was changed:
  ----- Method: CogSimStackEntry>>popToReg: (in category 'compile abstract instructions') -----
  popToReg: reg
  	| inst |
  	<var: #inst type: #'AbstractInstruction *'>
  	spilled
  		ifTrue:
  			[inst := cogit PopR: reg]
  		ifFalse:
  			[type caseOf: {
  				[SSBaseOffset]	-> [inst := cogit MoveMw: offset r: register R: reg].
  				[SSConstant]	-> [inst := cogit genMoveConstant: constant R: reg].
  				[SSRegister]	-> [inst := reg ~= register
  												ifTrue: [cogit MoveR: register R: reg]
  												ifFalse: [cogit Label]] }].
+ 	self maybeAnnotateUse: inst!
- 	annotateUse ifTrue:
- 		[cogit annotateBytecode: inst.
- 		 annotateUse := false]!

Item was changed:
  ----- Method: CogSimStackEntry>>storeToReg: (in category 'compile abstract instructions') -----
  storeToReg: reg
  	| inst |
  	<var: #inst type: #'AbstractInstruction *'>
  	type caseOf: {
  		[SSBaseOffset]	-> [inst := cogit MoveMw: offset r: register R: reg].
  		[SSSpill]		-> [inst := cogit MoveMw: offset r: register R: reg].
  		[SSConstant]	-> [inst := cogit genMoveConstant: constant R: reg].
  		[SSRegister]	-> [inst := reg ~= register
  										ifTrue: [cogit MoveR: register R: reg]
  										ifFalse: [cogit Label]] }.
+ 	self maybeAnnotateUse: inst!
- 	annotateUse ifTrue:
- 		[cogit annotateBytecode: inst.
- 		 annotateUse := false]!

Item was changed:
  ----- Method: Cogit class>>testPCMappingSelect:options: (in category 'tests') -----
  testPCMappingSelect: aBlock options: optionsDictionaryOrArray
  	"Test pc mapping both ways using a selection of the methods in the current image."
  	| cogit coInterpreter |
  	cogit := self instanceForTests: optionsDictionaryOrArray.
  	coInterpreter := CurrentImageCoInterpreterFacade forCogit: cogit.
  	[cogit
  			setInterpreter: coInterpreter;
  			singleStep: true;
  			initializeCodeZoneFrom: 1024 upTo: coInterpreter memory size]
  		on: Notification
  		do: [:ex|
  			(ex messageText beginsWith: 'cannot find receiver for') ifTrue:
  				[ex resume: coInterpreter]].
  	SystemNavigation new allSelect:
  		[:m| | cm |
  		(m isQuick not
  		 and: [aBlock value: m]) ifTrue:
  			[Transcript nextPut: $.; flush.
+ 			 cm := cogit
- 			 [coInterpreter.
- 			  cm := cogit
  						cog: (coInterpreter oopForObject: m)
  						selector: (coInterpreter oopForObject: m selector).
+ 			  cm ifNil:
- 			   cm isNil and: [coInterpreter isCogCompiledCodeCompactionCalledFor]] whileTrue:
  				[cogit methodZone clearCogCompiledCode.
+ 				 coInterpreter initializeObjectMap.
+ 				 cm := cogit
+ 							cog: (coInterpreter oopForObject: m)
+ 							selector: (coInterpreter oopForObject: m selector).
+ 				cm ifNil: [Transcript show: 'After 1 Cog compiled code compaction, still not able to generate the cog method...' ] ].
+ 			  cm ifNotNil:
+ 				[cogit testPCMappingForCompiledMethod: m cogMethod: cm]].
+ 		 false] !
- 				 coInterpreter clearCogCompiledCodeCompactionCalledFor.
- 				 coInterpreter initializeObjectMap].
- 			 cogit testPCMappingForCompiledMethod: m cogMethod: cm].
- 		 false]!

Item was changed:
  ----- Method: CurrentImageCoInterpreterFacade>>cCoerceSimple:to: (in category 'debug support') -----
  cCoerceSimple: value to: cTypeString
  	"Type coercion for translation and simulation.
  	 For simulation answer a suitable surrogate for the struct types"
  	^cTypeString
  		caseOf:
+ 		   {	[#'CogMethod *']		->	[value < 0 ifTrue: [value] ifFalse: [cogit cogMethodSurrogateAt: value asUnsignedInteger]].
- 		   {	[#'CogMethod *']		->	[cogit cogMethodSurrogateAt: value asUnsignedInteger].
  			[#'CogBlockMethod *']	->	[cogit cogBlockMethodSurrogateAt: value asUnsignedInteger] }
  		otherwise: [super cCoerceSimple: value to: cTypeString]!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>compileAbstractInstructionsFrom:through: (in category 'compile abstract instructions') -----
  compileAbstractInstructionsFrom: start through: end
  	"Loop over bytecodes, dispatching to the generator for each bytecode, handling fixups in due course."
  	| nextOpcodeIndex descriptor nExts fixup result |
  	<var: #descriptor type: #'BytecodeDescriptor *'>
  	<var: #fixup type: #'BytecodeFixup *'>
  	self traceSimStack.
  	bytecodePC := start.
  	nExts := 0.
  	descriptor := nil.
  	deadCode := false.
  	[self cCode: '' inSmalltalk:
  		[(debugBytecodePointers includes: bytecodePC) ifTrue: [self halt]].
+ 	 fixup := self fixupAt: bytecodePC - initialPC.
+ 	 "If there's no fixup following a return there's no jump to that code and it is dead."
+ 	 (descriptor notNil and: [descriptor isReturn]) ifTrue: [deadCode := true].
+ 	 self mergeWithFixupIfRequired: fixup.
- 	fixup := self fixupAt: bytecodePC - initialPC.
- 	"If there's no fixup following a return there's no jump to that code and it is dead."
- 	(descriptor notNil and: [descriptor isReturn]) ifTrue: [deadCode := true].
- 	fixup needsFixupOrIsFixedUp ifTrue:
- 		[fixup isMergeFixupOrIsFixedUp ifTrue:
- 			[self merge: fixup afterContinuation: deadCode not].
- 		deadCode := false].
  	 self cCode: '' inSmalltalk:
  		[deadCode ifFalse:
  			[self assert: simStackPtr + (needsFrame ifTrue: [0] ifFalse: [1])
  						= (self debugStackPointerFor: bytecodePC)]].
  	 byte0 := (objectMemory fetchByte: bytecodePC ofObject: methodObj) + bytecodeSetOffset.
  	 descriptor := self generatorAt: byte0.
  	 self loadSubsequentBytesForDescriptor: descriptor at: bytecodePC.
  	 nextOpcodeIndex := opcodeIndex.
  	 result := deadCode
  				ifTrue: "insert nops for dead code that is mapped so that bc to mc mapping is not many to one"
  					[(descriptor isMapped
  					  or: [inBlock and: [descriptor isMappedInBlock]]) ifTrue:
  						[self annotateBytecode: self Nop].
  						0]
  				ifFalse:
  					[self perform: descriptor generator].
  	 descriptor isExtension ifFalse: "extended bytecodes must consume their extensions"
  		[self assert: (extA = 0 and: [extB = 0])].
  	 self traceDescriptor: descriptor; traceSimStack.
  	 fixup needsFixup ifTrue:
  		["There is a fixup for this bytecode.  It must point to the first generated
  		   instruction for this bytecode.  If there isn't one we need to add a label."
  		 opcodeIndex = nextOpcodeIndex ifTrue: [self Label].
  		 fixup targetInstruction: (self abstractInstructionAt: nextOpcodeIndex)].
  	 self maybeDumpLiterals: descriptor.
  	 bytecodePC := self nextBytecodePCFor: descriptor at: bytecodePC exts: nExts in: methodObj.
  	 result = 0 and: [bytecodePC <= end]] whileTrue:
  		[nExts := descriptor isExtension ifTrue: [nExts + 1] ifFalse: [0]].
  	self checkEnoughOpcodes.
  	^result!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genBlockReturn (in category 'bytecode generators') -----
+ genBlockReturn
+ 	"Return from block, assuming result already loaded into ReceiverResultReg."
+ 	super genBlockReturn.
+ 	deadCode := true. "can't fall through"
+ 	^0!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genJumpBackTo: (in category 'bytecode generator support') -----
  genJumpBackTo: targetBytecodePC
  	self ssFlushTo: simStackPtr.
+ 	deadCode := true. "can't fall through"
  	^super genJumpBackTo: targetBytecodePC!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genJumpTo: (in category 'bytecode generator support') -----
  genJumpTo: targetBytecodePC
  	self ssFlushTo: simStackPtr.
+ 	deadCode := true. "can't fall through"
  	^super genJumpTo: targetBytecodePC!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genUpArrowReturn (in category 'bytecode generators') -----
  genUpArrowReturn
  	"Generate a method return from within a method or a block.
  	 Frameless method activation looks like
  	 CISCs (x86):
  				receiver
  				args
  		sp->	ret pc.
  	 RISCs (ARM):
  				receiver
  				args
  				ret pc in LR.
  	 A fully framed activation is described in CoInterpreter class>initializeFrameIndices.
  	 Return pops receiver and arguments off the stack.  Callee pushes the result."
  	inBlock ifTrue:
  		[self assert: needsFrame. 
  		 self CallRT: ceNonLocalReturnTrampoline.
  		 self annotateBytecode: self Label.
  		 ^0].
  	needsFrame
  		ifTrue:
  			[self MoveR: FPReg R: SPReg.
  			 self PopR: FPReg.
  			 backEnd hasLinkRegister ifTrue:
  				[self PopR: LinkReg].
  			 self RetN: methodOrBlockNumArgs + 1 * objectMemory wordSize]
  		ifFalse:
  			[self RetN: ((methodOrBlockNumArgs > self numRegArgs
  						"A method with an interpreter prim will push its register args for the prim.  If the failure
  						 body is frameless the args must still be popped, see e.g. Behavior>>nextInstance."
  						or: [regArgsHaveBeenPushed])
  							ifTrue: [methodOrBlockNumArgs + 1 * objectMemory wordSize]
  							ifFalse: [0])].
+ 	deadCode := true. "can't fall through"
  	^0!

Item was removed:
- ----- Method: StackToRegisterMappingCogit>>merge:afterContinuation: (in category 'simulation stack') -----
- merge: fixup afterContinuation: mergeWithContinuation
- 	"Merge control flow at a fixup.  The fixup holds the simStackPtr at the jump to this target.
- 	 See stackToRegisterMapping on the class side for a full description."
- 	<var: #fixup type: #'BytecodeFixup *'>
- 	self traceMerge: fixup.
- 	"For now we don't try and preserve the optimization status through merges."
- 	optStatus isReceiverResultRegLive: false.
- 	"If this instruction follows a return or an unconditional branch then the
- 	 current simStackPtr is irrelevant and we continue with that of the fixup."
- 	mergeWithContinuation ifFalse:
- 		[self assert: fixup isMergeFixupOrIsFixedUp.  "Must have a valid simStackPtr"
- 		 simStackPtr := fixup simStackPtr].
- 	fixup notYetFixedUp ifTrue:
- 		["This is either a forward or backward branch target.
- 		  The stack must be flushed."
- 		 self ssFlushTo: simStackPtr.
- 		 fixup isBackwardBranchFixup ifTrue:
- 			"This is the target of a backward branch.  It doesn't have a simStackPtr yet."
- 			[fixup simStackPtr: simStackPtr].
- 		 fixup targetInstruction: self Label].
- 	self assert: simStackPtr >= fixup simStackPtr.
- 	self cCode: '' inSmalltalk:
- 		[self assert: fixup simStackPtr = (self debugStackPointerFor: bytecodePC)].
- 	simStackPtr := fixup simStackPtr.
- 	simSpillBase := methodOrBlockNumTemps.
- 	"For now throw away all type information for values on the stack, but sometime consider
- 	 the more sophisticated merge described in the class side stackToRegisterMapping."
- 	methodOrBlockNumTemps to: simStackPtr do:
- 		[:i|
- 		(self simStackAt: i)
- 			mergeAt: FoxMFReceiver - (i - methodOrBlockNumArgs + 1 * objectMemory bytesPerOop)
- 			from: FPReg]!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>mergeWithFixupIfRequired: (in category 'simulation stack') -----
+ mergeWithFixupIfRequired: fixup
+ 	"If this bytecode has a fixup, some kind of merge needs to be done. There are 4 cases:
+ 		1) the bytecode has no fixup (fixup isNotAFixup)
+ 			do nothing
+ 		2) the bytecode has a non merge fixup
+ 			the fixup has needsNonMergeFixup.
+ 			The code generating non merge fixup (currently only special selector code) is responsible
+ 				for the merge so no need to do it.
+ 			We set deadCode to false as the instruction can be reached from jumps.
+ 		3) the bytecode has a merge fixup, but execution flow *cannot* fall through to the merge point.
+ 			the fixup has needsMergeFixup and deadCode = true.
+ 			ignores the current simStack as it does not mean anything 
+ 			restores the simStack to the state the jumps to the merge point expects it to be.
+ 		4) the bytecode has a merge fixup and execution flow *can* fall through to the merge point.
+ 			the fixup has needsMergeFixup and deadCode = false.
+ 			flushes the stack to the stack pointer so the fall through execution path simStack is 
+ 				in the state the merge point expects it to be. 
+ 			restores the simStack to the state the jumps to the merge point expects it to be.
+ 			
+ 	In addition, if this is a backjump merge point, we patch the fixup to hold the current simStackPtr 
+ 	for later assertions."
+ 	
+ 	<var: #fixup type: #'BytecodeFixup *'>
+ 	"case 1"
+ 	fixup notAFixup ifTrue: [^ 0].
+ 
+ 	"case 2"
+ 	fixup isNonMergeFixup ifTrue: [deadCode := false. ^ 0 ].
+ 
+ 	"cases 3 and 4"
+ 	self assert: fixup isMergeFixup.
+ 	self traceMerge: fixup.
+ 	deadCode 
+ 		ifTrue: [simStackPtr := fixup simStackPtr] "case 3"
+ 		ifFalse: [self ssFlushTo: simStackPtr]. "case 4"
+ 	deadCode := false.
+ 	fixup isBackwardBranchFixup ifTrue: [fixup simStackPtr: simStackPtr].
+ 	fixup targetInstruction: self Label.
+ 	self assert: simStackPtr = fixup simStackPtr.
+ 	self cCode: '' inSmalltalk:
+ 		[self assert: fixup simStackPtr = (self debugStackPointerFor: bytecodePC)].
+ 	self restoreSimStackAtMergePoint: fixup.
+ 	
+ 	^0!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>restoreSimStackAtMergePoint: (in category 'simulation stack') -----
+ restoreSimStackAtMergePoint: fixup
+ 	<inline: true>
+ 	"All the execution paths reaching a merge point expected everything to be
+ 	spilled on stack and the optStatus is unknown. Throw away all simStack and 
+ 	optStatus optimization state."
+ 	simSpillBase := methodOrBlockNumTemps.
+ 	optStatus isReceiverResultRegLive: false.
+ 	methodOrBlockNumTemps to: simStackPtr do:
+ 		[:i|
+ 			(self simStackAt: i)
+ 				type: SSSpill;
+ 				offset: FoxMFReceiver - (i - methodOrBlockNumArgs + 1 * objectMemory bytesPerOop);
+ 				register: FPReg;
+ 				spilled: true].
+ 	^ 0!



More information about the Vm-dev mailing list