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