Merge branch 'package2module' into wip
[nit.git] / src / compiling / compiling_icode.nit
index 847280b..00e87c4 100644 (file)
@@ -51,10 +51,10 @@ class I2CCompilerVisitor
                                        if not strs.has_key(i) then strs[i] = "REGB{i}"
                                else if closure and not e.is_local then
                                        strs = once new HashMap[Int, String]
-                                       if not strs.has_key(i) then strs[i] = "closctx->variable[{i}]"
+                                       if not strs.has_key(i) then strs[i] = "closctx->REG[{i}]"
                                else
                                        strs = once new HashMap[Int, String]
-                                       if not strs.has_key(i) then strs[i] = "REG[{i}]"
+                                       if not strs.has_key(i) then strs[i] = "fra.me.REG[{i}]"
                                end
                                s = strs[i]
                                ids[e] = s
@@ -94,7 +94,7 @@ class I2CCompilerVisitor
        end
 
        # The rank (number) of each closure
-       readable var _closures: HashMap[IClosureDecl, Int] = new HashMap[IClosureDecl, Int]
+       readable var _closures: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
 
        # The functionnal type of each closure
        readable var _clostypes: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
@@ -134,11 +134,14 @@ class I2CCompilerVisitor
                else
                        assert closure
                        var ind = register_escape_label(seq)
-                       add_instr("closctx->has_broke = (val_t*){ind};")
+                       add_instr("closctx->has_broke = {ind};")
                        add_instr("goto {lab(return_label.as(not null))};")
                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
 
@@ -156,14 +159,28 @@ class I2CCompilerVisitor
                visitor.add_decl(s)
        end
 
-       fun add_instr(s: String)
+       # Prepare a new instuction (indent, comment)
+       # Caller must ensure to add a new line to finish its instr
+       fun new_instr: Writer
        do
+               var w = visitor.writer
                var l = _next_location
                if l != null then
-                       visitor.add_instr("/* ", l.file, ":", l.line_start.to_s, " */")
+                       visitor.add_indent(w)
+                       w.add("/* ")
+                       w.add(l.file)
+                       w.add(":")
+                       w.add(l.line_start.to_s)
+                       w.add(" */\n")
                        _next_location = null
                end
-               visitor.add_instr(s)
+               visitor.add_indent(w)
+               return w
+       end
+
+       fun add_instr(s: String)
+       do
+               new_instr.add(s).add("\n")
        end
 
        fun indent
@@ -224,19 +241,20 @@ redef class IRoutine
                        cparams.add("val_t p{i}")
                end
                if closure_decls != null then
