sep_comp: improve deadness management in compile_class_to_c
[nit.git] / src / compiler / separate_compiler.nit
index 15da8c1..44bb68f 100644 (file)
@@ -59,6 +59,8 @@ redef class ToolContext
        var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
        # --tables-metrics
        var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
        var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
        # --tables-metrics
        var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
+       # --type-poset
+       var opt_type_poset = new OptionBool("Build a poset of types to create more condensed tables.", "--type-poset")
 
        redef init
        do
 
        redef init
        do
@@ -72,6 +74,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
                self.option_context.add_option(self.opt_colo_dead_methods)
                self.option_context.add_option(self.opt_tables_metrics)
                self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
                self.option_context.add_option(self.opt_colo_dead_methods)
                self.option_context.add_option(self.opt_tables_metrics)
+               self.option_context.add_option(self.opt_type_poset)
        end
 
        redef fun process_options(args)
        end
 
        redef fun process_options(args)
@@ -146,8 +149,6 @@ class SeparateCompiler
        private var type_ids: Map[MType, Int] is noinit
        private var type_colors: Map[MType, Int] is noinit
        private var opentype_colors: Map[MType, Int] is noinit
        private var type_ids: Map[MType, Int] is noinit
        private var type_colors: Map[MType, Int] is noinit
        private var opentype_colors: Map[MType, Int] is noinit
-       protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
-       protected var attr_colors: Map[MAttribute, Int] is noinit
 
        init do
                var file = new_file("nit.common")
 
        init do
                var file = new_file("nit.common")
@@ -251,7 +252,7 @@ class SeparateCompiler
        do
                # Collect all bas box class
                # FIXME: this is not completely fine with a separate compilation scheme
        do
                # Collect all bas box class
                # FIXME: this is not completely fine with a separate compilation scheme
-               for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
+               for classname in ["Int", "Bool", "Byte", "Char", "Float", "NativeString", "Pointer"] do
                        var classes = self.mainmodule.model.get_mclasses_by_name(classname)
                        if classes == null then continue
                        assert classes.length == 1 else print classes.join(", ")
                        var classes = self.mainmodule.model.get_mclasses_by_name(classname)
                        if classes == null then continue
                        assert classes.length == 1 else print classes.join(", ")
@@ -305,170 +306,147 @@ class SeparateCompiler
 
        private var color_consts_done = new HashSet[Object]
 
 
        private var color_consts_done = new HashSet[Object]
 
+       # The conflict graph of classes used for coloration
+       var class_conflict_graph: POSetConflictGraph[MClass] is noinit
+
        # colorize classe properties
        fun do_property_coloring do
 
                var rta = runtime_type_analysis
 
        # colorize classe properties
        fun do_property_coloring do
 
                var rta = runtime_type_analysis
 
-               # Layouts
-               var poset = mainmodule.flatten_mclass_hierarchy
-               var mclasses = new HashSet[MClass].from(poset)
-               var colorer = new POSetColorer[MClass]
-               colorer.colorize(poset)
-
-               # The dead methods, still need to provide a dead color symbol
-               var dead_methods = new Array[MMethod]
+               # Class graph
+               var mclasses = mainmodule.flatten_mclass_hierarchy
+               class_conflict_graph = mclasses.to_conflict_graph
 
 
-               # lookup properties to build layout with
+               # Prepare to collect elements to color and build layout with
                var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
                var mattributes = new HashMap[MClass, Set[MAttribute]]
                var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
                var mattributes = new HashMap[MClass, Set[MAttribute]]
+
+               # The dead methods and super-call, still need to provide a dead color symbol
+               var dead_methods = new Array[PropertyLayoutElement]
+
                for mclass in mclasses do
                        mmethods[mclass] = new HashSet[PropertyLayoutElement]
                        mattributes[mclass] = new HashSet[MAttribute]
                for mclass in mclasses do
                        mmethods[mclass] = new HashSet[PropertyLayoutElement]
                        mattributes[mclass] = new HashSet[MAttribute]
