icode: inline methods with closures
authorJean Privat <jean@pryen.org>
Mon, 10 Aug 2009 19:01:15 +0000 (15:01 -0400)
committerJean Privat <jean@pryen.org>
Mon, 17 Aug 2009 19:06:07 +0000 (15:06 -0400)
Warning, break of closure call cannot be inlined.

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

src/analysis/inline_methods.nit
src/compiling/compiling_global.nit
src/icode/icode_tools.nit
src/syntax/icode_generation.nit
tests/base_inline_closure.nit [new file with mode: 0644]
tests/base_inline_closure2.nit [new file with mode: 0644]
tests/sav/base_inline_closure.sav [new file with mode: 0644]
tests/sav/base_inline_closure2.sav [new file with mode: 0644]

index a661452..eafa6d7 100644 (file)
@@ -35,7 +35,7 @@ special ICodeVisitor
                                var old_seq = icb.seq
                                icb.seq = seq
                                current_icode.insert_before(seq)
-                               var e = icb.inline_routine(ir, ic.exprs)
+                               var e = icb.inline_routine(ir, ic.exprs, ic.closure_defs)
                                var r = ic.result
                                if r != null then
                                        assert e != null
index bdc7e55..49b390f 100644 (file)
@@ -881,7 +881,7 @@ redef class MMLocalClass
                                                var ir = p.iroutine
                                                if ir == null then continue
                                                # FIXME: Not compatible with sep compilation
-                                               var e = icb.inline_routine(ir, iselfa).as(not null)
+                                               var e = icb.inline_routine(ir, iselfa, null).as(not null)
                                                icb.stmt(new IAttrWrite(p, iself, e))
                                        end
                                end
index 3884840..076f125 100644 (file)
@@ -93,10 +93,14 @@ end
 
 redef class ICodeBuilder
        # Inline an iroutine in the current icode sequence
-       fun inline_routine(routine: IRoutine, args: Sequence[IRegister]): nullable IRegister
+       fun inline_routine(routine: IRoutine, args: Sequence[IRegister], closdefs: nullable Sequence[nullable IClosureDef]): nullable IRegister
        do
                var d = new ICodeDupContext(self)
                assert args.length == routine.params.length
+               var closdecls = routine.closure_decls
+               var cdefsa = if closdefs != null then closdefs.length else 0
+               var cdeclsa = if closdecls != null then closdecls.length else 0
+               assert cdefsa <= cdeclsa
 
                # Fill register duplicate association
                var dico = d._registers
@@ -117,6 +121,17 @@ redef class ICodeBuilder
                        #seq.icodes.add(new IMove(dico[routine.params[i]]), args[i]))
                end
 
+               # Fill closure association
+               if closdecls != null then
+                       var cdico = d._closures
+                       for i in [0..cdefsa[ do
+                               cdico[closdecls[i]] = closdefs[i]
+                       end
+                       for i in [cdefsa..cdeclsa[ do
+                               cdico[closdecls[i]] = null
+                       end
+               end
+
                # Process inlining
                routine.body.dup_with(d)
                return res
@@ -156,6 +171,9 @@ private class ICodeDupContext
        # Used by dup_ireg
        var _registers: Map[IRegister, IRegister] = new HashMap[IRegister, IRegister]
 
+       # The association between a closure_decl and its closure_def (if any)
+       var _closures: Map[IClosureDecl, nullable IClosureDef] = new ArrayMap[IClosureDecl, nullable IClosureDef]
+
        # The current code builder
        var _icb: ICodeBuilder
 
@@ -267,16 +285,20 @@ redef class INew
 end
 
 redef class IClosCall
-       redef fun inner_dup_with(d)
+       redef fun dup_with(d)
        do
-               var c2 = new IClosCall(closure_decl, d.dup_iregs(exprs))
-               var bs = break_seq
-               if bs != null then
-                       var bs2 = new ISeq
-                       c2.break_seq = bs2
-                       bs.dup_seq_to(d, bs2)
+               var closdef = d._closures[closure_decl]
+               if closdef == null then
+                       # Default is already guarded and inlined
+                       return
+               end
+               # Break sequence cannot be inlined :/
+               assert break_seq == null
+               var res = d._icb.inline_routine(closdef, d.dup_iregs(exprs), null)
+               if result != null then
+                       assert res != null
+                       d._icb.stmt(new IMove(d.dup_ireg(result.as(not null)), res))
                end
-               return c2
        end
 end
 
@@ -350,6 +372,13 @@ end
 redef class IHasClos
        redef fun inner_dup_with(d)
        do
-               return new IHasClos(closure_decl)
+               var closdef = d._closures[closure_decl]
+               var res: IRegister
+               if closdef != null then
+                       res = d._icb.lit_true_reg
+               else
+                       res = d._icb.lit_false_reg
+               end
+               return new IMove(d.dup_ireg(result.as(not null)), res)
        end
 end
index 9477f2d..64fd0f2 100644 (file)
@@ -1450,7 +1450,7 @@ redef class AClosureCallExpr
                                v.add_assignment(r, r2)
                        end
                        v.seq = iif.else_seq
-                       var r3 = v.inline_routine(closdecl_default, args)
+                       var r3 = v.inline_routine(closdecl_default, args, null)
                        if r != null then
                                assert r3 != null
                                v.add_assignment(r, r3)
diff --git a/tests/base_inline_closure.nit b/tests/base_inline_closure.nit
new file mode 100644 (file)
index 0000000..645fa8c
--- /dev/null
@@ -0,0 +1,44 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2009 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
+
+interface Inline__
+       fun foo
+               !f
+       do
+               0.output
+               f
+               2.output
+       end
+
+       fun bar
+               !b do 11.output
+       do
+               10.output
+               b
+               12.output
+       end
+end
+
+class A
+special Inline__
+end
+
+var a: A = new A
+a.foo !f do 1.output
+a.bar !b do 1.output
+a.bar
diff --git a/tests/base_inline_closure2.nit b/tests/base_inline_closure2.nit
new file mode 100644 (file)
index 0000000..31ef7b9
--- /dev/null
@@ -0,0 +1,44 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2009 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
+
+interface Inline__
+       fun foo
+               !f: Int
+       do
+               0.output
+               f.output
+               2.output
+       end
+
+       fun bar
+               !b: Int do continue 11
+       do
+               10.output
+               b.output
+               12.output
+       end
+end
+
+class A
+special Inline__
+end
+
+var a: A = new A
+a.foo !f do continue 1
+a.bar !b do continue 1
+a.bar
diff --git a/tests/sav/base_inline_closure.sav b/tests/sav/base_inline_closure.sav
new file mode 100644 (file)
index 0000000..52a0ad1
--- /dev/null
@@ -0,0 +1,9 @@
+0
+1
+2
+10
+1
+12
+10
+11
+12
diff --git a/tests/sav/base_inline_closure2.sav b/tests/sav/base_inline_closure2.sav
new file mode 100644 (file)
index 0000000..52a0ad1
--- /dev/null
@@ -0,0 +1,9 @@
+0
+1
+2
+10
+1
+12
+10
+11
+12