+                       cparams.add("struct stack_frame_t *closctx_param")
                        for i in [0..closure_decls.length[ do
                                var closcn = "CLOS_{cname}_{i}"
                                var cs = closure_decls[i].closure.signature
                                var subparams = new Array[String] # Parameters of the closure
-                               subparams.add("struct WBT_ *")
+                               subparams.add("struct stack_frame_t *")
                                for j in [0..cs.arity[ do
                                        subparams.add("val_t")
                                end
                                var rr = "void"
                                if cs.return_type != null then rr = "val_t"
                                v.add_decl("typedef {rr} (*{closcn})({subparams.join(", ")});")
-                               cargs.add("wd{i}")
-                               cparams.add("struct WBT_ *wd{i}")
+                               cargs.add("clos_fun{i}")
+                               cparams.add("fun_t clos_fun{i}")
                        end
                end
                if after_params != null then cparams.add(after_params)
@@ -248,10 +266,10 @@ redef class IRoutine
                else
                        p = cparams.join(", ")
                end
-               if human_name != null then v.add_decl("#define LOCATE_", cname, " \"", human_name, "\"")
-               v.add_decl(r, " ", cname, "(", p, ");")
-               v.add_decl("typedef ", r, " (*", cname, "_t)(", p, ");")
-               v.add_instr(r, " ", cname, "(", p, ")\{")
+               if human_name != null then v.add_decl("static const char * const LOCATE_{cname} = \"{human_name}\";")
+               v.add_decl("{r} {cname}({p});")
+               v.add_decl("typedef {r} (*{cname}_t)({p});")
+               v.add_instr("{r} {cname}({p})\{")
                v.indent
                return cargs
        end
@@ -259,44 +277,50 @@ redef class IRoutine
        # Compile the body of the routine, return the result value is any
        fun compile_inside_to_c(v: I2CCompilerVisitor, args: Array[String]): nullable String
        do
-               # Add the trace
+               # Create and push the stack frame
                var ll = 0
                if location != null then
                        ll = location.line_start
                end
-               v.add_decl("struct trace_t trace = \{NULL, NULL, {ll}, LOCATE_{v.basecname}\};")
-               v.add_instr("trace.prev = tracehead; tracehead = &trace;")
-               v.add_instr("trace.file = LOCATE_{v.visitor.module.name};")
-
-               # Add local variables
-               if std_slots_nb == 0 then
-                       v.add_decl("val_t *REG = NULL;")
+               # Encapsulate the frame ('me') in a larger structure ('fra') that has enough space to store the local variables (REG)
+               if std_slots_nb > 1 then
+                       v.add_decl("struct \{struct stack_frame_t me; val_t MORE_REG[{std_slots_nb-1}];\} fra;")
                else
-                       v.add_decl("val_t REG[{std_slots_nb}];")
+                       v.add_decl("struct \{struct stack_frame_t me;\} fra;")
+               end
+               v.add_instr("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;")
+               v.add_instr("fra.me.file = LOCATE_{v.visitor.mmmodule.name};")
+               v.add_instr("fra.me.line = {ll};")
+               v.add_instr("fra.me.meth = LOCATE_{v.basecname};")
+               v.add_instr("fra.me.has_broke = 0;")
+               v.add_instr("fra.me.REG_size = {std_slots_nb};")
+
+               # Declare/initialize local variables
+               for i in [0..std_slots_nb[ do
+                       v.add_instr("fra.me.REG[{i}] = NIT_NULL;")
                end
                for i in [0..tag_slots_nb[ do
                        v.add_decl("val_t REGB{i};")
                end
                var iclosdecls = closure_decls
                if iclosdecls != null then
-                       v.add_decl("struct WBT_ *CREG[{iclosdecls.length}];")
-               else
-                       v.add_decl("struct WBT_ **CREG = NULL;")
+                       v.add_decl("fun_t CREG[{iclosdecls.length}];")
+                       v.add_instr("fra.me.closure_ctx = closctx_param;")
+                       v.add_instr("fra.me.closure_funs = CREG;")
                end
-               var i = 0
+               var k = 0
                for r in params do
-                       if r.slot_index != null then v.add_assignment(v.register(r), args[i])
-                       i += 1
+                       if r.slot_index != null then v.add_assignment(v.register(r), args[k])
+                       k += 1
                end
-               var iclosdecls = closure_decls
                if iclosdecls != null then
                        for i in [0..iclosdecls.length[ do
                                var iclosdecl = iclosdecls[i]
                                v.add_instr("CREG[{i}] = {args[params.length+i]};")
-                               v.closures[iclosdecl] = i
+                               v.closures[iclosdecl] = i.to_s
                                var cs = iclosdecl.closure.signature # Closure signature
                                var subparams = new Array[String] # Parameters of the closure
-                               subparams.add("struct WBT_ *")
+                               subparams.add("struct stack_frame_t *")
                                for j in [0..cs.arity[ do
                                        var p = "val_t"
                                        subparams.add(p)
@@ -315,7 +339,7 @@ redef class IRoutine
                # Compile body
                body.compile_to_c(v)
 
-               v.add_instr("tracehead = trace.prev;")
+               v.add_instr("stack_frame_head = fra.me.prev;")
                v.return_label = old_rl
                var r = result
                if r != null then
@@ -326,11 +350,9 @@ redef class IRoutine
        end
 
        # Full compilation of the routine
-       # Including optimization and other stuff.
        # cv must be in the correct function
        fun compile_to_c(cv: CompilerVisitor, cname: String, args: Array[String]): nullable String
        do
-               optimize
                var v = new I2CCompilerVisitor(cv, self, cname)
                return compile_inside_to_c(v, args)
        end
@@ -338,11 +360,7 @@ end
 
 redef class ICode
        # Full compilation of the icode
-       fun compile_to_c(v: I2CCompilerVisitor)
-       do
-               v.add_location(location)
-               store_result(v, inner_compile_to_c(v))
-       end
+       fun compile_to_c(v: I2CCompilerVisitor) is abstract
 
        # Is a result really needed
        private fun need_result: Bool
@@ -352,76 +370,102 @@ redef class ICode
        end
 
        # Store s in the result value of self
-       private fun store_result(v: I2CCompilerVisitor, s: nullable String)
+       private fun store_result(v: I2CCompilerVisitor, w: nullable Writer)
        do
                var r = result
                if r != null and r.slot_index != null then
-                       assert s != null
-                       v.add_assignment(v.register(r), s)
-               else if s != null and not self isa IMove then
-                       v.add_instr(s + ";")
+                       assert w != null
+                       var w2 = v.new_instr
+                       w2.add(v.register(r))
+                       w2.add(" = ")
+                       w2.append(w)
+                       w2.add(";\n")
+               else if w != null and not is_pure then
+                       # ICode with side effects must be evaluated
+                       # even if the result is not wanted
+                       var w2 = v.new_instr
+                       w2.append(w)
+                       w2.add(";\n")
                end
        end
 
-       # Compilation of without the result assigment
-       # Return the right value is case of expression
-       # Return the full expression (witout ;) in case of statement
-       private fun inner_compile_to_c(v: I2CCompilerVisitor): nullable String is abstract
+       # Prepare a writer if the expression icode need to be compiled
+       # * Result assigment is automatic if needed
+       private fun new_result(v: I2CCompilerVisitor): Writer
+       do
+               assert need_result or not is_pure
+               var w2 = v.new_instr
+               var r = result
+               if r != null and r.slot_index != null then
+                       w2.add(v.register(r))
+                       w2.add(" = ")
+               end
+               var w = w2.sub
+               w2.add(";\n")
+               return w
+       end
 end
 
 redef class ISeq
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
+               v.add_location(location)
                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
                v.add_label(self)
-               return null
        end
 end
 
 redef class IIf
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               v.add_instr("if (UNTAG_Bool({v.register(expr)})) \{")
+               v.add_location(location)
+               var w = v.new_instr
+               w.add("if (UNTAG_Bool(")
+               w.add(v.register(expr))
+               w.add(")) \{\n")
                if not then_seq.icodes.is_empty then
                        v.indent
-                       then_seq.inner_compile_to_c(v)
+                       then_seq.compile_to_c(v)
                        v.unindent
                end
                if not else_seq.icodes.is_empty then
-                       v.add_instr("} else \{")
+                       v.add_instr("\} else \{")
                        v.indent
-                       else_seq.inner_compile_to_c(v)
+                       else_seq.compile_to_c(v)
                        v.unindent
                end
-               v.add_instr("}")
-               return null
+               v.add_instr("\}")
        end
 end
 
 redef class ILoop
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
+               v.add_location(location)
                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
                        ic.compile_to_c(v)
                end
                v.unindent
-               v.add_instr("}")
+               v.add_instr("\}")
                v.add_label(self)
-               return null
        end
 end
 
 redef class IEscape
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               v.add_goto(seq)
-               return null
+               v.add_location(location)
+               v.add_goto(v.marks_to_seq[iescape_mark])
        end
 end
 
@@ -434,47 +478,58 @@ redef class IAbsCall
                # Compile closure definitions
                var old_el = v.escaped_labels
                var closdefs = closure_defs
-               var closcns: nullable Array[String] = null
+               var closctx: nullable String = null # The closure context of closdefs
                if closdefs != null then
+                       # Get the closure context
+                       if v.closure then
+                               closctx = "closctx"
+                       else
+                               closctx = "(&(fra.me))"
+                       end
+
+                       # First aditionnal arguments is the closure context
+                       args.add(closctx)
+
+                       # We are in a new escape boundary
                        v.escaped_labels = new HashMap[ISeq, Int]
-                       closcns = new Array[String]
+
+                       # Compile each closures and add each sub-function as an other additionnal parameter
                        for cd in closdefs do
                                if cd != null then
                                        var cn = cd.compile_closure(v)
                                        args.add(cn)
-                                       closcns.add(cn)
                                else
                                        args.add("NULL")
                                end
                        end
                end
 
-               var s = compile_call_to_c(v, args)
-               var r: nullable String = s
+               # Compile the real call
+               var call = compile_call_to_c(v, args)
+               var res: nullable Writer = call
 
                # Intercept escapes
-               if closcns != null then
+               if closctx != null then
                        var els = v.escaped_labels
                        v.escaped_labels = old_el
                        # Is there possible escapes?
                        if not els.is_empty then
                                # Call in a tmp variable to avoid 'break' overwrite
+                               var w = v.new_instr
                                if need_result then
-                                       r = "tmp"
-                                       v.add_assignment(r, s)
+                                       w.add("tmp")
+                                       w.add(" = ")
+                                       w.append(call)
+                                       w.add(";\n")
+                                       res = new Writer
+                                       res.add("tmp")
                                else
-                                       r = null
-                                       v.add_instr(s + ";")
+                                       res = null
+                                       w.append(call)
+                                       w.add(";\n")
                                end
-                               # What is the escape index (if any?)
-                               # It's computed as the union of has_broke
-                               var switcha = new Array[String]
-                               for cn in closcns do
-                                       switcha.add("((int)({cn}->has_broke))")
-                               end
-                               var switch = switcha.join(" | ")
                                # What are the expected escape indexes
-                               v.add_instr("switch ({switch}) \{")
+                               v.new_instr.add("switch (").add(closctx).add("->has_broke) \{\n")
                                v.indent
                                # No escape occured, continue as usual
                                v.add_instr("case 0: break;")
@@ -485,7 +540,8 @@ redef class IAbsCall
                                        var seq = iels.key
                                        if lls.has(seq) then
                                                # Local escape occured
-                                               v.add_instr("case {iels.item}: goto {v.lab(seq)};")
+                                               # Clear the has_broke information and go to the target
+                                               v.new_instr.add("case ").add(iels.item.to_s).add(": ").add(closctx).add("->has_broke = 0; goto ").add(v.lab(seq)).add(";\n")
                                        else
                                                # Forward escape occured: register the escape label
                                                assert v.closure
@@ -494,34 +550,40 @@ redef class IAbsCall
                                        end
                                        iels.next
                                end
-                               # Forward escape occured, just pass to the next one
+                               # If forward escape occured, just pass to the next one
                                if forward_escape then
-                                       v.add_instr("default: closctx->has_broke = (val_t*)({switch}); goto {v.lab(v.return_label.as(not null))};")
+                                       # Do not need to copy 'has_broke' value since it is shared by the next one.
+                                       # So just exit the C function.
+                                       v.new_instr.add("default: goto ").add(v.lab(v.return_label.as(not null))).add(";\n")
                                end
                                v.unindent
                                v.add_instr("\}")
                        end
                end
 
-               store_result(v, r)
+               if res != null then
+                       var w = new_result(v)
+                       w.append(res)
+               end
        end
 
-       redef fun inner_compile_to_c(v) do abort
-
        # The single invocation witout fancy stuffs
-       private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): String is abstract
+       private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): Writer is abstract
 end
 
 redef class ICall
        redef fun compile_call_to_c(v, args)
        do
+               var w = new Writer
                var prop = property
                if prop.global.is_init then args.add("init_table")
-               if prop.name == (once ("add".to_symbol)) and prop.local_class.name == (once ("Array".to_symbol)) then
-                       return "{prop.cname}({args.join(", ")})"
-               else
-                       return "{prop.global.meth_call}({args[0]})({args.join(", ")})"
-               end
+               w.add(prop.global.meth_call)
+               w.add("(")
+               w.add(args.first)
+               w.add(")(")
+               w.add_all(args, ", ")
+               w.add(")")
+               return w
        end
 end
 
@@ -530,162 +592,532 @@ redef class ISuper
        do
                var prop = property
                if prop.global.is_init then args.add("init_table")
-               return "{prop.super_meth_call}({args[0]})({args.join(", ")})"
+               var w = new Writer
+               w.add(prop.super_meth_call)
+               w.add("(")
+               w.add(args.first)
+               w.add(")(")
+               w.add_all(args, ", ")
+               w.add(")")
+               return w
        end
 end
 
 redef class INew
        redef fun compile_call_to_c(v, args)
        do
-               return "NEW_{stype.local_class}_{property.global.intro.cname}({args.join(", ")})"
+               var w = new Writer
+               w.add("NEW_")
+               w.add(stype.local_class.to_s)
+               w.add("_")
+               w.add(property.global.intro.cname)
+               w.add("(")
+               w.add_all(args, ", ")
+               w.add(")")
+               return w
+       end
+end
+
+redef class IAllocateInstance
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("NEW_")
+               w.add(stype.local_class.name.to_s)
+               w.add("()")
+       end
+end
+
+redef class ICheckInstance
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("CHECKNEW_")
+               w.add(stype.local_class.name.to_s)
+               w.add("(")
+               w.add(v.register(expr))
+               w.add(")")
+       end
+end
+
+redef class IInitAttributes
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = v.new_instr
+               w.add("INIT_ATTRIBUTES__")
+               w.add(stype.local_class.name.to_s)
+               w.add("(")
+               w.add(v.register(expr))
+               w.add(");\n")
+       end
+end
+
+redef class IStaticCall
+       redef fun compile_call_to_c(v, args)
+       do
+               var prop = property
+               if prop.global.is_init then args.add("init_table")
+               var w = new Writer
+               w.add(property.cname)
+               w.add("(")
+               w.add_all(args, ", ")
+               w.add(")")
+               return w
        end
 end
 
 redef class INative
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               if exprs.is_empty then
-                       return code
+               v.add_location(location)
+               if method.is_intern then
+                       compile_intern_method_to_c(v)
                else
-                       var res = new Buffer
-                       var i = 0
-                       var c = code.split_with("@@@")
-                       for s in c do
-                               res.append(s)
-                               if i < exprs.length and i < c.length-1 then
-                                       res.append(v.register(exprs[i]))
-                               end
-                               i += 1
+                       compile_extern_method_to_c(v)
+               end
+       end
+
+       fun compile_extern_method_to_c(v: I2CCompilerVisitor)
+       do
+               var ename = method.extern_name.as(not null)#"{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
+               var sig = method.signature
+               assert exprs.length == sig.arity + 1
+
+               var regs = v.registers(exprs)
+
+               var args = new Array[String]
+               args.add(sig.recv.unboxtype(regs[0]))
+               for i in [0..sig.arity[ do
+                       args.add(sig[i].unboxtype(regs[i+1]))
+               end
+               var s = "{ename}({args.join(", ")})"
+
+               if need_result then s = sig.return_type.boxtype(s)
+               var w = new_result(v)
+               w.add(s)
+       end
+
+       fun compile_intern_method_to_c(v: I2CCompilerVisitor)
+       do
+               var sig = method.signature
+               assert exprs.length == sig.arity + 1
+               var c = method.local_class.name
+               var n = method.name
+               var regs = v.registers(exprs)
+               var s: nullable String = null
+               if c == once "Int".to_symbol then
+                       if n == once "object_id".to_symbol then
+                               s = regs[0]
+                       else if n == once "unary -".to_symbol then
+                               s = "TAG_Int(-UNTAG_Int({regs[0]}))"
+                       else if n == once "output".to_symbol then
+                               s = "printf(\"%ld\\n\", UNTAG_Int({regs[0]}));"
+                       else if n == once "ascii".to_symbol then
+                               s = "TAG_Char(UNTAG_Int({regs[0]}))"
+                       else if n == once "succ".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})+1)"
+                       else if n == once "prec".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})-1)"
+                       else if n == once "to_f".to_symbol then
+                               s = "BOX_Float((float)UNTAG_Int({regs[0]}))"
+                       else if n == once "+".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})+UNTAG_Int({regs[1]}))"
+                       else if n == once "-".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})-UNTAG_Int({regs[1]}))"
+                       else if n == once "*".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})*UNTAG_Int({regs[1]}))"
+                       else if n == once "/".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})/UNTAG_Int({regs[1]}))"
+                       else if n == once "%".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})%UNTAG_Int({regs[1]}))"
+                       else if n == once "<".to_symbol then
+                               s = "TAG_Bool(UNTAG_Int({regs[0]})<UNTAG_Int({regs[1]}))"
+                       else if n == once ">".to_symbol then
+                               s = "TAG_Bool(UNTAG_Int({regs[0]})>UNTAG_Int({regs[1]}))"
+                       else if n == once "<=".to_symbol then
+                               s = "TAG_Bool(UNTAG_Int({regs[0]})<=UNTAG_Int({regs[1]}))"
+                       else if n == once ">=".to_symbol then
+                               s = "TAG_Bool(UNTAG_Int({regs[0]})>=UNTAG_Int({regs[1]}))"
+                       else if n == once "lshift".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})<<UNTAG_Int({regs[1]}))"
+                       else if n == once "rshift".to_symbol then
+                               s = "TAG_Int(UNTAG_Int({regs[0]})>>UNTAG_Int({regs[1]}))"
+                       else if n == once "==".to_symbol then
+                               s = "TAG_Bool(({regs[0]})==({regs[1]}))"
+                       else if n == once "!=".to_symbol then
+                               s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
+                       end
+               else if c == once "Float".to_symbol then
+                       if n == once "object_id".to_symbol then
+                               s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
+                       else if n == once "unary -".to_symbol then
+                               s = "BOX_Float(-UNBOX_Float({regs[0]}))"
+                       else if n == once "output".to_symbol then
+                               s = "printf(\"%f\\n\", UNBOX_Float({regs[0]}));"
+                       else if n == once "to_i".to_symbol then
+                               s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
+                       else if n == once "+".to_symbol then
+                               s = "BOX_Float(UNBOX_Float({regs[0]})+UNBOX_Float({regs[1]}))"
+                       else if n == once "-".to_symbol then
+                               s = "BOX_Float(UNBOX_Float({regs[0]})-UNBOX_Float({regs[1]}))"
+                       else if n == once "*".to_symbol then
+                               s = "BOX_Float(UNBOX_Float({regs[0]})*UNBOX_Float({regs[1]}))"
+                       else if n == once "/".to_symbol then
+                               s = "BOX_Float(UNBOX_Float({regs[0]})/UNBOX_Float({regs[1]}))"
+                       else if n == once "<".to_symbol then
+                               s = "TAG_Bool(UNBOX_Float({regs[0]})<UNBOX_Float({regs[1]}))"
+                       else if n == once ">".to_symbol then
+                               s = "TAG_Bool(UNBOX_Float({regs[0]})>UNBOX_Float({regs[1]}))"
+                       else if n == once "<=".to_symbol then
+                               s = "TAG_Bool(UNBOX_Float({regs[0]})<=UNBOX_Float({regs[1]}))"
+                       else if n == once ">=".to_symbol then
+                               s = "TAG_Bool(UNBOX_Float({regs[0]})>=UNBOX_Float({regs[1]}))"
                        end