-                       for mprop in self.mainmodule.properties(mclass) do
-                               if mprop isa MMethod then
-                                       if not modelbuilder.toolcontext.opt_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
-                                               dead_methods.add(mprop)
-                                               continue
-                                       end
-                                       mmethods[mclass].add(mprop)
-                               else if mprop isa MAttribute then
-                                       mattributes[mclass].add(mprop)
-                               end
+               end
+
+               # Pre-collect known live things
+               if rta != null then
+                       for m in rta.live_methods do
+                               mmethods[m.intro_mclassdef.mclass].add m
+                       end
+                       for m in rta.live_super_sends do
+                               var mclass = m.mclassdef.mclass
+                               mmethods[mclass].add m
                        end
                end
 
                        end
                end
 
-               # Collect all super calls (dead or not)
-               var all_super_calls = new HashSet[MMethodDef]
-               for mmodule in self.mainmodule.in_importation.greaters do
-                       for mclassdef in mmodule.mclassdefs do
-                               for mpropdef in mclassdef.mpropdefs do
-                                       if not mpropdef isa MMethodDef then continue
-                                       if mpropdef.has_supercall then
-                                               all_super_calls.add(mpropdef)
+               for m in mainmodule.in_importation.greaters do for cd in m.mclassdefs do
+                       var mclass = cd.mclass
+                       # Collect methods ad attributes
+                       for p in cd.intro_mproperties do
+                               if p isa MMethod then
+                                       if rta == null then
+                                               mmethods[mclass].add p
+                                       else if not rta.live_methods.has(p) then
+                                               dead_methods.add p
                                        end
                                        end
+                               else if p isa MAttribute then
+                                       mattributes[mclass].add p
                                end
                        end
                                end
                        end
-               end
 
 
-               # lookup super calls and add it to the list of mmethods to build layout with
-               var super_calls
-               if rta != null then
-                       super_calls = rta.live_super_sends
-               else
-                       super_calls = all_super_calls
-               end
-
-               for mmethoddef in super_calls do
-                       var mclass = mmethoddef.mclassdef.mclass
-                       mmethods[mclass].add(mmethoddef)
-                       for descendant in mclass.in_hierarchy(self.mainmodule).smallers do
-                               mmethods[descendant].add(mmethoddef)
+                       # Collect all super calls (dead or not)
+                       for mpropdef in cd.mpropdefs do
+                               if not mpropdef isa MMethodDef then continue
+                               if mpropdef.has_supercall then
+                                       if rta == null then
+                                               mmethods[mclass].add mpropdef
+                                       else if not rta.live_super_sends.has(mpropdef) then
+                                               dead_methods.add mpropdef
+                                       end
+                               end
                        end
                end
 
                # methods coloration
                        end
                end
 
                # methods coloration
-               var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts)
-               method_colors = meth_colorer.colorize(mmethods)
-               method_tables = build_method_tables(mclasses, super_calls)
+               var meth_colorer = new POSetGroupColorer[MClass, PropertyLayoutElement](class_conflict_graph, mmethods)
+               var method_colors = meth_colorer.colors
                compile_color_consts(method_colors)
 
                compile_color_consts(method_colors)
 
-               # attribute null color to dead methods and supercalls
-               for mproperty in dead_methods do
-                       compile_color_const(new_visitor, mproperty, -1)
-               end
-               for mpropdef in all_super_calls do
-                       if super_calls.has(mpropdef) then continue
-                       compile_color_const(new_visitor, mpropdef, -1)
-               end
+               # give null color to dead methods and supercalls
+               for mproperty in dead_methods do compile_color_const(new_visitor, mproperty, -1)
 
 
-               # attributes coloration
-               var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts)
-               attr_colors = attr_colorer.colorize(mattributes)
-               attr_tables = build_attr_tables(mclasses)
+               # attribute coloration
+               var attr_colorer = new POSetGroupColorer[MClass, MAttribute](class_conflict_graph, mattributes)
+               var attr_colors = attr_colorer.colors#ize(poset, mattributes)
                compile_color_consts(attr_colors)
                compile_color_consts(attr_colors)
-       end
 
 
-       fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do
-               var tables = new HashMap[MClass, Array[nullable MPropDef]]
+               # Build method and attribute tables
+               method_tables = new HashMap[MClass, Array[nullable MPropDef]]
+               attr_tables = new HashMap[MClass, Array[nullable MProperty]]
                for mclass in mclasses do
                for mclass in mclasses do
