nitg & lib: intro `Finalizable` to be called when an object is freed
[nit.git] / src / separate_compiler.nit
index fe9000c..aab5468 100644 (file)
@@ -105,7 +105,9 @@ redef class ModelBuilder
 
                # The main function of the C
                compiler.new_file("{mainmodule.name}.main")
+               compiler.compile_nitni_global_ref_functions
                compiler.compile_main_function
+               compiler.compile_finalizer_function
 
                # compile methods
                for m in mainmodule.in_importation.greaters do
@@ -263,8 +265,8 @@ class SeparateCompiler
                var rta = runtime_type_analysis
 
                # Layouts
-               var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
                var poset = mainmodule.flatten_mclass_hierarchy
+               var mclasses = new HashSet[MClass].from(poset)
                var colorer = new POSetColorer[MClass]
                colorer.colorize(poset)
 
@@ -345,45 +347,12 @@ class SeparateCompiler
                var tables = new HashMap[MClass, Array[nullable MPropDef]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
-                       var supercalls = new List[MMethodDef]
+                       tables[mclass] = table
 
-                       # first, fill table from parents by reverse linearization order
-                       var parents = new Array[MClass]
-                       if mainmodule.flatten_mclass_hierarchy.has(mclass) then
-                               parents = mclass.in_hierarchy(mainmodule).greaters.to_a
-                               self.mainmodule.linearize_mclasses(parents)
-                       end
+                       var mproperties = self.mainmodule.properties(mclass)
+                       var mtype = mclass.intro.bound_mtype
 
-                       for parent in parents do
-                               if parent == mclass then continue
-                               for mproperty in self.mainmodule.properties(parent) do
-                                       if not mproperty isa MMethod then continue
-                                       if not method_colors.has_key(mproperty) then continue
-                                       var color = method_colors[mproperty]
-                                       if table.length <= color then
-                                               for i in [table.length .. color[ do
-                                                       table[i] = null
-                                               end
-                                       end
-                                       for mpropdef in mproperty.mpropdefs do
-                                               if mpropdef.mclassdef.mclass == parent then
-                                                       table[color] = mpropdef
-                                               end
-                                       end
-                               end
-
-                               # lookup for super calls in super classes
-                               for mmethoddef in super_calls do
-                                       for mclassdef in parent.mclassdefs do
-                                               if mclassdef.mpropdefs.has(mmethoddef) then
-                                                       supercalls.add(mmethoddef)
-                                               end
-                                       end
-                               end
-                       end
-
-                       # then override with local properties
-                       for mproperty in self.mainmodule.properties(mclass) do
+                       for mproperty in mproperties do
                                if not mproperty isa MMethod then continue
                                if not method_colors.has_key(mproperty) then continue
                                var color = method_colors[mproperty]
@@ -392,33 +361,22 @@ class SeparateCompiler
                                                table[i] = null
                                        end
                                end
-                               for mpropdef in mproperty.mpropdefs do
-                                       if mpropdef.mclassdef.mclass == mclass then
-                                               table[color] = mpropdef
-                                       end
-                               end
+                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
                        end
 
-                       # lookup for super calls in local class
-                       for mmethoddef in super_calls do
-                               for mclassdef in mclass.mclassdefs do
-                                       if mclassdef.mpropdefs.has(mmethoddef) then
-                                               supercalls.add(mmethoddef)
-                                       end
-                               end
-                       end
-                       # insert super calls in table according to receiver
-                       for supercall in supercalls do
+                       for supercall in super_calls do
+                               if not mtype.collect_mclassdefs(mainmodule).has(supercall.mclassdef) then continue
+
                                var color = method_colors[supercall]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
                                        end
                                end
-                               var mmethoddef = supercall.lookup_next_definition(self.mainmodule, mclass.intro.bound_mtype)
+                               var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype)
                                table[color] = mmethoddef
                        end
-                       tables[mclass] = table
+
                end
                return tables
        end
@@ -427,46 +385,22 @@ class SeparateCompiler
                var tables = new HashMap[MClass, Array[nullable MPropDef]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
-                       # first, fill table from parents by reverse linearization order
-                       var parents = new Array[MClass]
-                       if mainmodule.flatten_mclass_hierarchy.has(mclass) then
-                               parents = mclass.in_hierarchy(mainmodule).greaters.to_a
-                               self.mainmodule.linearize_mclasses(parents)
-                       end
-                       for parent in parents do
-                               if parent == mclass then continue
-                               for mproperty in self.mainmodule.properties(parent) do
-                                       if not mproperty isa MAttribute then continue
-                                       var color = attr_colors[mproperty]
-                                       if table.length <= color then
-                                               for i in [table.length .. color[ do
-                                                       table[i] = null
-                                               end
-                                       end
-                                       for mpropdef in mproperty.mpropdefs do
-                                               if mpropdef.mclassdef.mclass == parent then
-                                                       table[color] = mpropdef
-                                               end
-                                       end
-                               end
-                       end
+                       tables[mclass] = table
 
-                       # then override with local properties
-                       for mproperty in self.mainmodule.properties(mclass) do
+                       var mproperties = self.mainmodule.properties(mclass)
+                       var mtype = mclass.intro.bound_mtype
+
+                       for mproperty in mproperties do
                                if not mproperty isa MAttribute then continue
+                               if not attr_colors.has_key(mproperty) then continue
                                var color = attr_colors[mproperty]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
                                        end
                                end
-                               for mpropdef in mproperty.mpropdefs do
-                                       if mpropdef.mclassdef.mclass == mclass then
-                                               table[color] = mpropdef
-                                       end
-                               end
+                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
                        end
-                       tables[mclass] = table
                end
                return tables
        end
@@ -657,8 +591,7 @@ class SeparateCompiler
 
                # resolution table (for receiver)
                if is_live then
-                       var mclass_type = mtype
-                       if mclass_type isa MNullableType then mclass_type = mclass_type.mtype
+                       var mclass_type = mtype.as_notnullable
                        assert mclass_type isa MClassType
                        if resolution_tables[mclass_type].is_empty then
                                v.add_decl("NULL, /*NO RESOLUTIONS*/")
@@ -691,12 +624,7 @@ class SeparateCompiler
 
        fun compile_type_resolution_table(mtype: MType) do
 
-               var mclass_type: MClassType
-               if mtype isa MNullableType then
-                       mclass_type = mtype.mtype.as(MClassType)
-               else
-                       mclass_type = mtype.as(MClassType)
-               end
+               var mclass_type = mtype.as_notnullable.as(MClassType)
 
                # extern const struct resolution_table_X resolution_table_X
                self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
@@ -838,6 +766,7 @@ class SeparateCompiler
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
                        self.generate_init_attr(v, res, mtype)
+                       v.set_finalizer res
                        v.add("return {res};")
                end
                v.add("\}")
@@ -851,7 +780,7 @@ class SeparateCompiler
                v.add_abort("type null")
                v.add("\}")
                v.add("if({t}->table_size == 0) \{")
-               v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", {t}->name);")
+               v.add("PRINT_ERROR(\"Insantiation of a dead type: %s\\n\", {t}->name);")
                v.add_abort("type dead")
                v.add("\}")
        end
@@ -938,9 +867,17 @@ class SeparateCompiler
 
        redef fun compile_nitni_structs
        do
-               self.header.add_decl("struct nitni_instance \{struct instance *value;\};")
+               self.header.add_decl """
+struct nitni_instance \{
+       struct nitni_instance *next,
+               *prev; /* adjacent global references in global list */
+       int count; /* number of time this global reference has been marked */
+       struct instance *value;
+\};
+"""
+               super
        end
-       
+
        redef fun finalize_ffi_for_module(mmodule)
        do
                var old_module = self.mainmodule
@@ -985,19 +922,21 @@ class SeparateCompilerVisitor
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(valtype) then
                                self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
-                               self.add("printf(\"Dead code executed!\\n\"); show_backtrace(1);")
+                               self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")
                        self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
                        return res
-               else if value.mtype.ctype == "void*" and mtype.ctype == "void*" then
+               else if (value.mtype.ctype == "void*" and mtype.ctype == "void*") or
+                       (value.mtype.ctype == "char*" and mtype.ctype == "void*") or
+                       (value.mtype.ctype == "void*" and mtype.ctype == "char*") then
                        return value
                else
                        # Bad things will appen!
                        var res = self.new_var(mtype)
                        self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
-                       self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
+                       self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
                        return res
                end
        end
@@ -1388,7 +1327,7 @@ class SeparateCompilerVisitor
                self.require_declaration(mtype.const_color)
                var col = mtype.const_color
                self.add("if({col} == -1) \{")
-               self.add("fprintf(stderr, \"Resolution of a dead open type: %s\\n\", \"{mtype.to_s.escape_to_c}\");")
+               self.add("PRINT_ERROR(\"Resolution of a dead open type: %s\\n\", \"{mtype.to_s.escape_to_c}\");")
                self.add_abort("open type dead")
                self.add("\}")
        end
@@ -1401,7 +1340,7 @@ class SeparateCompilerVisitor
                add_abort("cast type null")
                add("\}")
                add("if({t}->id == -1 || {t}->color == -1) \{")
-               add("fprintf(stderr, \"Try to cast on a dead cast type: %s\\n\", {t}->name);")
+               add("PRINT_ERROR(\"Try to cast on a dead cast type: %s\\n\", {t}->name);")
                add_abort("cast type dead")
                add("\}")
        end
@@ -1488,7 +1427,7 @@ class SeparateCompilerVisitor
                                self.add("count_type_test_resolved_{tag}++;")
                        end
                else
-                       self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
+                       self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
                end
 
                # check color is in table
@@ -1642,8 +1581,7 @@ class SeparateCompilerVisitor
 
        fun can_be_primitive(value: RuntimeVariable): Bool
        do
-               var t = value.mcasttype
-               if t isa MNullableType then t = t.mtype
+               var t = value.mcasttype.as_notnullable
                if not t isa MClassType then return false
                var k = t.mclass.kind
                return k == interface_kind or t.ctype != "val*"
@@ -1673,7 +1611,7 @@ class SeparateCompilerVisitor
                return res
        end
 
-       fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
+       redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
        do
                var mtype = self.get_class("NativeArray").get_mtype([elttype])
                self.require_declaration("NEW_{mtype.mclass.c_name}")