icode: add IStaticCall
[nit.git] / src / compiling / compiling_icode.nit
index 97514ac..e0be792 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
@@ -134,7 +134,7 @@ 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
@@ -224,19 +224,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)
@@ -259,36 +260,42 @@ 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.module.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]
@@ -296,7 +303,7 @@ redef class IRoutine
                                v.closures[iclosdecl] = i
                                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 +322,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
@@ -330,7 +337,7 @@ redef class IRoutine
        # cv must be in the correct function
        fun compile_to_c(cv: CompilerVisitor, cname: String, args: Array[String]): nullable String
        do
-               optimize
+               optimize(cv.module)
                var v = new I2CCompilerVisitor(cv, self, cname)
                return compile_inside_to_c(v, args)
        end
@@ -436,26 +443,38 @@ 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
 
+               # Compile the real call
                var s = compile_call_to_c(v, args)
                var r: nullable String = s
 
                # Intercept escapes
-               if closcns != null then
+               if closctx != null then
                        var els = v.escaped_labels
                        v.escaped_labels = old_el
                        # Is there possible escapes?
@@ -468,15 +487,8 @@ redef class IAbsCall
                                        r = null
                                        v.add_instr(s + ";")
                                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.add_instr("switch ({closctx}->has_broke) \{")
                                v.indent
                                # No escape occured, continue as usual
                                v.add_instr("case 0: break;")
@@ -487,7 +499,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.add_instr("case {iels.item}: {closctx}->has_broke = 0; goto {v.lab(seq)};")
                                        else
                                                # Forward escape occured: register the escape label
                                                assert v.closure
@@ -496,9 +509,11 @@ 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.add_instr("default: goto {v.lab(v.return_label.as(not null))};")
                                end
                                v.unindent
                                v.add_instr("\}")
@@ -543,6 +558,15 @@ redef class INew
        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")
+               return "{property.cname}({args.join(", ")})"
+       end
+end
+
 redef class INative
        redef fun inner_compile_to_c(v)
        do
@@ -575,16 +599,11 @@ redef class IAbort
                v.add_instr(s.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")
+               s = new Buffer.from("fprintf(stderr, \" (%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}")
+               s.append(")\\n\", LOCATE_{module_location.name}")
                if ll != null then
                        s.append(", {ll.line_start}")
                end
@@ -702,6 +721,7 @@ redef class IOnce
                body.compile_to_c(v)
                var e = v.register(result.as(not null))
                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};")
@@ -714,18 +734,21 @@ 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(", ")})"
+               var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
                store_result(v, s)
 
-               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
@@ -744,7 +767,7 @@ redef class IHasClos
        do
                var ivar: String
                if v.closure then
-                       ivar = "closctx->closurevariable[{v.closures[closure_decl]}]"
+                       ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
                else
                        ivar = "CREG[{v.closures[closure_decl]}]"
                end
@@ -752,54 +775,46 @@ redef class IHasClos
        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
+               # We are now in a new C context
                var ctx_old = cv.ctx
                cv.ctx = new CContext
                cv.out_contexts.add(cv.ctx)
 
+               # 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 args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
                var ctx_old2 = cv.ctx
                cv.ctx = new CContext
-
                var s = compile_inside_to_c(v, args)
                if s == null then
                        v.add_instr("return;")
                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
 
+               # Restore things
+               cv.ctx = ctx_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