-                       return res.to_s
+               else if c == once "Char".to_symbol then
+                       if n == once "object_id".to_symbol then
+                               s = "TAG_Int(UNTAG_Char({regs[0]}))"
+                       else if n == once "unary -".to_symbol then
+                               s = "TAG_Char(-UNTAG_Char({regs[0]}))"
+                       else if n == once "output".to_symbol then
+                               s = "printf(\"%c\", (unsigned char)UNTAG_Char({regs[0]}));"
+                       else if n == once "ascii".to_symbol then
+                               s = "TAG_Int((unsigned char)UNTAG_Char({regs[0]}))"
+                       else if n == once "succ".to_symbol then
+                               s = "TAG_Char(UNTAG_Char({regs[0]})+1)"
+                       else if n == once "prec".to_symbol then
+                               s = "TAG_Char(UNTAG_Char({regs[0]})-1)"
+                       else if n == once "to_i".to_symbol then
+                               s = "TAG_Int(UNTAG_Char({regs[0]})-'0')"
+                       else if n == once "+".to_symbol then
+                               s = "TAG_Char(UNTAG_Char({regs[0]})+UNTAG_Char({regs[1]}))"
+                       else if n == once "-".to_symbol then
+                               s = "TAG_Char(UNTAG_Char({regs[0]})-UNTAG_Char({regs[1]}))"
+                       else if n == once "*".to_symbol then
+                               s = "TAG_Char(UNTAG_Char({regs[0]})*UNTAG_Char({regs[1]}))"
+                       else if n == once "/".to_symbol then
+                               s = "TAG_Char(UNTAG_Char({regs[0]})/UNTAG_Char({regs[1]}))"
+                       else if n == once "%".to_symbol then
+                               s = "TAG_Char(UNTAG_Char({regs[0]})%UNTAG_Char({regs[1]}))"
+                       else if n == once "<".to_symbol then
+                               s = "TAG_Bool(UNTAG_Char({regs[0]})<UNTAG_Char({regs[1]}))"
+                       else if n == once ">".to_symbol then
+                               s = "TAG_Bool(UNTAG_Char({regs[0]})>UNTAG_Char({regs[1]}))"
+                       else if n == once "<=".to_symbol then
+                               s = "TAG_Bool(UNTAG_Char({regs[0]})<=UNTAG_Char({regs[1]}))"
+                       else if n == once ">=".to_symbol then
+                               s = "TAG_Bool(UNTAG_Char({regs[0]})>=UNTAG_Char({regs[1]}))"
+                       else if n == once "==".to_symbol then
+                               s = "TAG_Bool(({regs[0]})==({regs[1]}))"
+                       else if n == once "!=".to_symbol then
+                               s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
+                       end
+               else if c == once "Bool".to_symbol then
+                       if n == once "object_id".to_symbol then
+                               s = "TAG_Int(UNTAG_Bool({regs[0]}))"
+                       else if n == once "unary -".to_symbol then
+                               s = "TAG_Bool(-UNTAG_Bool({regs[0]}))"
+                       else if n == once "output".to_symbol then
+                               s = "(void)printf(UNTAG_Bool({regs[0]})?\"true\\n\":\"false\\n\");"
+                       else if n == once "ascii".to_symbol then
+                               s = "TAG_Bool(UNTAG_Bool({regs[0]}))"
+                       else if n == once "to_i".to_symbol then
+                               s = "TAG_Int(UNTAG_Bool({regs[0]}))"
+                       else if n == once "==".to_symbol then
+                               s = "TAG_Bool(({regs[0]})==({regs[1]}))"
+                       else if n == once "!=".to_symbol then
+                               s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
+                       end
+               else if c == once "NativeArray".to_symbol then
+                       if n == once "object_id".to_symbol then
+                               s = "TAG_Int(((Nit_NativeArray){regs[0]})->object_id)"
+                       else if n == once "[]".to_symbol then
+                               s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]"
+                       else if n == once "[]=".to_symbol then
+                               s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]={regs[2]}"
+                       else if n == once "copy_to".to_symbol then
+                               s = "(void)memcpy(((Nit_NativeArray ){regs[1]})->val, ((Nit_NativeArray){regs[0]})->val, UNTAG_Int({regs[2]})*sizeof(val_t))"
+                       end
+               else if c == once "NativeString".to_symbol then
+                       if n == once "object_id".to_symbol then
+                               s = "TAG_Int(UNBOX_NativeString({regs[0]}))"
+                       else if n == once "atoi".to_symbol then
+                               s = "TAG_Int(atoi(UNBOX_NativeString({regs[0]})))"
+                       else if n == once "[]".to_symbol then
+                               s = "TAG_Char(UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})])"
+                       else if n == once "[]=".to_symbol then
+                               s = "UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})]=UNTAG_Char({regs[2]});"
+                       else if n == once "copy_to".to_symbol then
+                               s = "(void)memcpy(UNBOX_NativeString({regs[1]})+UNTAG_Int({regs[4]}), UNBOX_NativeString({regs[0]})+UNTAG_Int({regs[3]}), UNTAG_Int({regs[2]}));"
+                       end
+               else if n == once "object_id".to_symbol then
+                       s = "TAG_Int((bigint)((obj_t){regs[0]})[1].object_id)"
+               else if n == once "sys".to_symbol then
+                       s = "(G_sys)"
+               else if n == once "is_same_type".to_symbol then
+                       s = "TAG_Bool((VAL2VFT({regs[0]})==VAL2VFT({regs[1]})))"
+               else if n == once "exit".to_symbol then
+                       s = "exit(UNTAG_Int({regs[1]}));"
+               else if n == once "calloc_array".to_symbol then
+                       s = "NEW_NativeArray(UNTAG_Int({regs[1]}), sizeof(val_t))"
+               else if n == once "calloc_string".to_symbol then
+                       s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int({regs[1]}) * sizeof(char))))"
+               end
+               if s == null then
+                       var ll = location
+                       if ll != null then v.add_instr("fprintf(stderr, \"{ll.to_s}: \");")
+                       v.add_instr("fprintf(stderr, \"Fatal error: unknown intern method {method.full_name}.\\n\");")
+                       v.add_instr("nit_exit(1);")
+                       s = "NIT_NULL"
+               end
+               if result == null then
+                       v.new_instr.add(s).add(";\n")
+               else if need_result then
+                       var w = new_result(v)
+                       w.add(s)
                end
        end
 end
 
