please don't send me more letters !!!

On 2020-06-24, at 04:41, commits@source.squeak.org wrote:


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 ].!