<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div dir="ltr"><pre class="tw-data-text tw-text-large XcVN5d tw-ta" data-placeholder="Translation" id="tw-target-text" dir="ltr" style="font-family: inherit; font-size: 24px; line-height: 28px; border: none; padding: 10px 0.14em 10px 0px; position: relative; margin-top: -10px; margin-bottom: -10px; resize: none; overflow: hidden; width: 343px; word-wrap: break-word; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); color: rgb(32, 33, 36) !important;"><span class="Y2IQFc" lang="en">please don't send me more letters !!!</span></pre></div><div dir="ltr"><br><blockquote type="cite">On 2020-06-24, at 04:41, commits@source.squeak.org wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><span></span><br><span>Eliot Miranda uploaded a new version of VMMaker to project VM Maker Inbox:</span><br><span>http://source.squeak.org/VMMakerInbox/VMMaker.oscog-eem.2765.mcz</span><br><span></span><br><span>==================== Summary ====================</span><br><span></span><br><span>Name: VMMaker.oscog-eem.2765</span><br><span>Author: eem</span><br><span>Time: 23 June 2020, 6:41:19.556484 pm</span><br><span>UUID: 91b9976e-60b9-4b5c-a2f8-b621dd454a07</span><br><span>Ancestors: VMMaker.oscog-eem.2764</span><br><span></span><br><span>Spur: Rewrite the revised followForwardedObjectFields:toDepth: soi it can be correctly inlined.</span><br><span></span><br><span>Slang: Change the order of application of ensureConditionalAssignmentsAreTransformedIn: so it is always the last thing done in tryToInlineMethodsIn:.</span><br><span></span><br><span>Straight-forward optimization of bindVariablesIn: in the common case of methods being inlined swith unchanged parameters.</span><br><span></span><br><span>=============== Diff against VMMaker.oscog-eem.2764 ===============</span><br><span></span><br><span>Item was changed:</span><br><span> ----- Method: Spur32BitCoMemoryManager>>followForwardedObjectFields:toDepth: (in category 'as yet unclassified') -----</span><br><span> followForwardedObjectFields: objOop toDepth: depth</span><br><span> "Follow pointers in the object to depth.</span><br><span> Answer if any forwarders were found.</span><br><span> How to avoid cyclic structures?? A temporary mark bit? eem 6/22/2020 no need since depth is always finite."</span><br><span> <api></span><br><span> <inline: false></span><br><span>+ | found fmt limit |</span><br><span>- | oop found fmt |</span><br><span> found := false.</span><br><span> self assert: ((self isPointers: objOop) or: [self isOopCompiledMethod: objOop]).</span><br><span> fmt := self formatOf: objOop.</span><br><span>+ limit := (self numPointerSlotsOf: objOop format: fmt) - 1.</span><br><span> "It is essential to skip the first field of a method because it may be a</span><br><span> reference to a Cog method in the method zone, not a real object at all."</span><br><span> ((self isCompiledMethodFormat: fmt)</span><br><span> ifTrue: [1]</span><br><span> ifFalse: [0])</span><br><span>+ to: limit</span><br><span>+ do: [:i| | oop |</span><br><span>- to: (self numPointerSlotsOf: objOop format: fmt) - 1</span><br><span>- do: [:i|</span><br><span> oop := self fetchPointer: i ofObject: objOop.</span><br><span> (self isNonImmediate: oop) ifTrue:</span><br><span> [(self isForwarded: oop) ifTrue:</span><br><span> [found := true.</span><br><span> oop := self followForwarded: oop.</span><br><span> self storePointer: i ofObject: objOop withValue: oop].</span><br><span> (depth > 0</span><br><span> and: [(self hasPointerFields: oop)</span><br><span> and: [self followForwardedObjectFields: oop toDepth: depth - 1]]) ifTrue:</span><br><span> [found := true]]].</span><br><span> ^found!</span><br><span></span><br><span>Item was changed:</span><br><span> ----- Method: Spur64BitCoMemoryManager>>followForwardedObjectFields:toDepth: (in category 'forwarding') -----</span><br><span> followForwardedObjectFields: objOop toDepth: depth</span><br><span> "Follow pointers in the object to depth.</span><br><span> Answer if any forwarders were found.</span><br><span> How to avoid cyclic structures?? A temporary mark bit? eem 6/22/2020 no need since depth is always finite."</span><br><span> <api></span><br><span> <inline: false></span><br><span>+ | found fmt limit |</span><br><span>- | oop found fmt |</span><br><span> found := false.</span><br><span> self assert: ((self isPointers: objOop) or: [self isOopCompiledMethod: objOop]).</span><br><span> fmt := self formatOf: objOop.</span><br><span>+ limit := (self numPointerSlotsOf: objOop format: fmt) - 1.</span><br><span> "It is essential to skip the first field of a method because it may be a</span><br><span> reference to a Cog method in the method zone, not a real object at all."</span><br><span> ((self isCompiledMethodFormat: fmt)</span><br><span> ifTrue: [1]</span><br><span> ifFalse: [0])</span><br><span>+ to: limit</span><br><span>+ do: [:i| | oop |</span><br><span>- to: (self numPointerSlotsOf: objOop format: fmt) - 1</span><br><span>- do: [:i|</span><br><span> oop := self fetchPointer: i ofObject: objOop.</span><br><span> (self isNonImmediate: oop) ifTrue:</span><br><span> [(self isForwarded: oop) ifTrue:</span><br><span> [found := true.</span><br><span> oop := self followForwarded: oop.</span><br><span> self storePointer: i ofObject: objOop withValue: oop].</span><br><span> (depth > 0</span><br><span> and: [(self hasPointerFields: oop)</span><br><span> and: [self followForwardedObjectFields: oop toDepth: depth - 1]]) ifTrue:</span><br><span> [found := true]]].</span><br><span> ^found!</span><br><span></span><br><span>Item was changed:</span><br><span> ----- Method: TMethod>>exitVar:label:in: (in category 'inlining') -----</span><br><span> exitVar: exitVar label: exitLabel in: aCodeGen</span><br><span> "Replace each return statement in this method with an assignment to the</span><br><span> exit variable followed by either a return or a goto to the given label.</span><br><span> Answer if a goto was generated."</span><br><span> "Optimization: If exitVar is nil, the return value of the inlined method is not being used, so don't add the assignment statement."</span><br><span></span><br><span> | labelUsed map elisions eliminateReturnSelfs |</span><br><span> labelUsed := false.</span><br><span> map := Dictionary new.</span><br><span> elisions := Set new.</span><br><span> "Conceivably one might ^self from a struct class and mean it. In most cases though</span><br><span> ^self means `get me outta here, fast'. So unless this method is from a VMStruct class,</span><br><span> elide any ^self's"</span><br><span> eliminateReturnSelfs := ((definingClass inheritsFrom: VMClass) and: [definingClass isStructClass]) not</span><br><span> and: [returnType = #void or: [returnType = #sqInt]].</span><br><span> parseTree nodesDo:</span><br><span> [:node | | replacement |</span><br><span> node isReturn ifTrue:</span><br><span> [self transformReturnSubExpression: node</span><br><span> toAssignmentOf: exitVar</span><br><span> andGoto: exitLabel</span><br><span> unless: eliminateReturnSelfs</span><br><span> into: [:rep :labelWasUsed|</span><br><span> replacement := rep.</span><br><span> labelWasUsed ifTrue: [labelUsed := true]]</span><br><span> in: aCodeGen.</span><br><span> "replaceNodesIn: is strictly top-down, so any replacement for ^expr ifTrue: [...^fu...] ifFalse: [...^bar...]</span><br><span> will prevent replacement of either ^fu or ^bar. The corollary is that ^expr ifTrue: [foo] ifFalse: [^bar]</span><br><span> must be transformed into expr ifTrue: [^foo] ifFalse: [^bar]"</span><br><span> (node expression isConditionalSend</span><br><span> and: [node expression hasExplicitReturn])</span><br><span> ifTrue:</span><br><span> [elisions add: node.</span><br><span> (node expression args reject: [:arg| arg endsWithReturn]) do:</span><br><span> [:nodeNeedingReturn|</span><br><span> self transformReturnSubExpression: nodeNeedingReturn statements last</span><br><span> toAssignmentOf: exitVar</span><br><span> andGoto: exitLabel</span><br><span> unless: eliminateReturnSelfs</span><br><span> into: [:rep :labelWasUsed|</span><br><span> replacement := rep.</span><br><span>+ labelWasUsed ifTrue: [labelUsed := true]]</span><br><span>+ in: aCodeGen.</span><br><span>- labelWasUsed ifTrue: [labelUsed := true]].</span><br><span> map</span><br><span> at: nodeNeedingReturn statements last</span><br><span> put: replacement]]</span><br><span> ifFalse:</span><br><span> [map</span><br><span> at: node</span><br><span> put: (replacement ifNil:</span><br><span> [TLabeledCommentNode new setComment: 'return ', node expression printString])]]].</span><br><span> map isEmpty ifTrue:</span><br><span> [self deny: labelUsed.</span><br><span> ^false].</span><br><span> "Now do a top-down replacement for all returns that should be mapped to assignments and gotos"</span><br><span> parseTree replaceNodesIn: map.</span><br><span> "Now it is safe to eliminate the returning ifs..."</span><br><span> elisions isEmpty ifFalse:</span><br><span> [| elisionMap |</span><br><span> elisionMap := Dictionary new.</span><br><span> elisions do: [:returnNode| elisionMap at: returnNode put: returnNode expression].</span><br><span> parseTree replaceNodesIn: elisionMap].</span><br><span> "Now flatten any new statement lists..."</span><br><span> parseTree nodesDo:</span><br><span> [:node| | list |</span><br><span> (node isStmtList</span><br><span> and: [node statements notEmpty</span><br><span> and: [node statements last isStmtList]]) ifTrue:</span><br><span> [list := node statements last statements.</span><br><span> node statements removeLast; addAllLast: list]].</span><br><span> ^labelUsed!</span><br><span></span><br><span>Item was changed:</span><br><span> ----- Method: TMethod>>inlineFunctionCall:in: (in category 'inlining') -----</span><br><span> inlineFunctionCall: aSendNode in: aCodeGen</span><br><span> "Answer the body of the called function, substituting the actual</span><br><span> parameters for the formal argument variables in the method body.</span><br><span> Assume caller has established that:</span><br><span> 1. the method arguments are all substitutable nodes, and</span><br><span> 2. the method to be inlined contains no additional embedded returns."</span><br><span></span><br><span> | sel meth doNotRename argsForInlining substitutionDict |</span><br><span>+ aCodeGen maybeBreakForInlineOf: aSendNode in: self.</span><br><span> sel := aSendNode selector.</span><br><span> meth := (aCodeGen methodNamed: sel) copy.</span><br><span> meth ifNil:</span><br><span> [^self inlineBuiltin: aSendNode in: aCodeGen].</span><br><span> doNotRename := Set withAll: args.</span><br><span> argsForInlining := aSendNode argumentsForInliningCodeGenerator: aCodeGen.</span><br><span> meth args with: argsForInlining do:</span><br><span> [ :argName :exprNode |</span><br><span> exprNode isLeaf ifTrue:</span><br><span> [doNotRename add: argName]].</span><br><span> (meth statements size = 2</span><br><span> and: [meth statements first isSend</span><br><span> and: [meth statements first selector == #flag:]]) ifTrue:</span><br><span> [meth statements removeFirst].</span><br><span> meth renameVarsForInliningInto: self except: doNotRename in: aCodeGen.</span><br><span> meth renameLabelsForInliningInto: self.</span><br><span> self addVarsDeclarationsAndLabelsOf: meth except: doNotRename.</span><br><span> substitutionDict := Dictionary new: meth args size * 2.</span><br><span> meth args with: argsForInlining do:</span><br><span> [ :argName :exprNode |</span><br><span>+ (exprNode isVariable and: [exprNode name = argName]) ifFalse:</span><br><span>+ [substitutionDict at: argName put: exprNode].</span><br><span>- substitutionDict at: argName put: exprNode.</span><br><span> (doNotRename includes: argName) ifFalse:</span><br><span> [locals remove: argName]].</span><br><span> meth parseTree bindVariablesIn: substitutionDict.</span><br><span> ^meth parseTree endsWithReturn</span><br><span> ifTrue: [meth parseTree copyWithoutReturn]</span><br><span> ifFalse: [meth parseTree]!</span><br><span></span><br><span>Item was changed:</span><br><span> ----- Method: TMethod>>tryToInlineMethodsIn: (in category 'inlining') -----</span><br><span> tryToInlineMethodsIn: aCodeGen</span><br><span> "Expand any (complete) inline methods sent by this method.</span><br><span> Set the complete flag when all inlining has been done.</span><br><span> Answer if something was inlined."</span><br><span></span><br><span> | didSomething statementLists |</span><br><span> "complete ifTrue:</span><br><span> [^false]."</span><br><span></span><br><span> self definedAsMacro ifTrue:</span><br><span> [complete ifTrue:</span><br><span> [^false].</span><br><span> ^complete := true].</span><br><span></span><br><span>- self ensureConditionalAssignmentsAreTransformedIn: aCodeGen.</span><br><span> didSomething := self tryToInlineMethodStatementsIn: aCodeGen statementListsInto: [:stmtLists| statementLists := stmtLists].</span><br><span> didSomething := (self tryToInlineMethodExpressionsIn: aCodeGen) or: [didSomething].</span><br><span>+ self ensureConditionalAssignmentsAreTransformedIn: aCodeGen.</span><br><span></span><br><span> didSomething ifTrue:</span><br><span> [writtenToGlobalVarsCache := nil].</span><br><span></span><br><span> complete ifFalse:</span><br><span> [self checkForCompletenessIn: aCodeGen.</span><br><span> complete ifTrue: [didSomething := true]]. "marking a method complete is progress"</span><br><span> ^didSomething!</span><br><span></span><br><span>Item was changed:</span><br><span> ----- Method: TStmtListNode>>bindVariablesIn: (in category 'transformations') -----</span><br><span> bindVariablesIn: aDictionary</span><br><span></span><br><span>+ aDictionary notEmpty ifTrue:</span><br><span>+ [statements := statements collect: [:s| s bindVariablesIn: aDictionary]]!</span><br><span>- statements := statements collect: [ :s | s bindVariablesIn: aDictionary ].!</span><br><span></span><br></div></blockquote></body></html>