+redef class IIntValue
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("TAG_Int(").add(value.to_s).add(")")
+       end
+end
+
+redef class IBoolValue
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("TAG_Bool(")
+               if value then w.add("true") else w.add("false")
+               w.add(")")
+       end
+end
+
+redef class ICharValue
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("TAG_Char(").add(value).add(")")
+       end
+end
+
+redef class IFloatValue
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("BOX_Float(").add(value).add(")")
+       end
+end
+
+redef class IStringValue
+       redef fun compile_to_c(v)
+       do
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("BOX_NativeString(\"").add(value).add("\")")
+       end
+end
+
 redef class IAbort
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               var s = new Buffer.from("fprintf(stderr")
-               for t in texts do
-                       s.append(", \"{t}\"")
+               v.add_location(location)
+               var w = v.new_instr
+               w.add("nit_abort(\"")
+               w.add(texts[0])
+               if texts.length > 1 then
+                       w.add("\", \"")
+                       w.add(texts[1])
+                       w.add("\"")
+               else
+                       w.add("\", NULL")
                end
-               s.append(");")
-               v.add_instr(s.to_s)
-
+               w.add(", LOCATE_")
+               w.add(module_location.name.to_s)
                var ll = location
-               var pl = property_location
-               s = new Buffer.from("fprintf(stderr, \"")
-               if pl != null then s.append(" in %s")
-               s.append(" (%s")
                if ll != null then
