icode: new IEscapeMark class to bind ISeq and IEscape
authorJean Privat <jean@pryen.org>
Wed, 26 Aug 2009 14:12:16 +0000 (10:12 -0400)
committerJean Privat <jean@pryen.org>
Wed, 26 Aug 2009 16:22:26 +0000 (12:22 -0400)
An IRoutine knows all its local escape marks.
This fix some bugs with nesting and escapes since only marks of the
current iroutine needs to be duplicated (like what is done for registers).

Signed-off-by: Jean Privat <jean@pryen.org>

32 files changed:
src/analysis/icode_dump.nit
src/compiling/compiling_icode.nit
src/icode/icode_base.nit
src/icode/icode_builder.nit
src/icode/icode_tools.nit
tests/base_inline_closure_escape.nit [new file with mode: 0644]
tests/base_inline_closure_escape2.nit [new file with mode: 0644]
tests/base_inline_closure_escape3.nit [new file with mode: 0644]
tests/base_inline_closure_fork.nit [new file with mode: 0644]
tests/sav/base_inline_closure_escape.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape2.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape2_alt1.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape2_alt2.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape2_alt3.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape2_alt4.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape2_alt5.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape3.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape3_alt1.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape3_alt2.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape3_alt3.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape3_alt4.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape3_alt5.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape_alt1.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape_alt2.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape_alt3.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape_alt4.sav [new file with mode: 0644]
tests/sav/base_inline_closure_escape_alt5.sav [new file with mode: 0644]
tests/sav/base_inline_closure_fork.sav [new file with mode: 0644]
tests/sav/base_inline_closure_fork_alt1.sav [new file with mode: 0644]
tests/sav/base_inline_closure_fork_alt2.sav [new file with mode: 0644]
tests/sav/base_inline_closure_fork_alt3.sav [new file with mode: 0644]
tests/sav/base_inline_closure_fork_alt4.sav [new file with mode: 0644]

index 18a2881..26f5c0c 100644 (file)
@@ -127,7 +127,7 @@ class ICodeDumper
        var _last_label: Int = 0
        # Return the name of e
        # If e is unknown, a new name is gived
-       fun lab(e: ISeq): String
+       fun lab(e: IEscapeMark): String
        do
                if _ids.has_key(e) then
                        return _ids[e]
@@ -154,7 +154,7 @@ class ICodeDumper
        end
 
        # Is the label e known? (because we goto to it)
-       fun has_lab(e: ISeq): Bool
+       fun has_lab(e: IEscapeMark): Bool
        do
                return _ids.has_key(e)
        end
@@ -224,7 +224,8 @@ redef class ISeq
                for ic in icodes do
                        ic.dump(icd)
                end
-               if icd.has_lab(self) then icd.write("{icd.lab(self)}:")
+               var mark = iescape_mark
+               if mark != null and icd.has_lab(mark) then icd.write("{icd.lab(mark)}:")
        end
 end
 
@@ -253,14 +254,15 @@ redef class ILoop
                end
                icd.unindent
                icd.write "}"
-               if icd.has_lab(self) then icd.write("{icd.lab(self)}:")
+               var mark = iescape_mark
+               if mark != null and icd.has_lab(mark) then icd.write("{icd.lab(mark)}:")
        end
 end
 
 redef class IEscape
        redef fun dump_intern(icd)
        do
-               return "ESCAPE {icd.lab(seq)}"
+               return "ESCAPE {icd.lab(iescape_mark)}"
        end
 end
 
index 011dca5..8ca8a7a 100644 (file)
@@ -139,6 +139,9 @@ class I2CCompilerVisitor
                end
        end
 
+       # Association between IEscapeMarks and visited ISeq
+       readable var _marks_to_seq: Map[IEscapeMark, ISeq] = new HashMap[IEscapeMark, ISeq]
+
        # Are we in a closure ?
        readable writable var _closure: Bool = false
 
@@ -382,6 +385,8 @@ redef class ISeq
        redef fun inner_compile_to_c(v)
        do
                v.local_labels.add(self)
+               var mark = iescape_mark
+               if mark != null then v.marks_to_seq[mark] = self
                for ic in icodes do
                        ic.compile_to_c(v)
                end
@@ -414,6 +419,8 @@ redef class ILoop
        redef fun inner_compile_to_c(v)
        do
                v.local_labels.add(self)
+               var mark = iescape_mark
+               if mark != null then v.marks_to_seq[mark] = self
                v.add_instr("while(1) \{")
                v.indent
                for ic in icodes do
@@ -429,7 +436,7 @@ end
 redef class IEscape
        redef fun inner_compile_to_c(v)
        do