-                       var table = new Array[nullable MPropDef]
-                       tables[mclass] = table
+                       if not mclass.has_new_factory and (mclass.kind == abstract_kind or mclass.kind == interface_kind) then continue
+                       if rta != null and not rta.live_classes.has(mclass) then continue
 
 
-                       var mproperties = self.mainmodule.properties(mclass)
                        var mtype = mclass.intro.bound_mtype
 
                        var mtype = mclass.intro.bound_mtype
 
-                       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]
-                               if table.length <= color then
-                                       for i in [table.length .. color[ do
-                                               table[i] = null
-                                       end
-                               end
-                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
-                       end
-
-                       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
+                       # Resolve elements in the layout to get the final table
+                       var meth_layout = meth_colorer.build_layout(mclass)
+                       var meth_table = new Array[nullable MPropDef].with_capacity(meth_layout.length)
+                       method_tables[mclass] = meth_table
+                       for e in meth_layout do
+                               if e == null then
+                                       meth_table.add null
+                               else if e isa MMethod then
+                                       # Standard method call of `e`
+                                       meth_table.add e.lookup_first_definition(mainmodule, mtype)
+                               else if e isa MMethodDef then
+                                       # Super-call in the methoddef `e`
+                                       meth_table.add e.lookup_next_definition(mainmodule, mtype)
+                               else
+                                       abort
                                end
                                end
-                               var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype)
-                               table[color] = mmethoddef
                        end
 
                        end
 
+                       # Do not need to resolve attributes as only the position is used
+                       attr_tables[mclass] = attr_colorer.build_layout(mclass)
                end
                end
-               return tables
-       end
 
 
-       fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
-               var tables = new HashMap[MClass, Array[nullable MPropDef]]
-               for mclass in mclasses do
-                       var table = new Array[nullable MPropDef]
-                       tables[mclass] = table
-
-                       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
-                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
-                       end
-               end
-               return tables
        end
 
        # colorize live types of the program
        end
 
        # colorize live types of the program
-       private fun do_type_coloring: POSet[MType] do
+       private fun do_type_coloring: Collection[MType] do
                # Collect types to colorize
                var live_types = runtime_type_analysis.live_types
                var live_cast_types = runtime_type_analysis.live_cast_types
 
                # Collect types to colorize
                var live_types = runtime_type_analysis.live_types
                var live_cast_types = runtime_type_analysis.live_cast_types
 
-               # Compute colors
-               var poset = poset_from_mtypes(live_types, live_cast_types)
-               var colorer = new POSetColorer[MType]
-               colorer.colorize(poset)
-               type_ids = colorer.ids
-               type_colors = colorer.colors
-               type_tables = build_type_tables(poset)
+               var res = new HashSet[MType]
+               res.add_all live_types
+               res.add_all live_cast_types
+
+               if modelbuilder.toolcontext.opt_type_poset.value then
+                       # Compute colors with a type poset
+                       var poset = poset_from_mtypes(live_types, live_cast_types)
+                       var colorer = new POSetColorer[MType]
+                       colorer.colorize(poset)
+                       type_ids = colorer.ids
+                       type_colors = colorer.colors
+                       type_tables = build_type_tables(poset)
+               else
+                       # Compute colors using the class poset
+                       # Faster to compute but the number of holes can degenerate
+                       compute_type_test_layouts(live_types, live_cast_types)
+
+                       type_ids = new HashMap[MType, Int]
+                       for x in res do type_ids[x] = type_ids.length + 1
+               end
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
                self.compute_resolution_tables(live_types)
 
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
                self.compute_resolution_tables(live_types)
 
-               return poset
+               return res
        end
 
        private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
        end
 
        private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
@@ -480,14 +458,14 @@ class SeparateCompiler
 
                var mtypes_by_class = new MultiHashMap[MClass, MType]
                for e in mtypes do
 
                var mtypes_by_class = new MultiHashMap[MClass, MType]
                for e in mtypes do
-                       var c = e.as_notnullable.as(MClassType).mclass
+                       var c = e.undecorate.as(MClassType).mclass
                        mtypes_by_class[c].add(e)
                        poset.add_node(e)
                end
 
                var casttypes_by_class = new MultiHashMap[MClass, MType]
                for e in cast_types do
                        mtypes_by_class[c].add(e)
                        poset.add_node(e)
                end
 
                var casttypes_by_class = new MultiHashMap[MClass, MType]
                for e in cast_types do
-                       var c = e.as_notnullable.as(MClassType).mclass
+                       var c = e.undecorate.as(MClassType).mclass
                        casttypes_by_class[c].add(e)
                        poset.add_node(e)
                end
                        casttypes_by_class[c].add(e)
                        poset.add_node(e)
                end
@@ -527,6 +505,48 @@ class SeparateCompiler
                return tables
        end
 
                return tables
        end
 
+
+       private fun compute_type_test_layouts(mtypes: Set[MClassType], cast_types: Set[MType]) do
+               # Group cast_type by their classes
+               var bucklets = new HashMap[MClass, Set[MType]]
+               for e in cast_types do
+                       var c = e.undecorate.as(MClassType).mclass
+                       if not bucklets.has_key(c) then
+                               bucklets[c] = new HashSet[MType]
+                       end
+                       bucklets[c].add(e)
+               end
+
+               # Colorize cast_types from the class hierarchy
+               var colorer = new POSetGroupColorer[MClass, MType](class_conflict_graph, bucklets)
+               type_colors = colorer.colors
+
+               var layouts = new HashMap[MClass, Array[nullable MType]]
+               for c in runtime_type_analysis.live_classes do
+                       layouts[c] = colorer.build_layout(c)
+               end
+
+               # Build the table for each live type
+               for t in mtypes do
+                       # A live type use the layout of its class
+                       var c = t.mclass
+                       var layout = layouts[c]
+                       var table = new Array[nullable MType].with_capacity(layout.length)
+                       type_tables[t] = table
+
+                       # For each potential super-type in the layout
+                       for sup in layout do
+                               if sup == null then
+                                       table.add null
+                               else if t.is_subtype(mainmodule, null, sup) then
+                                       table.add sup
+                               else
+                                       table.add null
+                               end
+                       end
+               end
+       end
+
        # resolution_tables is used to perform a type resolution at runtime in O(1)
        private fun compute_resolution_tables(mtypes: Set[MType]) do
                # During the visit of the body of classes, live_unresolved_types are collected
        # resolution_tables is used to perform a type resolution at runtime in O(1)
        private fun compute_resolution_tables(mtypes: Set[MType]) do
                # During the visit of the body of classes, live_unresolved_types are collected
@@ -534,21 +554,26 @@ class SeparateCompiler
                # Collect all live_unresolved_types (visited in the body of classes)
 
                # Determinate fo each livetype what are its possible requested anchored types
                # Collect all live_unresolved_types (visited in the body of classes)
 
                # Determinate fo each livetype what are its possible requested anchored types
-               var mtype2unresolved = new HashMap[MClassType, Set[MType]]
+               var mtype2unresolved = new HashMap[MClass, Set[MType]]
                for mtype in self.runtime_type_analysis.live_types do
                for mtype in self.runtime_type_analysis.live_types do
-                       var set = new HashSet[MType]
+                       var mclass = mtype.mclass
+                       var set = mtype2unresolved.get_or_null(mclass)
+                       if set == null then
+                               set = new HashSet[MType]
+                               mtype2unresolved[mclass] = set
+                       end
                        for cd in mtype.collect_mclassdefs(self.mainmodule) do
                                if self.live_unresolved_types.has_key(cd) then
                                        set.add_all(self.live_unresolved_types[cd])
                                end
                        end
                        for cd in mtype.collect_mclassdefs(self.mainmodule) do
                                if self.live_unresolved_types.has_key(cd) then
                                        set.add_all(self.live_unresolved_types[cd])
                                end
                        end
-                       mtype2unresolved[mtype] = set
                end
 
                # Compute the table layout with the prefered method
                end
 
                # Compute the table layout with the prefered method
-               var colorer = new BucketsColorer[MType, MType]
+               var colorer = new BucketsColorer[MClass, MType]
+
                opentype_colors = colorer.colorize(mtype2unresolved)
                opentype_colors = colorer.colorize(mtype2unresolved)
-               resolution_tables = self.build_resolution_tables(mtype2unresolved)
+               resolution_tables = self.build_resolution_tables(self.runtime_type_analysis.live_types, mtype2unresolved)
 
                # Compile a C constant for each collected unresolved type.
                # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
 
                # Compile a C constant for each collected unresolved type.
                # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
@@ -573,9 +598,10 @@ class SeparateCompiler
                #print ""
        end
 
                #print ""
        end
 
-       fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+       fun build_resolution_tables(elements: Set[MClassType], map: Map[MClass, Set[MType]]): Map[MClassType, Array[nullable MType]] do
                var tables = new HashMap[MClassType, Array[nullable MType]]
                var tables = new HashMap[MClassType, Array[nullable MType]]
-               for mclasstype, mtypes in elements do
+               for mclasstype in elements do
+                       var mtypes = map[mclasstype.mclass]
                        var table = new Array[nullable MType]
                        for mtype in mtypes do
                                var color = opentype_colors[mtype]
                        var table = new Array[nullable MType]
                        for mtype in mtypes do
                                var color = opentype_colors[mtype]
@@ -599,6 +625,7 @@ class SeparateCompiler
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
+                               if pd.msignature == null then continue # Skip broken method
                                var rta = runtime_type_analysis
                                if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
                                #print "compile {pd} @ {cd} @ {mmodule}"
                                var rta = runtime_type_analysis
                                if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
                                #print "compile {pd} @ {cd} @ {mmodule}"
@@ -716,7 +743,7 @@ class SeparateCompiler
 
                # resolution table (for receiver)
                if is_live then
 
                # resolution table (for receiver)
                if is_live then
-                       var mclass_type = mtype.as_notnullable
+                       var mclass_type = mtype.undecorate
                        assert mclass_type isa MClassType
                        if resolution_tables[mclass_type].is_empty then
                                v.add_decl("NULL, /*NO RESOLUTIONS*/")
                        assert mclass_type isa MClassType
                        if resolution_tables[mclass_type].is_empty then
                                v.add_decl("NULL, /*NO RESOLUTIONS*/")
@@ -742,14 +769,15 @@ class SeparateCompiler
                        end
                        v.add_decl("\},")
                else
                        end
                        v.add_decl("\},")
                else
-                       v.add_decl("0, \{\}, /*DEAD TYPE*/")
+                       # Use -1 to indicate dead type, the info is used by --hardening
+                       v.add_decl("-1, \{\}, /*DEAD TYPE*/")
                end
                v.add_decl("\};")
        end
 
        fun compile_type_resolution_table(mtype: MType) do
 
                end
                v.add_decl("\};")
        end
 
        fun compile_type_resolution_table(mtype: MType) do
 
-               var mclass_type = mtype.as_notnullable.as(MClassType)
+               var mclass_type = mtype.undecorate.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};")
 
                # 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};")