-                       s.append(":%d")
-               end
-               s.append(")\\n\", ")
-               if pl != null then s.append("LOCATE_{pl.cname}, ")
-               s.append("LOCATE_{module_location.name}")
-               if ll != null then
-                       s.append(", {ll.line_start}")
+                       w.add(", ")
+                       w.add(ll.line_start.to_s)
+               else
+                       w.add(", 0")
                end
-               s.append(");")
-               v.add_instr(s.to_s)
-
-               v.add_instr("nit_exit(1);")
-               return null
+               w.add(");\n")
        end
 end
 
 redef class IMove
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               return v.register(expr)
+               if not need_result then return
+               var e = v.register(expr)
+               var r = v.register(result.as(not null))
+               if e == r then return
+               v.add_location(location)
+               var w = v.new_instr
+               w.add(r)
+               w.add(" = ")
+               w.add(e)
+               w.add(";\n")
        end
 end
 
 redef class IAttrRead
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               return "{property.global.attr_access}({v.register(expr)})"
+               if not need_result then return
+               v.add_location(location)
+               var w = new_result(v)
+               w.add(property.global.attr_access)
+               w.add("(")
+               w.add(v.register(expr))
+               w.add(")")
        end
 end
 
 redef class IAttrIsset
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               return "TAG_Bool({property.global.attr_access}({v.register(expr)})!=NIT_NULL)"
+               if not need_result then return
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("TAG_Bool(")
+               w.add(property.global.attr_access)
+               w.add("(")
+               w.add(v.register(expr))
+               w.add(")!=NIT_NULL)")
        end
 end
 
 redef class IAttrWrite
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               v.add_instr("{property.global.attr_access}({v.register(expr1)}) = {v.register(expr2)};")
-               return null
+               v.add_location(location)
+               var w = v.new_instr
+               w.add(property.global.attr_access)
+               w.add("(")
+               w.add(v.register(expr1))
+               w.add(") = ")
+               w.add(v.register(expr2))
+               w.add(";\n")
        end
 end
 
 redef class ITypeCheck
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
+               if not need_result then return
                # FIXME handle formaltypes