-               v.add_goto(seq)
+               v.add_goto(v.marks_to_seq[iescape_mark])
                return null
        end
 end
index 922284b..b3da5a9 100644 (file)
@@ -32,6 +32,10 @@ class IRegister
        end
 end
 
+# A mark used to associate IEscapes to ISeqs
+class IEscapeMark
+end
+
 # A Closure declaration
 class IClosureDecl
        # The associated closure definition
@@ -57,6 +61,9 @@ class IRoutine
        # The result of the routine
        readable var _result: nullable IRegister
 
+       # The local escapes marks of the routine
+       readable var _escape_marks: Set[IEscapeMark] = new ArraySet[IEscapeMark]
+
        # The sequence of icode
        readable var _body: ISeq = new ISeq
 
@@ -159,6 +166,10 @@ class ISeq
 special ICode0
        # The sequence of icode
        readable var _icodes: List[ICode] = new List[ICode]
+
+       # The associated iescape_mark (if any)
+       readable writable var _iescape_mark: nullable IEscapeMark
+
        init do end
 end
 
@@ -184,9 +195,9 @@ end
 class IEscape
 special ICode0
        # The seqeuence to escape
-       # The control flow continues at the next icode after the sequence
-       readable var _seq: ISeq
-       init(seq: ISeq) do _seq = seq
+       # The control flow continues at the next icode after the associated sequence
+       readable var _iescape_mark: IEscapeMark
+       init(mark: IEscapeMark) do _iescape_mark = mark
 end
 
 # An abort statement
index 3731a61..118d325 100644 (file)
@@ -160,9 +160,16 @@ class ICodeBuilder
        end
 
        # Add an escape to a given sequence
+       # Create a new IEscapeMark if required
        fun add_escape(seq: ISeq)
        do
-               stmt(new IEscape(seq))
+               var mark = seq.iescape_mark
+               if mark == null then
+                       mark = new IEscapeMark
+                       iroutine.escape_marks.add(mark)
+                       seq.iescape_mark = mark
+               end
+               stmt(new IEscape(mark))
        end
 
        # Return a literal "null" value
index 100c4b3..33b0010 100644 (file)
@@ -134,6 +134,13 @@ redef class ICodeBuilder
                        #seq.icodes.add(new IMove(dico[routine.params[i]]), args[i]))
                end
 
+               # Fill escape mark association
+               for m in routine.escape_marks do
+                       var m2 = new IEscapeMark
+                       iroutine.escape_marks.add(m2)
+                       d._marks[m] = m2
+               end
+
                # Fill closure association
                if closdecls != null then
                        var cdico = d._closures
@@ -177,14 +184,27 @@ private class ICodeDupContext
                return a
        end
 
-       # The associoation between old_seq and new_seq
-       # Directly used by the IEscape
-       var _seqs: Map[ISeq, ISeq] = new HashMap[ISeq, ISeq]
-
        # The assocation between old_ireg and new_ireg
        # Used by dup_ireg
        var _registers: Map[IRegister, IRegister] = new HashMap[IRegister, IRegister]
 
+       # Return the correct escape mark
+       # * a duplicate of the local escape mark 'm' of the inlined iroutine
+       # * 'r' else (it is a escape mark of the caller iroutine)
+       fun dup_mark(m: IEscapeMark): IEscapeMark
+       do
+               var ms = _marks
+               if ms.has_key(m) then
+                       return ms[m]
+               else
+                       return m
+               end
+       end
+
+       # The associoation between old_seq and new_seq
+       # Used by dup_mark
+       var _marks: Map[IEscapeMark, IEscapeMark] = new HashMap[IEscapeMark, IEscapeMark]
+
        # The association between a closure_decl and its closure_def (if any)
        var _closures: Map[IClosureDecl, nullable IClosureDef] = new ArrayMap[IClosureDecl, nullable IClosureDef]
 
@@ -230,11 +250,15 @@ redef class ISeq
        do
                var old_seq = d._icb.seq
                d._icb.seq = dest
-               d._seqs[self] = dest
                for c in icodes do
                        c.dup_with(d)
                end
                d._icb.seq = old_seq
+               assert dest.iescape_mark == null
+               var mark = iescape_mark
+               if mark != null then
+                       dest.iescape_mark = d.dup_mark(mark)
+               end
        end
 end
 
@@ -260,13 +284,10 @@ end
 redef class IEscape
        redef fun inner_dup_with(d)
        do
-               if d._seqs.has_key(seq) then
-                       # Jump to a duplicated sequence
-                       return new IEscape(d._seqs[seq])
-               else
-                       # Jump to an englobing unduplicated sequence
-                       return new IEscape(seq)
-               end
+               # Get the associated mark (duplicated of not)
+               var mark = d.dup_mark(iescape_mark)
+               # Jump to the mark
+               return new IEscape(mark)
        end
 end
 
