MessageNode.st
changeset 565 00673e9d6edc
parent 564 ffac5191213f
child 567 a6e4c44ff326
--- a/MessageNode.st	Thu Jun 26 13:22:48 1997 +0200
+++ b/MessageNode.st	Fri Jun 27 14:08:18 1997 +0200
@@ -762,7 +762,7 @@
 
 codeOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
     |recType nargs isBuiltIn litIndex cls clsLitIndex code isSpecial
-     specialCode stackTop arg1 arg2|
+     specialCode stackTop arg1 arg2 arg3 okToInline|
 
     argArray isNil ifTrue:[
         nargs := 0
@@ -871,24 +871,40 @@
         ].
 
         selector == #to:do: ifTrue:[
-            (receiver isConstant
-            and:[receiver type == #Integer]) ifTrue:[
-                (arg1 isConstant
-                and:[arg1 type == #Integer]) ifTrue:[
-                    receiver value <= arg1 value ifTrue:[
-                        arg2 isBlock ifTrue:[
-                            arg2 numArgs == 1 ifTrue:[
-                                ^ self codeToDoOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
-                            ]
-                        ].    
-                    ]
-                ]
+            okToInline := true.
+
+            (arg2 isBlock and:[arg2 numArgs == 1]) ifFalse:[
+                okToInline := false.
+            ].
+            okToInline ifTrue:[
+                ^ self codeToDoOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
             ]
         ].
 
         isBuiltIn := aCompiler isBuiltIn2ArgSelector:selector forReceiver:receiver.
     ].
 
+    (nargs == 3) ifTrue:[
+        arg1 := argArray at:1.
+        arg2 := argArray at:2.
+        arg3 := argArray at:3.
+
+        selector == #to:by:do: ifTrue:[
+            okToInline := true.
+
+            (arg2 isConstant and:[arg2 type == #Integer]) ifFalse:[
+                "/ step must be a constant (need to know how to compare)
+                okToInline := false.
+            ].
+            (arg3 isBlock and:[arg3 numArgs == 1]) ifFalse:[
+                okToInline := false.
+            ].
+            okToInline ifTrue:[
+                ^ self codeToByDoOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
+            ]
+        ].
+    ].
+
     isBuiltIn ifFalse:[
         specialCode := aCompiler specialSendCodeFor:selector.
         isSpecial := specialCode notNil.
@@ -1048,7 +1064,7 @@
     ].
 
     "Modified: 3.9.1995 / 12:55:42 / claus"
-    "Modified: 26.6.1997 / 13:22:08 / cg"
+    "Modified: 27.6.1997 / 13:41:41 / cg"
 !
 
 codeOrIfElseOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
@@ -1407,20 +1423,27 @@
     "Modified: 27.5.1997 / 14:28:49 / cg"
 !
 
-codeToDoOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
-    "generate code for n to:n do:[:unusedArg | ... ]"
+codeToByDoOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
+    "generate code for a to:b by:c do:[:arg | ... ]"
 
-    |pos pos2 start stop lateEval theBlock loopVarIndex|
+    |pos pos2 start stop step lateEval theBlock loopVarIndex
+     stepVal stopVarIndex|
 
-    "/ NOTICE: could compile it as a timesRepeat, if
+    "/ NOTICE: could compile it as a timesRepeat-like loop, if
     "/ the loop-counter is not accessed within the loop-block.
     "/ This generates somewhat (15%) faster code, but makes
     "/ debugging somewhat difficult (no loop-value seen in debugger).
 
     start := receiver.
     stop := (argArray at:1).
-    stop isConstant ifFalse:[self halt:'should not happen'].
-    (stop evaluate isMemberOf:SmallInteger) ifFalse:[self halt:'should not happen'].
+    step := (argArray at:2).
+
+"/    stop isConstant ifFalse:[self halt:'should not happen'].
+"/    (stop evaluate isMemberOf:SmallInteger) ifFalse:[self halt:'should not happen'].
+
+    step isConstant ifFalse:[self halt:'should not happen'].
+    stepVal := step evaluate.
+    (stepVal isMemberOf:SmallInteger) ifFalse:[self halt:'should not happen'].
 
     start codeOn:aStream inBlock:b for:aCompiler.
 
@@ -1438,10 +1461,172 @@
         ].
     ].
 
