compiler/PPCCodeGenerator.st
changeset 491 82b272c7dc37
parent 489 0ca7a70db0f5
child 492 fc3dbe5654c5
--- a/compiler/PPCCodeGenerator.st	Tue Jun 16 06:54:14 2015 +0100
+++ b/compiler/PPCCodeGenerator.st	Tue Jun 16 07:49:21 2015 +0100
@@ -209,18 +209,77 @@
 !PPCCodeGenerator methodsFor:'visiting'!
 
 visitActionNode: node
-    | blockNode blockBody blockNodesVar |
+    | blockNode blockBody blockNodesVar blockNeedsCollection blockMatches childValueVars |
 
     blockNode := node block ast copy.
     self assert: blockNode arguments size == 1.
     blockNodesVar := blockNode arguments first .
     blockBody := blockNode body.
-    "Replace all references to blockNodeVar to retvalVar..."
-    blockBody variableNodesDo:[:variableNode| 
-        variableNode name = blockNodesVar name ifTrue:[ 
-            variableNode token value: self retvalVar.
+
+    "Now, analyze block body, search for all references to
+     block arg <barg> and check if in all cases it's used 
+     in one of the following patterns:
+
+        * <barg> first , <barg> second, ... , <barg> sixth
+        * <barg> at: <integer constant>
+
+     If so, then the block code can be inlined and the intermediate
+     result collection need not to be created. Keep this information
+     in temporary `blockNeedsCollection`. 
+     During the analysis, remember all nodes that matches the pattern
+     in a dictionary `blockMatches` mapping the node to actual temporary
+     variable where the node is used. This will be later used for block's node
+     rewriting"
+    blockNeedsCollection := true.
+    node child isSequenceNode ifTrue:[
+        blockNeedsCollection := false.
+        blockMatches := IdentityDictionary new."Must use IDENTITY dict as nodes have overwritten their #=!!!!!!"
+        childValueVars := node child preferredChildrenVariableNames.
+        blockBody variableNodesDo:[:variableNode| 
+            variableNode name = blockNodesVar name ifTrue:[ 
+                "Check if variable node matches..."
+                variableNode parent isMessage ifTrue:[ 
+                    | parent |
+
+                    parent := variableNode parent.
+                    "Check for <barg> at: <number>"
+                    ((parent selector == #at:) and:[ parent arguments first isLiteralNumber ]) ifTrue:[ 
+                        blockMatches at: parent put: (childValueVars at: parent arguments first value).
+                    ] ifFalse:[ 
+                        "Check for <barg> first / second / ..."
+                        | i |
+
+                        i := #(first second third fourth fifth sixth) indexOf: parent selector.
+                        i ~~ 0 ifTrue:[ 
+                            blockMatches at: parent put: (childValueVars at: i).
+                        ] ifFalse:[ 
+                            blockNeedsCollection := true.
+                        ].
+                    ].
+                ] ifFalse:[ 
+                    blockNeedsCollection := true.
+                ].
+            ].
         ].
     ].
+
+    blockNeedsCollection ifTrue:[
+        "Bad, we have to use the collection.
+         Replace all references to blockNodeVar to retvalVar..."
+        blockBody variableNodesDo:[:variableNode| 
+            variableNode name = blockNodesVar name ifTrue:[ 
+                variableNode token value: self retvalVar.
+            ].
+        ].
+    ] ifFalse:[ 
+        "Good, can avoid intermediate collection.
+         Replace references to collection with corresponding temporary variable"
+        blockMatches keysAndValuesDo:[:node :childValueVar |
+            node parent replaceNode: node withNode: (RBVariableNode named: childValueVar).
+        ].
+        node child returnParsedObjectsAsCollection: false. 
+    ].
+
     "Block return value is return value of last statement.
      So if the method is not inline, make last statement a return.
         if the method is inline, make it assignment to retvalVar."
@@ -238,16 +297,14 @@
         ].
     ].
 
-    compiler 
-          codeAssignParsedValueOf:[ self visit:node child ]
-          to:self retvalVar.
-    compiler codeIf: 'error' then: [ 
+    compiler codeAssignParsedValueOf:[ self visit:node child ] to:self retvalVar.
+    compiler codeIfErrorThen: [ 
         compiler codeReturn: 'failure'. 
     ] else: [
         compiler code: blockBody.    
     ]
 
-    "Modified: / 15-06-2015 / 17:08:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 16-06-2015 / 07:41:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 visitAndNode: node