+               v.add_location(location)
                var g = stype.local_class.global
                var recv = v.register(expr)
-               var s = ""
+               var w = new_result(v)
+               w.add("TAG_Bool(")
                if expr.stype.is_nullable then
                        if stype.is_nullable then
-                               s = "({recv}==NIT_NULL) || "
+                               w.add("(")
+                               w.add(recv)
+                               w.add("==NIT_NULL) || ")
                        else if stype.as_nullable == expr.stype then
-                               return "TAG_Bool({recv}!=NIT_NULL)"
+                               w.add(recv)
+                               w.add("!=NIT_NULL)")
+                               return
                        else
-                               s = "({recv}!=NIT_NULL) && "
+                               w.add("(")
+                               w.add(recv)
+                               w.add("!=NIT_NULL) && ")
                        end
                end
-               return "TAG_Bool({s}VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {stype}*/"
+               w.add("VAL_ISA(")
+               w.add(recv)
+               w.add(", ")
+               w.add(g.color_id)
+               w.add(", ")
+               w.add(g.id_id)
+               w.add(")) /*cast ")
+               w.add(stype.to_s)
+               w.add("*/")
        end
 end
 
 redef class IIs
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
+               if not need_result then return
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("TAG_Bool(")
                var t1 = expr1.stype
                var t2 = expr2.stype
                if t1 isa MMTypeNone then
                        if t2 isa MMTypeNone then
