icode: add IStaticCall
[nit.git] / src / icode / icode_tools.nit
index 3884840..9109c38 100644 (file)
@@ -92,11 +92,28 @@ class ICodeVisitor
 end
 
 redef class ICodeBuilder
+       # IRoutine currently inlining
+       # Used to avoid recursive inlining
+       var _current_inlining: Array[IRoutine] = new Array[IRoutine]
+
+       # Return false if routine can be saflely inlined
+       fun is_currently_inlining_routine(routine: IRoutine): Bool
+       do
+               return routine == iroutine or _current_inlining.has(routine)
+       end
+
        # Inline an iroutine in the current icode sequence
-       fun inline_routine(routine: IRoutine, args: Sequence[IRegister]): nullable IRegister
+       # Require not is_currently_inlining
+       fun inline_routine(routine: IRoutine, args: Sequence[IRegister], closdefs: nullable Sequence[nullable IClosureDef]): nullable IRegister
        do
+               assert not is_currently_inlining_routine(routine)
+               _current_inlining.add(routine)
                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,8 +134,20 @@ 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)
+               _current_inlining.pop
                return res
        end
 end
@@ -156,6 +185,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
 
@@ -266,17 +298,27 @@ redef class INew
        end
 end
 
-redef class IClosCall
+redef class IStaticCall
        redef fun inner_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)
+               return new IStaticCall(property, d.dup_iregs(exprs))
+       end
+end
+redef class IClosCall
+       redef fun dup_with(d)
+       do
+               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 +392,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