diff --git a/tests/base_inline_closure_escape.nit b/tests/base_inline_closure_escape.nit
new file mode 100644 (file)
index 0000000..c912c9f
--- /dev/null
@@ -0,0 +1,50 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2008 Jean Privat <jean@pryen.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class Inline__
+       fun foo1
+               !f
+       do
+               f
+               5.output
+       end
+
+       fun foo2
+               !f
+       do
+               f
+               2.output
+       end
+end
+
+var a = new Inline__
+a.foo1 !f do
+       do
+               a.foo2 !f do
+                       #alt1#break label l1
+                       #alt2#break label l2
+                       #alt3#break label l3
+                       #alt4#continue label l1
+                       #alt5#continue label l2
+                       1.output
+               end label l1
+               3.output
+       end label l3
+       4.output
+end label l2
+6.output
diff --git a/tests/base_inline_closure_escape2.nit b/tests/base_inline_closure_escape2.nit
new file mode 100644 (file)
index 0000000..01bec46
--- /dev/null
@@ -0,0 +1,52 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2008 Jean Privat <jean@pryen.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class Inline__
+       fun foo1: Int
+               !f: Int
+       do
+               f.output
+               return 5
+       end
+
+       fun foo2: Int
+               !f: Int
+       do
+               f.output
+               return  2
+       end
+end
+
+var a = new Inline__
+var x = a.foo1 !f do
+       do
+               var y = a.foo2 !f do
+                       #alt1#break label l1 20
+                       #alt2#break label l2 50
+                       #alt3#break label l3
+                       #alt4#continue label l1 10
+                       #alt5#continue label l2 40
+                       continue 1
+               end label l1
+               y.output
+               3.output
+       end label l3
+       continue 4
+end label l2
+x.output
+6.output
diff --git a/tests/base_inline_closure_escape3.nit b/tests/base_inline_closure_escape3.nit
new file mode 100644 (file)
index 0000000..f1358a6
--- /dev/null
@@ -0,0 +1,49 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2008 Jean Privat <jean@pryen.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class Inline__
+       fun foo
+               !f
+       do
+               do
+                       if true then
+                               f
+                               break label l0
+                       end
+                       0.output
+               end label l0
+               5.output
+       end
+end
+
+var a = new Inline__
+a.foo !f do
+       do
+               a.foo !f do
+                       #alt1#break label l1
+                       #alt2#break label l2
+                       #alt3#break label l3
+                       #alt4#continue label l1
+                       #alt5#continue label l2
+                       1.output
+               end label l1
+               3.output
+       end label l3
+       4.output
+end label l2
+6.output
diff --git a/tests/base_inline_closure_fork.nit b/tests/base_inline_closure_fork.nit
new file mode 100644 (file)
index 0000000..3a2f6df
--- /dev/null
@@ -0,0 +1,56 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2008 Jean Privat <jean@pryen.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class Inline__
+       fun foo1
+               !f
+       do
+               f
+               f
+       end
+       fun foo2
+               !f
+       do
+               f
+               f
+       end
+end
+
+class B
+       var _b: Int
+       redef fun output do _b.output
+end
+
+var a = new Inline__
+a.foo1 !f do
+       var x = new B(1)
+       var y = 2
+       a.foo2 !f do
+               x.output
+               y.output
+               x = new B(3)
+               y = 4
+               #alt1#break label l1
+               #alt2#break label l2
+               #alt3#continue label l1
+               #alt4#continue label l2
+       end label l1
+       x.output
+       y.output
+end label l2
+5.output
diff --git a/tests/sav/base_inline_closure_escape.sav b/tests/sav/base_inline_closure_escape.sav
new file mode 100644 (file)
index 0000000..b414108
--- /dev/null
@@ -0,0 +1,6 @@
+1
+2
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape2.sav b/tests/sav/base_inline_closure_escape2.sav
new file mode 100644 (file)
index 0000000..b414108
--- /dev/null
@@ -0,0 +1,6 @@
+1
+2
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape2_alt1.sav b/tests/sav/base_inline_closure_escape2_alt1.sav
new file mode 100644 (file)
index 0000000..c0301d5
--- /dev/null
@@ -0,0 +1,5 @@
+20
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape2_alt2.sav b/tests/sav/base_inline_closure_escape2_alt2.sav
new file mode 100644 (file)
index 0000000..13caf21
--- /dev/null
@@ -0,0 +1,2 @@
+50
+6
diff --git a/tests/sav/base_inline_closure_escape2_alt3.sav b/tests/sav/base_inline_closure_escape2_alt3.sav
new file mode 100644 (file)
index 0000000..4578bc1
--- /dev/null
@@ -0,0 +1,3 @@
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape2_alt4.sav b/tests/sav/base_inline_closure_escape2_alt4.sav
new file mode 100644 (file)
index 0000000..774a9bf
--- /dev/null
@@ -0,0 +1,6 @@
+10
+2
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape2_alt5.sav b/tests/sav/base_inline_closure_escape2_alt5.sav
new file mode 100644 (file)
index 0000000..8c6aa17
--- /dev/null
@@ -0,0 +1,3 @@
+40
+5
+6
diff --git a/tests/sav/base_inline_closure_escape3.sav b/tests/sav/base_inline_closure_escape3.sav
new file mode 100644 (file)
index 0000000..07d850b
--- /dev/null
@@ -0,0 +1,6 @@
+1
+5
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape3_alt1.sav b/tests/sav/base_inline_closure_escape3_alt1.sav
new file mode 100644 (file)
index 0000000..dc5f2ef
--- /dev/null
@@ -0,0 +1,4 @@
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape3_alt2.sav b/tests/sav/base_inline_closure_escape3_alt2.sav
new file mode 100644 (file)
index 0000000..1e8b314
--- /dev/null
@@ -0,0 +1 @@
+6
diff --git a/tests/sav/base_inline_closure_escape3_alt3.sav b/tests/sav/base_inline_closure_escape3_alt3.sav
new file mode 100644 (file)
index 0000000..4578bc1
--- /dev/null
@@ -0,0 +1,3 @@
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape3_alt4.sav b/tests/sav/base_inline_closure_escape3_alt4.sav
new file mode 100644 (file)
index 0000000..2dd4842
--- /dev/null
@@ -0,0 +1,5 @@
+5
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape3_alt5.sav b/tests/sav/base_inline_closure_escape3_alt5.sav
new file mode 100644 (file)
index 0000000..6613b56
--- /dev/null
@@ -0,0 +1,2 @@
+5
+6
diff --git a/tests/sav/base_inline_closure_escape_alt1.sav b/tests/sav/base_inline_closure_escape_alt1.sav
new file mode 100644 (file)
index 0000000..dc5f2ef
--- /dev/null
@@ -0,0 +1,4 @@
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape_alt2.sav b/tests/sav/base_inline_closure_escape_alt2.sav
new file mode 100644 (file)
index 0000000..1e8b314
--- /dev/null
@@ -0,0 +1 @@
+6
diff --git a/tests/sav/base_inline_closure_escape_alt3.sav b/tests/sav/base_inline_closure_escape_alt3.sav
new file mode 100644 (file)
index 0000000..4578bc1
--- /dev/null
@@ -0,0 +1,3 @@
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape_alt4.sav b/tests/sav/base_inline_closure_escape_alt4.sav
new file mode 100644 (file)
index 0000000..33e5156
--- /dev/null
@@ -0,0 +1,5 @@
+2
+3
+4
+5
+6
diff --git a/tests/sav/base_inline_closure_escape_alt5.sav b/tests/sav/base_inline_closure_escape_alt5.sav
new file mode 100644 (file)
index 0000000..6613b56
--- /dev/null
@@ -0,0 +1,2 @@
+5
+6
diff --git a/tests/sav/base_inline_closure_fork.sav b/tests/sav/base_inline_closure_fork.sav
new file mode 100644 (file)
index 0000000..76ae684
--- /dev/null
@@ -0,0 +1,13 @@
+1
+2
+3
+4
+3
+4
+1
+2
+3
+4
+3
+4
+5
diff --git a/tests/sav/base_inline_closure_fork_alt1.sav b/tests/sav/base_inline_closure_fork_alt1.sav
new file mode 100644 (file)
index 0000000..5bec908
--- /dev/null
@@ -0,0 +1,9 @@
+1
+2
+3
+4
+1
+2
+3
+4
+5
diff --git a/tests/sav/base_inline_closure_fork_alt2.sav b/tests/sav/base_inline_closure_fork_alt2.sav
new file mode 100644 (file)
index 0000000..c728202
--- /dev/null
@@ -0,0 +1,3 @@
+1
+2
+5
diff --git a/tests/sav/base_inline_closure_fork_alt3.sav b/tests/sav/base_inline_closure_fork_alt3.sav
new file mode 100644 (file)
index 0000000..76ae684
--- /dev/null
@@ -0,0 +1,13 @@
+1
+2
+3
+4
+3
+4
+1
+2
+3
+4
+3
+4
+5
diff --git a/tests/sav/base_inline_closure_fork_alt4.sav b/tests/sav/base_inline_closure_fork_alt4.sav
new file mode 100644 (file)
index 0000000..b23b646
--- /dev/null
@@ -0,0 +1,5 @@
+1
+2
+1
+2
+5