-                               return "TAG_Bool(1)"
+                               w.add("1)")
+                               return
                        else if t2.is_nullable then
-                               return "TAG_Bool({v.register(expr2)}==NIT_NULL)"
+                               w.add(v.register(expr2))
+                               w.add("==NIT_NULL)")
+                               return
                        else
-                               return "TAG_Bool(0)"
+                               w.add("0)")
+                               return
                        end
                else if t1.is_nullable then
                        if t2 isa MMTypeNone then
-                               return "TAG_Bool({v.register(expr1)}==NIT_NULL)"
+                               w.add(v.register(expr1))
+                               w.add("==NIT_NULL)")
+                               return
                        else if t2.is_nullable then
-                               return "TAG_Bool(IS_EQUAL_NN({v.register(expr1)},{v.register(expr2)}))"
+                               w.add("IS_EQUAL_NN(")
                        else
-                               return "TAG_Bool(IS_EQUAL_ON({v.register(expr2)},{v.register(expr1)}))"
+                               w.add("IS_EQUAL_ON(")
+                               w.add(v.register(expr2))
+                               w.add(",")
+                               w.add(v.register(expr1))
+                               w.add("))")
+                               return
                        end
                else
                        if t2 isa MMTypeNone then
-                               return "TAG_Bool(0)"
+                               w.add("0)")
+                               return
                        else if t2.is_nullable then
-                               return "TAG_Bool(IS_EQUAL_ON({v.register(expr1)},{v.register(expr2)}))"
+                               w.add("IS_EQUAL_ON(")
                        else
-                               return "TAG_Bool(IS_EQUAL_OO({v.register(expr1)},{v.register(expr2)}))"
+                               w.add("IS_EQUAL_OO(")
                        end
                end
