207 ! ! |
207 ! ! |
208 |
208 |
209 !PPCCodeGenerator methodsFor:'visiting'! |
209 !PPCCodeGenerator methodsFor:'visiting'! |
210 |
210 |
211 visitActionNode: node |
211 visitActionNode: node |
212 | blockNode blockBody blockNodesVar | |
212 | blockNode blockBody blockNodesVar blockNeedsCollection blockMatches childValueVars | |
213 |
213 |
214 blockNode := node block ast copy. |
214 blockNode := node block ast copy. |
215 self assert: blockNode arguments size == 1. |
215 self assert: blockNode arguments size == 1. |
216 blockNodesVar := blockNode arguments first . |
216 blockNodesVar := blockNode arguments first . |
217 blockBody := blockNode body. |
217 blockBody := blockNode body. |
218 "Replace all references to blockNodeVar to retvalVar..." |
218 |
219 blockBody variableNodesDo:[:variableNode| |
219 "Now, analyze block body, search for all references to |
220 variableNode name = blockNodesVar name ifTrue:[ |
220 block arg <barg> and check if in all cases it's used |
221 variableNode token value: self retvalVar. |
221 in one of the following patterns: |
|
222 |
|
223 * <barg> first , <barg> second, ... , <barg> sixth |
|
224 * <barg> at: <integer constant> |
|
225 |
|
226 If so, then the block code can be inlined and the intermediate |
|
227 result collection need not to be created. Keep this information |
|
228 in temporary `blockNeedsCollection`. |
|
229 During the analysis, remember all nodes that matches the pattern |
|
230 in a dictionary `blockMatches` mapping the node to actual temporary |
|
231 variable where the node is used. This will be later used for block's node |
|
232 rewriting" |
|
233 blockNeedsCollection := true. |
|
234 node child isSequenceNode ifTrue:[ |
|
235 blockNeedsCollection := false. |
|
236 blockMatches := IdentityDictionary new."Must use IDENTITY dict as nodes have overwritten their #=!!!!!!" |
|
237 childValueVars := node child preferredChildrenVariableNames. |
|
238 blockBody variableNodesDo:[:variableNode| |
|
239 variableNode name = blockNodesVar name ifTrue:[ |
|
240 "Check if variable node matches..." |
|
241 variableNode parent isMessage ifTrue:[ |
|
242 | parent | |
|
243 |
|
244 parent := variableNode parent. |
|
245 "Check for <barg> at: <number>" |
|
246 ((parent selector == #at:) and:[ parent arguments first isLiteralNumber ]) ifTrue:[ |
|
247 blockMatches at: parent put: (childValueVars at: parent arguments first value). |
|
248 ] ifFalse:[ |
|
249 "Check for <barg> first / second / ..." |
|
250 | i | |
|
251 |
|
252 i := #(first second third fourth fifth sixth) indexOf: parent selector. |
|
253 i ~~ 0 ifTrue:[ |
|
254 blockMatches at: parent put: (childValueVars at: i). |
|
255 ] ifFalse:[ |
|
256 blockNeedsCollection := true. |
|
257 ]. |
|
258 ]. |
|
259 ] ifFalse:[ |
|
260 blockNeedsCollection := true. |
|
261 ]. |
|
262 ]. |
222 ]. |
263 ]. |
223 ]. |
264 ]. |
|
265 |
|
266 blockNeedsCollection ifTrue:[ |
|
267 "Bad, we have to use the collection. |
|
268 Replace all references to blockNodeVar to retvalVar..." |
|
269 blockBody variableNodesDo:[:variableNode| |
|
270 variableNode name = blockNodesVar name ifTrue:[ |
|
271 variableNode token value: self retvalVar. |
|
272 ]. |
|
273 ]. |
|
274 ] ifFalse:[ |
|
275 "Good, can avoid intermediate collection. |
|
276 Replace references to collection with corresponding temporary variable" |
|
277 blockMatches keysAndValuesDo:[:node :childValueVar | |
|
278 node parent replaceNode: node withNode: (RBVariableNode named: childValueVar). |
|
279 ]. |
|
280 node child returnParsedObjectsAsCollection: false. |
|
281 ]. |
|
282 |
224 "Block return value is return value of last statement. |
283 "Block return value is return value of last statement. |
225 So if the method is not inline, make last statement a return. |
284 So if the method is not inline, make last statement a return. |
226 if the method is inline, make it assignment to retvalVar." |
285 if the method is inline, make it assignment to retvalVar." |
227 blockBody statements notEmpty ifTrue:["Care for empty blocks - [:t | ] !!" |
286 blockBody statements notEmpty ifTrue:["Care for empty blocks - [:t | ] !!" |
228 compiler currentMethod isInline ifTrue:[ |
287 compiler currentMethod isInline ifTrue:[ |