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

commits at source.squeak.org commits at source.squeak.org
Wed Jun 24 01:41:29 UTC 2020


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

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

Name: VMMaker.oscog-eem.2765
Author: eem
Time: 23 June 2020, 6:41:19.556484 pm
UUID: 91b9976e-60b9-4b5c-a2f8-b621dd454a07
Ancestors: VMMaker.oscog-eem.2764

Spur: Rewrite the revised followForwardedObjectFields:toDepth: soi it can be correctly inlined.

Slang: Change the order of application of ensureConditionalAssignmentsAreTransformedIn: so it is always the last thing done in tryToInlineMethodsIn:.

Straight-forward optimization of bindVariablesIn: in the common case of methods being inlined swith unchanged parameters.

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

Item was changed:
  ----- Method: Spur32BitCoMemoryManager>>followForwardedObjectFields:toDepth: (in category 'as yet unclassified') -----
  followForwardedObjectFields: objOop toDepth: depth
  	"Follow pointers in the object to depth.
  	 Answer if any forwarders were found.
  	 How to avoid cyclic structures?? A temporary mark bit? eem 6/22/2020 no need since depth is always finite."
  	<api>
  	<inline: false>
+ 	| found fmt limit |
- 	| oop found fmt |
  	found := false.
  	self assert: ((self isPointers: objOop) or: [self isOopCompiledMethod: objOop]).
  	fmt := self formatOf: objOop.
+ 	limit := (self numPointerSlotsOf: objOop format: fmt) - 1.
  	"It is essential to skip the first field of a method because it may be a
  	 reference to a Cog method in the method zone, not a real object at all."
  	((self isCompiledMethodFormat: fmt)
  			ifTrue: [1]
  			ifFalse: [0])