+               w.add(v.register(expr1))
+               w.add(",")
+               w.add(v.register(expr2))
+               w.add("))")
        end
 end
 
 redef class INot
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               return "TAG_Bool(!UNTAG_Bool({v.register(expr)}))"
+               if not need_result then return
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("TAG_Bool(!UNTAG_Bool(")
+               w.add(v.register(expr))
+               w.add("))")
        end
 end
 
 redef class IOnce
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
+               v.add_location(location)
                var i = v.new_number
                var res = result.as(not null)
                if res.stype.is_nullable then
@@ -698,12 +1130,14 @@ redef class IOnce
                end
                v.indent
                body.compile_to_c(v)
-               var e = v.register(result.as(not null))
+               var e = v.register(res)
                v.add_instr("once_value_{i} = {e};")
+               v.add_instr("register_static_object(&once_value_{i});")
                if res.stype.is_nullable then v.add_instr("once_bool_{i} = true;")
                v.unindent
-               v.add_instr("} else {e} = once_value_{i};")
-               return e
+               v.add_instr("\} else {e} = once_value_{i};")
+               var w = new_result(v)
+               w.add(e)
        end
 end
 
@@ -712,18 +1146,23 @@ redef class IClosCall
        do
                v.add_location(location)
                var ivar: String
+               var args: Array[String]
                if v.closure then
-                       ivar = "closctx->closurevariable[{v.closures[closure_decl]}]"
+                       ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
+                       args = ["closctx->closure_ctx"]
                else
                        ivar = "CREG[{v.closures[closure_decl]}]"
+                       args = ["closctx_param"]
                end
-               var args = [ivar]
                args.append(v.registers(exprs))
 
-               var s = "(({v.clostypes[closure_decl]})({ivar}->fun))({args.join(", ")})"
-               store_result(v, s)
+               var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
+               var w = new Writer
+               w.add(s)
+               store_result(v, w)
 
-               v.add_instr("if ({ivar}->has_broke) \{")
+               # Intercept escape
+               v.add_instr("if ({args.first}->has_broke) \{")
                v.indent
                var bs = break_seq
                if bs != null then
@@ -733,41 +1172,53 @@ redef class IClosCall
                v.unindent
                v.add_instr("\}")
        end
-
-       redef fun inner_compile_to_c(v) do abort
 end
 
 redef class IHasClos
-       redef fun inner_compile_to_c(v)
+       redef fun compile_to_c(v)
        do
-               var ivar: String
+               if not need_result then return
+               v.add_location(location)
+               var w = new_result(v)
+               w.add("TAG_Bool(")
                if v.closure then
-                       ivar = "closctx->closurevariable[{v.closures[closure_decl]}]"
+                       w.add("closctx->closure_funs[")
+                       w.add(v.closures[closure_decl])
+                       w.add("]")
                else
-                       ivar = "CREG[{v.closures[closure_decl]}]"
+                       w.add("CREG[")
+                       w.add(v.closures[closure_decl])
+                       w.add("]")
                end
-               return "TAG_Bool({ivar} != NULL)"
+               w.add(" != NULL)")
        end
 end
 
-
 redef class IClosureDef
+       # Compile the closure as a separate C function in the visitor out_contexts.
+       # Return a fun_t pointer to the function.
        fun compile_closure(v: I2CCompilerVisitor): String
        do
+               var cv = v.visitor
+
+               # We are now in a closure
                var cfc_old = v.closure
                v.closure = true
+
+               # We are now in a escape boundary
                var lls_old = v.local_labels
                v.local_labels = new HashSet[ISeq]
 
-               var cv = v.visitor
-               var ctx_old = cv.ctx
-               cv.ctx = new CContext
-               cv.out_contexts.add(cv.ctx)
+               # We are now in a new C context
+               var decl_writer_old = cv.decl_writer
+               var writer_old = cv.writer
+               cv.writer = cv.top_writer.sub
+               cv.decl_writer = cv.header_writer.sub
 
+               # Generate the C function
                var cname = "OC_{v.basecname}_{v.new_number}"
-               var args = compile_signature_to_c(v.visitor, cname, null, "struct WBT_ *closctx", null)
-               var ctx_old2 = cv.ctx
-               cv.ctx = new CContext
+               var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
+               cv.decl_writer = cv.writer.sub
 
                var s = compile_inside_to_c(v, args)
                if s == null then
@@ -775,29 +1226,14 @@ redef class IClosureDef
                else
                        v.add_instr("return {s};")
                end
-
-               ctx_old2.append(cv.ctx)
-               cv.ctx = ctx_old2
                v.unindent
-               v.add_instr("}")
-               cv.ctx = ctx_old
+               v.add_instr("\}")
 
+               # Restore things
+               cv.writer = writer_old
+               cv.decl_writer = decl_writer_old
                v.closure = cfc_old
-
-               # Build closure
-               var closcnv = "wbclos{v.new_number}"
-               v.add_decl("struct WBT_ {closcnv};")
-               v.add_instr("{closcnv}.fun = (fun_t){cname};")
-               v.add_instr("{closcnv}.has_broke = NULL;")
-               if cfc_old then
-                       v.add_instr("{closcnv}.variable = closctx->variable;")
-                       v.add_instr("{closcnv}.closurevariable = closctx->closurevariable;")
-               else
-                       v.add_instr("{closcnv}.variable = REG;")
-                       v.add_instr("{closcnv}.closurevariable = CREG;")
-               end
-
                v.local_labels = lls_old
-               return "(&{closcnv})"
+               return "((fun_t){cname})"
        end
 end