<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>