+ 		to: limit
+ 		do: [:i| | oop |
- 		to: (self numPointerSlotsOf: objOop format: fmt) - 1
- 		do: [:i|
  			 oop := self fetchPointer: i ofObject: objOop.
  			 (self isNonImmediate: oop) ifTrue:
  				[(self isForwarded: oop) ifTrue:
  					[found := true.
  					 oop := self followForwarded: oop.
  					 self storePointer: i ofObject: objOop withValue: oop].
  				(depth > 0
  				 and: [(self hasPointerFields: oop)
  				 and: [self followForwardedObjectFields: oop toDepth: depth - 1]]) ifTrue:
  					[found := true]]].
  	^found!

Item was changed:
  ----- Method: Spur64BitCoMemoryManager>>followForwardedObjectFields:toDepth: (in category 'forwarding') -----
  followForwardedObjectFields: objOop toDepth: depth
  	"Follow pointers in the object to depth.
  	 Answer if any forwarders were found.
  	 How to avoid cyclic structures?? A temporary mark bit? eem 6/22/2020 no need since depth is always finite."
  	<api>
  	<inline: false>
+ 	| found fmt limit |
- 	| oop found fmt |
  	found := false.
  	self assert: ((self isPointers: objOop) or: [self isOopCompiledMethod: objOop]).
  	fmt := self formatOf: objOop.
+ 	limit := (self numPointerSlotsOf: objOop format: fmt) - 1.
  	"It is essential to skip the first field of a method because it may be a
  	 reference to a Cog method in the method zone, not a real object at all."
  	((self isCompiledMethodFormat: fmt)
  			ifTrue: [1]
  			ifFalse: [0])
+ 		to: limit
+ 		do: [:i| | oop |
- 		to: (self numPointerSlotsOf: objOop format: fmt) - 1
- 		do: [:i|
  			 oop := self fetchPointer: i ofObject: objOop.
  			 (self isNonImmediate: oop) ifTrue:
  				[(self isForwarded: oop) ifTrue:
  					[found := true.
  					 oop := self followForwarded: oop.
  					 self storePointer: i ofObject: objOop withValue: oop].
  				(depth > 0
  				 and: [(self hasPointerFields: oop)
  				 and: [self followForwardedObjectFields: oop toDepth: depth - 1]]) ifTrue:
  					[found := true]]].
  	^found!

Item was changed:
  ----- Method: TMethod>>exitVar:label:in: (in category 'inlining') -----
  exitVar: exitVar label: exitLabel in: aCodeGen
  	"Replace each return statement in this method with an assignment to the
  	 exit variable followed by either a return or a goto to the given label.
  	 Answer if a goto was generated."
  	"Optimization: If exitVar is nil, the return value of the inlined method is not being used, so don't add the assignment statement."
  
  	| labelUsed map elisions eliminateReturnSelfs |
  	labelUsed := false.
  	map := Dictionary new.
  	elisions := Set new.
  	"Conceivably one might ^self from a struct class and mean it.  In most cases though
  	 ^self means `get me outta here, fast'.  So unless this method is from a VMStruct class,
  	 elide any ^self's"
  	eliminateReturnSelfs := ((definingClass inheritsFrom: VMClass) and: [definingClass isStructClass]) not
  							  and: [returnType = #void or: [returnType = #sqInt]].
  	parseTree nodesDo:
  		[:node | | replacement |
  		node isReturn ifTrue:
  			[self transformReturnSubExpression: node
  				toAssignmentOf: exitVar
  				andGoto: exitLabel
  				unless: eliminateReturnSelfs
  				into: [:rep :labelWasUsed|
  					replacement := rep.
  					labelWasUsed ifTrue: [labelUsed := true]]
  				in: aCodeGen.
  			"replaceNodesIn: is strictly top-down, so any replacement for ^expr ifTrue: [...^fu...] ifFalse: [...^bar...]
  			 will prevent replacement of either ^fu or ^bar. The corollary is that ^expr ifTrue: [foo] ifFalse: [^bar]
  			 must be transformed into expr ifTrue: [^foo] ifFalse: [^bar]"
  			(node expression isConditionalSend
  			 and: [node expression hasExplicitReturn])
  				ifTrue:
  					[elisions add: node.
  					 (node expression args reject: [:arg| arg endsWithReturn]) do:
  						[:nodeNeedingReturn|
  						 self transformReturnSubExpression: nodeNeedingReturn statements last
  							toAssignmentOf: exitVar
  							andGoto: exitLabel
  							unless: eliminateReturnSelfs
  							into: [:rep :labelWasUsed|
  								replacement := rep.
+ 								labelWasUsed ifTrue: [labelUsed := true]]
+ 							in: aCodeGen.
- 								labelWasUsed ifTrue: [labelUsed := true]].
  						 map
  							at: nodeNeedingReturn statements last
  							put: replacement]]
  				ifFalse:
  					[map
  						at: node
  						put: (replacement ifNil:
  								[TLabeledCommentNode new setComment: 'return ', node expression printString])]]].
  	map isEmpty ifTrue:
  		[self deny: labelUsed.
  		 ^false].
  	"Now do a top-down replacement for all returns that should be mapped to assignments and gotos"
  	parseTree replaceNodesIn: map.
  	"Now it is safe to eliminate the returning ifs..."
  	elisions isEmpty ifFalse:
  		[| elisionMap |
  		 elisionMap := Dictionary new.
  		 elisions do: [:returnNode| elisionMap at: returnNode put: returnNode expression].
  		 parseTree replaceNodesIn: elisionMap].
  	"Now flatten any new statement lists..."
  	parseTree nodesDo:
  		[:node| | list |
  		(node isStmtList
  		 and: [node statements notEmpty
  		 and: [node statements last isStmtList]]) ifTrue:
  			[list := node statements last statements.
  			 node statements removeLast; addAllLast: list]].
  	^labelUsed!

Item was changed:
  ----- Method: TMethod>>inlineFunctionCall:in: (in category 'inlining') -----
  inlineFunctionCall: aSendNode in: aCodeGen
  	"Answer the body of the called function, substituting the actual
  	 parameters for the formal argument variables in the method body.
  	 Assume caller has established that:
  		1. the method arguments are all substitutable nodes, and
  		2. the method to be inlined contains no additional embedded returns."
  
  	| sel meth doNotRename argsForInlining substitutionDict |
+ 	aCodeGen maybeBreakForInlineOf: aSendNode in: self.
  	sel := aSendNode selector.
  	meth := (aCodeGen methodNamed: sel) copy.
  	meth ifNil:
  		[^self inlineBuiltin: aSendNode in: aCodeGen].
  	doNotRename := Set withAll: args.
  	argsForInlining := aSendNode argumentsForInliningCodeGenerator: aCodeGen.
  	meth args with: argsForInlining do:
  		[ :argName :exprNode |
  		exprNode isLeaf ifTrue:
  			[doNotRename add: argName]].
  	(meth statements size = 2
  	and: [meth statements first isSend
  	and: [meth statements first selector == #flag:]]) ifTrue:
  		[meth statements removeFirst].
  	meth renameVarsForInliningInto: self except: doNotRename in: aCodeGen.
  	meth renameLabelsForInliningInto: self.
  	self addVarsDeclarationsAndLabelsOf: meth except: doNotRename.
  	substitutionDict := Dictionary new: meth args size * 2.
  	meth args with: argsForInlining do:
  		[ :argName :exprNode |
+ 		(exprNode isVariable and: [exprNode name = argName]) ifFalse:
+ 			[substitutionDict at: argName put: exprNode].
- 		substitutionDict at: argName put: exprNode.
  		(doNotRename includes: argName) ifFalse:
  			[locals remove: argName]].
  	meth parseTree bindVariablesIn: substitutionDict.
  	^meth parseTree endsWithReturn
  		ifTrue: [meth parseTree copyWithoutReturn]
  		ifFalse: [meth parseTree]!

Item was changed:
  ----- Method: TMethod>>tryToInlineMethodsIn: (in category 'inlining') -----
  tryToInlineMethodsIn: aCodeGen
  	"Expand any (complete) inline methods sent by this method.
  	 Set the complete flag when all inlining has been done.
  	 Answer if something was inlined."
  
  	| didSomething statementLists |
  	"complete ifTrue:
  		[^false]."
  
  	self definedAsMacro ifTrue:
  		[complete ifTrue:
  			[^false].
  		 ^complete := true].
  
- 	self ensureConditionalAssignmentsAreTransformedIn: aCodeGen.
  	didSomething := self tryToInlineMethodStatementsIn: aCodeGen statementListsInto: [:stmtLists| statementLists := stmtLists].
  	didSomething := (self tryToInlineMethodExpressionsIn: aCodeGen) or: [didSomething].
+ 	self ensureConditionalAssignmentsAreTransformedIn: aCodeGen.
  
  	didSomething ifTrue:
  		[writtenToGlobalVarsCache := nil].
  
  	complete ifFalse:
  		[self checkForCompletenessIn: aCodeGen.
  		 complete ifTrue: [didSomething := true]].  "marking a method complete is progress"
  	^didSomething!

Item was changed:
  ----- Method: TStmtListNode>>bindVariablesIn: (in category 'transformations') -----
  bindVariablesIn: aDictionary
  
+ 	aDictionary notEmpty ifTrue:
+ 		[statements := statements collect: [:s| s bindVariablesIn: aDictionary]]!
- 	statements := statements collect: [ :s | s bindVariablesIn: aDictionary ].!



More information about the Vm-dev mailing list