gc: add 'help' option to list all available GC
[nit.git] / src / compiling / compiling_icode.nit
index e41e277..8ca8a7a 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,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
 
@@ -224,19 +227,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,34 +263,36 @@ 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}, {std_slots_nb}\};")
-               v.add_instr("trace.prev = tracehead; tracehead = &trace;")
-               v.add_instr("trace.file = LOCATE_{v.visitor.module.name};")
-               v.add_instr("trace.REG_pointer = (val_t **)®")
-
-               # 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
-                       var init_vals = new Buffer
-                       init_vals.append "val_t REG[{std_slots_nb}] = \{ NIT_NULL"
-                       for i in [1..std_slots_nb[ do init_vals.append(", NIT_NULL")
-                       init_vals.append " \};"
-                       v.add_decl(init_vals.to_s)
+                       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 k = 0
                for r in params do
@@ -300,7 +306,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)
@@ -319,7 +325,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
@@ -379,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
@@ -411,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
@@ -426,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
@@ -440,26 +450,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?
@@ -472,15 +494,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;")
@@ -491,7 +506,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
@@ -500,9 +516,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("\}")
@@ -547,6 +565,36 @@ redef class INew
        end
 end
 
+redef class IAllocateInstance
+       redef fun inner_compile_to_c(v)
+       do
+               return "NEW_{stype.local_class.name}()"
+       end
+end
+
+redef class ICheckInstance
+       redef fun inner_compile_to_c(v)
+       do
+               return "CHECKNEW_{stype.local_class.name}({v.register(expr)})"
+       end
+end
+
+redef class IInitAttributes
+       redef fun inner_compile_to_c(v)
+       do
+               return "INIT_ATTRIBUTES__{stype.local_class.name}({v.register(expr)})"
+       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
@@ -701,6 +749,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};")
@@ -713,18 +762,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
@@ -743,7 +795,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
@@ -751,54 +803,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