@@ -788,22 +816,24 @@ class SeparateCompiler
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
-               var vft = self.method_tables[mclass]
-               var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
                var rta = runtime_type_analysis
                var v = new_visitor
 
                var rta = runtime_type_analysis
-               var is_dead = rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" and mclass.name != "Pointer"
+               var is_dead = rta != null and not rta.live_classes.has(mclass)
+               # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so
+               # in order to compile and link correctly the C code, these symbols should be declared and defined.
+               var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind
 
 
-               v.add_decl("/* runtime class {c_name} */")
+               v.add_decl("/* runtime class {c_name}: {mclass.full_name} (dead={is_dead}; need_corpse={need_corpse})*/")
 
                # Build class vft
 
                # Build class vft
-               if not is_dead then
+               if not is_dead or need_corpse then
                        self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};")
                        v.add_decl("const struct class class_{c_name} = \{")
                        v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
                        v.add_decl("\{")
                        self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};")
                        v.add_decl("const struct class class_{c_name} = \{")
                        v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
                        v.add_decl("\{")
-                       for i in [0 .. vft.length[ do
+                       var vft = self.method_tables.get_or_null(mclass)
+                       if vft != null then for i in [0 .. vft.length[ do
                                var mpropdef = vft[i]
                                if mpropdef == null then
                                        v.add_decl("NULL, /* empty */")
                                var mpropdef = vft[i]
                                if mpropdef == null then
                                        v.add_decl("NULL, /* empty */")
@@ -834,7 +864,8 @@ class SeparateCompiler
                        self.header.add_decl("{mtype.ctype_extern} value;")
                        self.header.add_decl("\};")
 
                        self.header.add_decl("{mtype.ctype_extern} value;")
                        self.header.add_decl("\};")
 
-                       if not rta.live_types.has(mtype) and mtype.mclass.name != "Pointer" then return
+                       # Pointer is needed by extern types, live or not
+                       if is_dead and mtype.mclass.name != "Pointer" then return
 
                        #Build BOX
                        self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
 
                        #Build BOX
                        self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
@@ -850,6 +881,7 @@ class SeparateCompiler
                        v.add("return (val*)res;")
                        v.add("\}")
 
                        v.add("return (val*)res;")
                        v.add("\}")
 
+                       # A Pointer class also need its constructor
                        if mtype.mclass.name != "Pointer" then return
 
                        v = new_visitor
                        if mtype.mclass.name != "Pointer" then return
 
                        v = new_visitor
@@ -904,7 +936,7 @@ class SeparateCompiler
                        var pointer_type = mainmodule.pointer_type
 
                        self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
                        var pointer_type = mainmodule.pointer_type
 
                        self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
-                       v.add_decl("/* allocate {mtype} */")
+                       v.add_decl("/* allocate extern {mtype} */")
                        v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
                        if is_dead then
                                v.add_abort("{mclass} is DEAD")
                        v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
                        if is_dead then
                                v.add_abort("{mclass} is DEAD")
@@ -932,13 +964,20 @@ class SeparateCompiler
                else
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
                else
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
-                       v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       var attrs = self.attr_tables.get_or_null(mclass)
+                       if attrs == null then
+                               v.add("{res} = nit_alloc(sizeof(struct instance));")
+                       else
+                               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       end
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       self.generate_init_attr(v, res, mtype)
-                       v.set_finalizer res
+                       if attrs != null then
+                               self.generate_init_attr(v, res, mtype)
+                               v.set_finalizer res
+                       end
                        v.add("return {res};")
                end
                v.add("\}")
                        v.add("return {res};")
                end
                v.add("\}")
@@ -1004,7 +1043,7 @@ class SeparateCompiler
                v.add("if({t} == NULL) \{")
                v.add_abort("type null")
                v.add("\}")
                v.add("if({t} == NULL) \{")
                v.add_abort("type null")
                v.add("\}")
-               v.add("if({t}->table_size == 0) \{")
+               v.add("if({t}->table_size < 0) \{")
                v.add("PRINT_ERROR(\"Insantiation of a dead type: %s\\n\", {t}->name);")
                v.add_abort("type dead")
                v.add("\}")
                v.add("PRINT_ERROR(\"Insantiation of a dead type: %s\\n\", {t}->name);")
                v.add_abort("type dead")
                v.add("\}")
@@ -1017,7 +1056,7 @@ class SeparateCompiler
        private var type_tables: Map[MType, Array[nullable MType]] = new HashMap[MType, Array[nullable MType]]
        private var resolution_tables: Map[MClassType, Array[nullable MType]] = new HashMap[MClassType, Array[nullable MType]]
        protected var method_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
        private var type_tables: Map[MType, Array[nullable MType]] = new HashMap[MType, Array[nullable MType]]
        private var resolution_tables: Map[MClassType, Array[nullable MType]] = new HashMap[MClassType, Array[nullable MType]]
        protected var method_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
-       protected var attr_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
+       protected var attr_tables: Map[MClass, Array[nullable MProperty]] = new HashMap[MClass, Array[nullable MProperty]]
 
        redef fun display_stats
        do
 
        redef fun display_stats
        do
@@ -1160,7 +1199,7 @@ class SeparateCompilerVisitor
                                if mtype.name == "Int" then
                                        return self.new_expr("(long)({value})>>2", mtype)
                                else if mtype.name == "Char" then
                                if mtype.name == "Int" then
                                        return self.new_expr("(long)({value})>>2", mtype)
                                else if mtype.name == "Char" then
-                                       return self.new_expr("(char)((long)({value})>>2)", mtype)
+                                       return self.new_expr("(uint32_t)((long)({value})>>2)", mtype)
                                else if mtype.name == "Bool" then
                                        return self.new_expr("(short int)((long)({value})>>2)", mtype)
                                else
                                else if mtype.name == "Bool" then
                                        return self.new_expr("(short int)((long)({value})>>2)", mtype)
                                else
@@ -1404,13 +1443,14 @@ class SeparateCompilerVisitor
                if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;")
 
                assert arguments.length == mmethod.intro.msignature.arity + 1 else debug("Invalid arity for {mmethod}. {arguments.length} arguments given.")
                if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;")
 
                assert arguments.length == mmethod.intro.msignature.arity + 1 else debug("Invalid arity for {mmethod}. {arguments.length} arguments given.")
-               var recv = arguments.first
 
                var res0 = before_send(mmethod, arguments)
 
                var runtime_function = mmethod.intro.virtual_runtime_function
                var msignature = runtime_function.called_signature
 
 
                var res0 = before_send(mmethod, arguments)
 
                var runtime_function = mmethod.intro.virtual_runtime_function
                var msignature = runtime_function.called_signature
 
+               adapt_signature(mmethod.intro, arguments)
+
                var res: nullable RuntimeVariable
                var ret = msignature.return_mtype
                if ret == null then
                var res: nullable RuntimeVariable
                var ret = msignature.return_mtype
                if ret == null then
@@ -1419,18 +1459,7 @@ class SeparateCompilerVisitor
                        res = self.new_var(ret)
                end
 
                        res = self.new_var(ret)
                end
 
-               var ss = new FlatBuffer
-
-               ss.append("{recv}")
-               for i in [0..msignature.arity[ do
-                       var a = arguments[i+1]
-                       var t = msignature.mparameters[i].mtype
-                       if i == msignature.vararg_rank then
-                               t = arguments[i+1].mcasttype
-                       end
-                       a = self.autobox(a, t)
-                       ss.append(", {a}")
-               end
+               var ss = arguments.join(", ")
 
                var const_color = mentity.const_color
                var ress
 
                var const_color = mentity.const_color
                var ress
@@ -1580,7 +1609,7 @@ class SeparateCompilerVisitor
                        self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
                else
 
                        self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
                else
 
-                       if not mtype.is_c_primitive then
+                       if not mtype.is_c_primitive and not mtype.is_tagged then
                                self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
                        else
                                self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
                                self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
                        else
                                self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
@@ -1974,7 +2003,7 @@ class SeparateCompilerVisitor
 
        fun can_be_primitive(value: RuntimeVariable): Bool
        do
 
        fun can_be_primitive(value: RuntimeVariable): Bool
        do
-               var t = value.mcasttype.as_notnullable
+               var t = value.mcasttype.undecorate
                if not t isa MClassType then return false
                var k = t.mclass.kind
                return k == interface_kind or t.is_c_primitive
                if not t isa MClassType then return false
                var k = t.mclass.kind
                return k == interface_kind or t.is_c_primitive
@@ -2010,6 +2039,7 @@ class SeparateCompilerVisitor
                self.require_declaration("NEW_{mtype.mclass.c_name}")
                assert mtype isa MGenericType
                var compiler = self.compiler
                self.require_declaration("NEW_{mtype.mclass.c_name}")
                assert mtype isa MGenericType
                var compiler = self.compiler
+               length = autobox(length, compiler.mainmodule.int_type)
                if mtype.need_anchor then
                        hardening_live_open_type(mtype)
                        link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
                if mtype.need_anchor then
                        hardening_live_open_type(mtype)
                        link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
@@ -2047,6 +2077,22 @@ class SeparateCompilerVisitor
                end
        end
 
                end
        end
 
+       redef fun native_array_get(nat, i)
+       do
+               var nclass = mmodule.native_array_class
+               var recv = "((struct instance_{nclass.c_name}*){nat})->values"
+               # Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing
+               var res = self.new_expr("{recv}[{i}]", compiler.mainmodule.object_type)
+               return res
+       end
+
+       redef fun native_array_set(nat, i, val)
+       do
+               var nclass = mmodule.native_array_class
+               var recv = "((struct instance_{nclass.c_name}*){nat})->values"
+               self.add("{recv}[{i}]={val};")
+       end
+
        fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
                assert mtype.need_anchor
                var compiler = self.compiler
        fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
                assert mtype.need_anchor
                var compiler = self.compiler
@@ -2168,13 +2214,18 @@ class SeparateRuntimeFunction
        # The C type for the function pointer.
        var c_funptrtype: String is lazy do return "{c_ret}(*){c_sig}"
 
        # The C type for the function pointer.
        var c_funptrtype: String is lazy do return "{c_ret}(*){c_sig}"
 
-       # The arguments, as generated by `compile_to_c`
-       private var arguments: Array[RuntimeVariable] is noinit
-
        redef fun compile_to_c(compiler)
        do
                var mmethoddef = self.mmethoddef
 
        redef fun compile_to_c(compiler)
        do
                var mmethoddef = self.mmethoddef
 
+               var sig = "{c_ret} {c_name}{c_sig}"
+               compiler.provide_declaration(self.c_name, "{sig} __attribute__((weak));")
+
+               var rta = compiler.as(SeparateCompiler).runtime_type_analysis
+               if rta != null and not rta.live_mmodules.has(mmethoddef.mclassdef.mmodule) then
+                       return
+               end
+
                var recv = self.mmethoddef.mclassdef.bound_mtype
                var v = compiler.new_visitor
                var selfvar = new RuntimeVariable("self", called_recv, recv)
                var recv = self.mmethoddef.mclassdef.bound_mtype
                var v = compiler.new_visitor
                var selfvar = new RuntimeVariable("self", called_recv, recv)
@@ -2185,12 +2236,7 @@ class SeparateRuntimeFunction
                var msignature = called_signature
                var ret = called_signature.return_mtype
 
                var msignature = called_signature
                var ret = called_signature.return_mtype
 
-               var sig = new FlatBuffer
                var comment = new FlatBuffer
                var comment = new FlatBuffer
-               sig.append(c_ret)
-               sig.append(" ")
-               sig.append(self.c_name)
-               sig.append(c_sig)
                comment.append("({selfvar}: {selfvar.mtype}")
                arguments.add(selfvar)
                for i in [0..msignature.arity[ do
                comment.append("({selfvar}: {selfvar.mtype}")
                arguments.add(selfvar)
                for i in [0..msignature.arity[ do
@@ -2206,8 +2252,6 @@ class SeparateRuntimeFunction
                if ret != null then
                        comment.append(": {ret}")
                end
                if ret != null then
                        comment.append(": {ret}")
                end
-               compiler.provide_declaration(self.c_name, "{sig};")
-               self.arguments = arguments.to_a
 
                v.add_decl("/* method {self} for {comment} */")
                v.add_decl("{sig} \{")
 
                v.add_decl("/* method {self} for {comment} */")
                v.add_decl("{sig} \{")
@@ -2240,8 +2284,10 @@ class SeparateRuntimeFunction
        fun compile_trampolines(compiler: SeparateCompiler)
        do
                var recv = self.mmethoddef.mclassdef.bound_mtype
        fun compile_trampolines(compiler: SeparateCompiler)
        do
                var recv = self.mmethoddef.mclassdef.bound_mtype
-               var selfvar = arguments.first
+               var selfvar = new RuntimeVariable("self", called_recv, recv)
                var ret = called_signature.return_mtype
                var ret = called_signature.return_mtype
+               var arguments = ["self"]
+               for i in [0..called_signature.arity[ do arguments.add "p{i}"
 
                if mmethoddef.is_intro and not recv.is_c_primitive then
                        var m = mmethoddef.mproperty
 
                if mmethoddef.is_intro and not recv.is_c_primitive then
                        var m = mmethoddef.mproperty
@@ -2250,7 +2296,7 @@ class SeparateRuntimeFunction
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
-                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});"
                        if ret != null then
                                v2.add "return {call}"
                        else
                        if ret != null then
                                v2.add "return {call}"
                        else
@@ -2267,7 +2313,7 @@ class SeparateRuntimeFunction
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
-                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});"
                        if ret != null then
                                v2.add "return {call}"
                        else
                        if ret != null then
                                v2.add "return {call}"
                        else
@@ -2308,3 +2354,14 @@ redef class AMethPropdef
                return super
        end
 end
                return super
        end
 end
+
+redef class AAttrPropdef
+       redef fun init_expr(v, recv)
+       do
+               super
+               if is_lazy and v.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
+                       var guard = self.mlazypropdef.mproperty
+                       v.write_attribute(guard, recv, v.bool_instance(false))
+               end
+       end
+end