+    "/ if stop is not constant, and not an argVar,
+    "/  evaluate it into a temp slot ...
+
+    (stop isConstant and:[stop type == #Integer]) ifFalse:[
+        "/ a method/blockArg is constant as well ...
+        (stop isVariable and:[stop isArgument]) ifFalse:[
+            stop codeOn:aStream inBlock:b for:aCompiler.
+
+            b isNil ifTrue:[
+                stopVarIndex := aCompiler addTempVar.
+                aStream nextPut:#storeMethodVar; nextPut:stopVarIndex.
+            ] ifFalse:[
+                stopVarIndex := b addTempVar.
+                aStream nextPut:#storeBlockVar; nextPut:stopVarIndex.
+            ].
+        ]
+    ].
+
     pos := aStream position.
 
     aStream nextPut:#dup.
-    stop codeOn:aStream inBlock:b for:aCompiler.
+    stopVarIndex notNil ifTrue:[
+        b isNil ifTrue:[
+            aStream nextPut:#pushMethodVar; nextPut:stopVarIndex.
+        ] ifFalse:[
+            aStream nextPut:#pushBlockVar; nextPut:stopVarIndex.
+        ]
+    ] ifFalse:[
+        stop codeOn:aStream inBlock:b for:aCompiler.
+    ].
+    stepVal > 0 ifTrue:[
+        aStream nextPut:#>.
+    ] ifFalse:[
+        aStream nextPut:#<.
+    ].
+    (aCompiler hasLineNumber:selector) ifTrue:[
+        aStream nextPut:lineNr.
+    ].
+    aStream nextPut:#trueJump.
+    pos2 := aStream position.
+    aStream nextPut:0.
+
+    theBlock := argArray at:3.
+
+    "/ need a temporary in the outer context for
+    "/ the loop ...
+    b isNil ifTrue:[
+        loopVarIndex := aCompiler addTempVar.
+        aStream nextPut:#dup.
+        aStream nextPut:#storeMethodVar; nextPut:loopVarIndex.
+    ] ifFalse:[
+        loopVarIndex := b addTempVar.
+        aStream nextPut:#dup.
+        aStream nextPut:#storeBlockVar; nextPut:loopVarIndex.
+    ].
+    theBlock indexOfFirstTemp:loopVarIndex.
+
+    theBlock codeInlineOn:aStream inBlock:b valueNeeded:false for:aCompiler.
+
+    "/ increment/decrement counter & jump back.
+
+    stepVal == 1 ifTrue:[
+        aStream nextPut:#plus1; nextPut:lineNr.
+    ] ifFalse:[
+        stepVal == -1 ifTrue:[
+            aStream nextPut:#minus1; nextPut:lineNr.
+        ] ifFalse:[
+            step codeOn:aStream inBlock:b for:aCompiler.
+            aStream nextPut:#+.
+            (aCompiler hasLineNumber:#+) ifTrue:[
+                aStream nextPut:lineNr.
+            ].
+        ]
+    ].
+
+    aStream nextPut:#jump; nextPut:pos.
+
+    (aStream contents) at:pos2 put:(aStream position).
+    aStream nextPut:#drop.  "/ drop run variable
+    lateEval ifTrue:[
+        start codeOn:aStream inBlock:b for:aCompiler.
+    ].
+
+    "/ no need to nil-out loop-tempVar to help GC
+    "/ (its integer, anyway).
+
+    b isNil ifTrue:[
+        aCompiler removeTempVar
+    ] ifFalse:[
+        b removeTempVar
+    ].
+
+    stopVarIndex notNil ifTrue:[
+        b isNil ifTrue:[
+            aCompiler removeTempVar
+        ] ifFalse:[
+            b removeTempVar
+        ]
+    ].
+
+    "Created: 27.6.1997 / 12:48:18 / cg"
+    "Modified: 27.6.1997 / 13:43:06 / cg"
+!
+
+codeToDoOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
+    "generate code for n to:n do:[:unusedArg | ... ]"
+
+    |pos pos2 start stop lateEval theBlock loopVarIndex
+     stopVarIndex|
+
+    "/ NOTICE: could compile it as a timesRepeat, if
+    "/ the loop-counter is not accessed within the loop-block.
+    "/ This generates somewhat (15%) faster code, but makes
+    "/ debugging somewhat difficult (no loop-value seen in debugger).
+
+    start := receiver.
+    stop := (argArray at:1).
+"/    stop isConstant ifFalse:[self halt:'should not happen'].
+"/    (stop evaluate isMemberOf:SmallInteger) ifFalse:[self halt:'should not happen'].
+
+    start codeOn:aStream inBlock:b for:aCompiler.
+
+    lateEval := false.
+
+    valueNeeded ifTrue:[
+        "/ easily reconstructable - no need to keep on stack
+        start isConstant ifTrue:[
+            (start evaluate isMemberOf:SmallInteger) ifTrue:[
+                lateEval := true.
+            ]
+        ].
+        lateEval ifFalse:[
+            aStream nextPut:#dup
+        ].
+    ].
+
+    "/ if stop is not constant, and not an argVar,
+    "/  evaluate it into a temp slot ...
+
+    (stop isConstant and:[stop type == #Integer]) ifFalse:[
+        "/ a method/blockArg is constant as well ...
+        (stop isVariable and:[stop isArgument]) ifFalse:[
+            stop codeOn:aStream inBlock:b for:aCompiler.
+
+            b isNil ifTrue:[
+                stopVarIndex := aCompiler addTempVar.
+                aStream nextPut:#storeMethodVar; nextPut:stopVarIndex.
+            ] ifFalse:[
+                stopVarIndex := b addTempVar.
+                aStream nextPut:#storeBlockVar; nextPut:stopVarIndex.
+            ].
+        ]
+    ].
+
+    pos := aStream position.
+
+    aStream nextPut:#dup.
+    stopVarIndex notNil ifTrue:[
+        b isNil ifTrue:[
+            aStream nextPut:#pushMethodVar; nextPut:stopVarIndex.
+        ] ifFalse:[
+            aStream nextPut:#pushBlockVar; nextPut:stopVarIndex.
+        ]
+    ] ifFalse:[
+        stop codeOn:aStream inBlock:b for:aCompiler.
+    ].
     aStream nextPut:#>.
     (aCompiler hasLineNumber:selector) ifTrue:[
         aStream nextPut:lineNr.
@@ -1484,10 +1669,18 @@
         aCompiler removeTempVar
     ] ifFalse:[
         b removeTempVar
-    ]
+    ].
+
+    stopVarIndex notNil ifTrue:[
+        b isNil ifTrue:[
+            aCompiler removeTempVar
+        ] ifFalse:[
+            b removeTempVar
+        ]
+    ].
 
     "Created: 26.6.1997 / 10:58:47 / cg"
-    "Modified: 26.6.1997 / 11:04:05 / cg"
+    "Modified: 27.6.1997 / 13:21:54 / cg"
 !
 
 codeWhileOn:aStream inBlock:b valueNeeded:valueNeeded for:aCompiler
@@ -1929,5 +2122,5 @@
 !MessageNode class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libcomp/MessageNode.st,v 1.73 1997-06-26 11:22:48 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libcomp/MessageNode.st,v 1.74 1997-06-27 12:08:18 cg Exp $'
 ! !