nitg & lib: intro `Finalizable` to be called when an object is freed
[nit.git] / src / separate_compiler.nit
index b8ccbb1..aab5468 100644 (file)
@@ -16,7 +16,7 @@
 module separate_compiler
 
 import abstract_compiler
-import layout_builders
+import coloring
 import rapid_type_analysis
 
 # Add separate compiler specific options
@@ -30,13 +30,17 @@ redef class ToolContext
        # --no-shortcut-equate
        var opt_no_shortcut_equate: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
        # --inline-coloring-numbers
-       var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids", "--inline-coloring-numbers")
-       # --use-naive-coloring
-       var opt_bm_typing: OptionBool = new OptionBool("Colorize items incrementaly, used to simulate binary matrix typing", "--bm-typing")
-       # --use-mod-perfect-hashing
-       var opt_phmod_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with mod operator)", "--phmod-typing")
-       # --use-and-perfect-hashing
-       var opt_phand_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with and operator)", "--phand-typing")
+       var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
+       # --inline-some-methods
+       var opt_inline_some_methods: OptionBool = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
+       # --direct-call-monomorph
+       var opt_direct_call_monomorph: OptionBool = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
+       # --skip-dead-methods
+       var opt_skip_dead_methods = new OptionBool("Do not compile dead methods (semi-global)", "--skip-dead-methods")
+       # --semi-global
+       var opt_semi_global = new OptionBool("Enable all semi-global optimizations", "--semi-global")
+       # --no-colo-dead-methods
+       var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
        # --tables-metrics
        var opt_tables_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
 
@@ -47,97 +51,135 @@ redef class ToolContext
                self.option_context.add_option(self.opt_no_inline_intern)
                self.option_context.add_option(self.opt_no_union_attribute)
                self.option_context.add_option(self.opt_no_shortcut_equate)
-               self.option_context.add_option(self.opt_inline_coloring_numbers)
-               self.option_context.add_option(self.opt_bm_typing)
-               self.option_context.add_option(self.opt_phmod_typing)
-               self.option_context.add_option(self.opt_phand_typing)
+               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)
        end
+
+       redef fun process_options(args)
+       do
+               super
+
+               var tc = self
+               if tc.opt_semi_global.value then
+                       tc.opt_inline_coloring_numbers.value = true
+                       tc.opt_inline_some_methods.value = true
+                       tc.opt_direct_call_monomorph.value = true
+                       tc.opt_skip_dead_methods.value = true
+               end
+       end
+
+       var separate_compiler_phase = new SeparateCompilerPhase(self, null)
+end
+
+class SeparateCompilerPhase
+       super Phase
+       redef fun process_mainmodule(mainmodule, given_mmodules) do
+               if not toolcontext.opt_separate.value then return
+
+               var modelbuilder = toolcontext.modelbuilder
+               var analysis = modelbuilder.do_rapid_type_analysis(mainmodule)
+               modelbuilder.run_separate_compiler(mainmodule, analysis)
+       end
 end
 
 redef class ModelBuilder
-       fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
+       fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: nullable RapidTypeAnalysis)
        do
                var time0 = get_time
-               self.toolcontext.info("*** COMPILING TO C ***", 1)
+               self.toolcontext.info("*** GENERATING C ***", 1)
 
                var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
                compiler.compile_header
 
                # compile class structures
+               self.toolcontext.info("Property coloring", 2)
+               compiler.new_file("{mainmodule.name}.classes")
+               compiler.do_property_coloring
                for m in mainmodule.in_importation.greaters do
                        for mclass in m.intro_mclasses do
+                               if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
                                compiler.compile_class_to_c(mclass)
                        end
                end
 
                # The main function of the C
-               compiler.new_file
+               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
-                       compiler.new_file
+                       self.toolcontext.info("Generate C for module {m}", 2)
+                       compiler.new_file("{m.name}.sep")
                        compiler.compile_module_to_c(m)
                end
 
                # compile live & cast type structures
-               compiler.new_file
+               self.toolcontext.info("Type coloring", 2)
+               compiler.new_file("{mainmodule.name}.types")
                var mtypes = compiler.do_type_coloring
                for t in mtypes do
                        compiler.compile_type_to_c(t)
                end
+               # compile remaining types structures (useless but needed for the symbol resolution at link-time)
+               for t in compiler.undead_types do
+                       if mtypes.has(t) then continue
+                       compiler.compile_type_to_c(t)
+               end
 
                compiler.display_stats
 
+               var time1 = get_time
+               self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
                write_and_make(compiler)
        end
+
+       # Count number of invocations by VFT
+       private var nb_invok_by_tables = 0
+       # Count number of invocations by direct call
+       private var nb_invok_by_direct = 0
+       # Count number of invocations by inlining
+       private var nb_invok_by_inline = 0
 end
 
 # Singleton that store the knowledge about the separate compilation process
 class SeparateCompiler
        super AbstractCompiler
 
+       redef type VISITOR: SeparateCompilerVisitor
+
        # The result of the RTA (used to know live types and methods)
-       var runtime_type_analysis: RapidTypeAnalysis
+       var runtime_type_analysis: nullable RapidTypeAnalysis
 
        private var undead_types: Set[MType] = new HashSet[MType]
-       private var partial_types: Set[MType] = new HashSet[MType]
        private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
 
-       private var type_layout: nullable Layout[MType]
-       private var resolution_layout: nullable Layout[MType]
-       protected var method_layout: nullable Layout[MMethod]
-       protected var attr_layout: nullable Layout[MAttribute]
+       private var type_ids: Map[MType, Int]
+       private var type_colors: Map[MType, Int]
+       private var opentype_colors: Map[MType, Int]
+       protected var method_colors: Map[PropertyLayoutElement, Int]
+       protected var attr_colors: Map[MAttribute, Int]
 
-       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis) do
+       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
                super(mainmodule, mmbuilder)
+               var file = new_file("nit.common")
+               self.header = new CodeWriter(file)
                self.runtime_type_analysis = runtime_type_analysis
-               self.do_property_coloring
                self.compile_box_kinds
        end
 
        redef fun compile_header_structs do
                self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
                self.compile_header_attribute_structs
-               self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
+               self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[]; \}; /* general C type representing a Nit class. */")
 
                # With resolution_table_table, all live type resolution are stored in a big table: resolution_table
-               self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; struct types *resolution_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
-
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("struct types \{ int mask; struct type *types[1]; \}; /* a list types (used for vts, fts and unresolved lists). */")
-               else
-                       self.header.add_decl("struct types \{ struct type *types[1]; \}; /* a list types (used for vts, fts and unresolved lists). */")
-               end
-
-               if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
-               end
-
-               self.header.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
+               self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; const struct types *resolution_table; int table_size; int type_table[]; \}; /* general C type representing a Nit type. */")
+               self.header.add_decl("struct instance \{ const struct type *type; const struct class *class; nitattribute_t attrs[]; \}; /* general C type representing a Nit instance. */")
+               self.header.add_decl("struct types \{ int dummy; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */")
+               self.header.add_decl("typedef struct instance val; /* general C type representing a Nit instance. */")
        end
 
        fun compile_header_attribute_structs
@@ -182,198 +224,234 @@ class SeparateCompiler
        end
 
        fun compile_color_consts(colors: Map[Object, Int]) do
+               var v = new_visitor
                for m, c in colors do
-                       if color_consts_done.has(m) then continue
-                       if m isa MProperty then
-                               if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
-                                       self.header.add_decl("#define {m.const_color} {c}")
-                               else
-                                       self.header.add_decl("extern const int {m.const_color};")
-                                       self.header.add("const int {m.const_color} = {c};")
-                               end
-                       else if m isa MType then
-                               if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
-                                       self.header.add_decl("#define {m.const_color} {c}")
-                               else
-                                       self.header.add_decl("extern const int {m.const_color};")
-                                       self.header.add("const int {m.const_color} = {c};")
-                               end
+                       compile_color_const(v, m, c)
+               end
+       end
+
+       fun compile_color_const(v: SeparateCompilerVisitor, m: Object, color: Int) do
+               if color_consts_done.has(m) then return
+               if m isa MProperty then
+                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
+                       else
+                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
+                               v.add("const int {m.const_color} = {color};")
+                       end
+               else if m isa MPropDef then
+                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
+                       else
+                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
+                               v.add("const int {m.const_color} = {color};")
+                       end
+               else if m isa MType then
+                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
+                       else
+                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
+                               v.add("const int {m.const_color} = {color};")
                        end
-                       color_consts_done.add(m)
                end
+               color_consts_done.add(m)
        end
 
        private var color_consts_done = new HashSet[Object]
 
        # colorize classe properties
        fun do_property_coloring do
-               var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
+
+               var rta = runtime_type_analysis
 
                # Layouts
-               var method_layout_builder: PropertyLayoutBuilder[MMethod]
-               var attribute_layout_builder: PropertyLayoutBuilder[MAttribute]
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       method_layout_builder = new MMethodBMizer(self.mainmodule)
-                       attribute_layout_builder = new MAttributeBMizer(self.mainmodule)
+               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]
+
+               # lookup properties to build layout with
+               var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
+               var mattributes = new HashMap[MClass, Set[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
+               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)
+                                       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
-                       method_layout_builder = new MMethodColorer(self.mainmodule)
-                       attribute_layout_builder = new MAttributeColorer(self.mainmodule)
+                       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)
+                       end
                end
 
                # methods coloration
-               var method_layout = method_layout_builder.build_layout(mclasses)
-               self.method_tables = build_method_tables(mclasses, method_layout)
-               self.compile_color_consts(method_layout.pos)
-               self.method_layout = method_layout
+               var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts)
+               method_colors = meth_colorer.colorize(mmethods)
+               method_tables = build_method_tables(mclasses, super_calls)
+               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
 
                # attributes coloration
-               var attr_layout = attribute_layout_builder.build_layout(mclasses)
-               self.attr_tables = build_attr_tables(mclasses, attr_layout)
-               self.compile_color_consts(attr_layout.pos)
-               self.attr_layout = attr_layout
+               var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts)
+               attr_colors = attr_colorer.colorize(mattributes)
+               attr_tables = build_attr_tables(mclasses)
+               compile_color_consts(attr_colors)
        end
 
-       fun build_method_tables(mclasses: Set[MClass], layout: Layout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+       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]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
-                       # first, fill table from parents by reverse linearization order
-                       var parents = self.mainmodule.super_mclasses(mclass)
-                       var lin = self.mainmodule.reverse_linearize_mclasses(parents)
-                       for parent in lin do
-                               for mproperty in self.mainmodule.properties(parent) do
-                                       if not mproperty isa MMethod then continue
-                                       var color = layout.pos[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
+
+                       var mproperties = self.mainmodule.properties(mclass)
+                       var mtype = mclass.intro.bound_mtype
 
-                       # 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
-                               var color = layout.pos[mproperty]
+                               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 == mclass then
-                                               table[color] = mpropdef
+                               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
                                end
+                               var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype)
+                               table[color] = mmethoddef
                        end
-                       tables[mclass] = table
+
                end
                return tables
        end
 
-       fun build_attr_tables(mclasses: Set[MClass], layout: Layout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+       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]
-                       # first, fill table from parents by reverse linearization order
-                       var parents = self.mainmodule.super_mclasses(mclass)
-                       var lin = self.mainmodule.reverse_linearize_mclasses(parents)
-                       for parent in lin do
-                               for mproperty in self.mainmodule.properties(parent) do
-                                       if not mproperty isa MAttribute then continue
-                                       var color = layout.pos[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
-                               var color = layout.pos[mproperty]
+                               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
 
        # colorize live types of the program
-       private fun do_type_coloring: Set[MType] do
+       private fun do_type_coloring: POSet[MType] do
+               # Collect types to colorize
+               var live_types = runtime_type_analysis.live_types
+               var live_cast_types = runtime_type_analysis.live_cast_types
                var mtypes = new HashSet[MType]
-               mtypes.add_all(self.runtime_type_analysis.live_types)
-               mtypes.add_all(self.runtime_type_analysis.live_cast_types)
-               mtypes.add_all(self.undead_types)
+               mtypes.add_all(live_types)
+               mtypes.add_all(live_cast_types)
                for c in self.box_kinds.keys do
                        mtypes.add(c.mclass_type)
                end
 
-               for mtype in mtypes do
-                       retieve_live_partial_types(mtype)
-               end
-               mtypes.add_all(self.partial_types)
-
-               # Typing Layout
-               var layout_builder: TypingLayoutBuilder[MType]
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       layout_builder = new MTypeBMizer(self.mainmodule)
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       layout_builder = new MTypeHasher(new PHModOperator, self.mainmodule)
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       layout_builder = new MTypeHasher(new PHAndOperator, self.mainmodule)
-               else
-                       layout_builder = new MTypeColorer(self.mainmodule)
-               end
-
-               # colorize types
-               self.type_layout = layout_builder.build_layout(mtypes)
-               self.type_tables = self.build_type_tables(mtypes)
+               # Compute colors
+               var poset = poset_from_mtypes(mtypes)
+               var colorer = new POSetColorer[MType]
+               colorer.colorize(poset)
+               type_ids = colorer.ids
+               type_colors = colorer.colors
+               type_tables = build_type_tables(poset)
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
                self.compile_resolution_tables(mtypes)
 
-               return mtypes
+               return poset
+       end
+
+       private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do
+               var poset = new POSet[MType]
+               for e in mtypes do
+                       poset.add_node(e)
+                       for o in mtypes do
+                               if e == o then continue
+                               if e.is_subtype(mainmodule, null, o) then
+                                       poset.add_edge(e, o)
+                               end
+                       end
+               end
+               return poset
        end
 
        # Build type tables
-       fun build_type_tables(mtypes: Set[MType]): Map[MType, Array[nullable MType]] do
+       fun build_type_tables(mtypes: POSet[MType]): Map[MType, Array[nullable MType]] do
                var tables = new HashMap[MType, Array[nullable MType]]
-               var layout = self.type_layout
                for mtype in mtypes do
                        var table = new Array[nullable MType]
-                       var supers = new HashSet[MType]
-                       supers.add_all(self.mainmodule.super_mtypes(mtype, mtypes))
-                       supers.add(mtype)
-                       for sup in supers do
-                               var color: Int
-                               if layout isa PHLayout[MType, MType] then
-                                       color = layout.hashes[mtype][sup]
-                               else
-                                       color = layout.pos[sup]
-                               end
+                       for sup in mtypes[mtype].greaters do
+                               var color = type_colors[sup]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -406,18 +484,9 @@ class SeparateCompiler
                end
 
                # Compute the table layout with the prefered method
-               var resolution_builder: ResolutionLayoutBuilder
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       resolution_builder = new ResolutionBMizer
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       resolution_builder = new ResolutionHasher(new PHModOperator)
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       resolution_builder = new ResolutionHasher(new PHAndOperator)
-               else
-                       resolution_builder = new ResolutionColorer
-               end
-               self.resolution_layout = resolution_builder.build_layout(mtype2unresolved)
-               self.resolution_tables = self.build_resolution_tables(mtype2unresolved)
+               var colorer = new BucketsColorer[MType, MType]
+               opentype_colors = colorer.colorize(mtype2unresolved)
+               resolution_tables = self.build_resolution_tables(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)
@@ -427,8 +496,8 @@ class SeparateCompiler
                end
                var all_unresolved_types_colors = new HashMap[MType, Int]
                for t in all_unresolved do
-                       if self.resolution_layout.pos.has_key(t) then
-                               all_unresolved_types_colors[t] = self.resolution_layout.pos[t]
+                       if opentype_colors.has_key(t) then
+                               all_unresolved_types_colors[t] = opentype_colors[t]
                        else
                                all_unresolved_types_colors[t] = -1
                        end
@@ -444,16 +513,10 @@ class SeparateCompiler
 
        fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
                var tables = new HashMap[MClassType, Array[nullable MType]]
-               var layout = self.resolution_layout
                for mclasstype, mtypes in elements do
                        var table = new Array[nullable MType]
                        for mtype in mtypes do
-                               var color: Int
-                               if layout isa PHLayout[MClassType, MType] then
-                                       color = layout.hashes[mclasstype][mtype]
-                               else
-                                       color = layout.pos[mtype]
-                               end
+                               var color = opentype_colors[mtype]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -466,34 +529,6 @@ class SeparateCompiler
                return tables
        end
 
-       fun retieve_live_partial_types(mtype: MType) do
-               # add formal types arguments to mtypes
-               if mtype isa MGenericType then
-                       for ft in mtype.arguments do
-                               if ft.need_anchor then
-                                       print("Why do we need anchor here ?")
-                                       abort
-                               end
-                               self.partial_types.add(ft)
-                               retieve_live_partial_types(ft)
-                       end
-               end
-               var mclass_type: MClassType
-               if mtype isa MNullableType then
-                       mclass_type = mtype.mtype.as(MClassType)
-               else
-                       mclass_type = mtype.as(MClassType)
-               end
-
-               # add virtual types to mtypes
-               for vt in self.mainmodule.properties(mclass_type.mclass) do
-                       if vt isa MVirtualTypeProp then
-                               var anchored = vt.mvirtualtype.lookup_bound(self.mainmodule, mclass_type).anchor_to(self.mainmodule, mclass_type)
-                               self.partial_types.add(anchored)
-                       end
-               end
-       end
-
        # Separately compile all the method definitions of the module
        fun compile_module_to_c(mmodule: MModule)
        do
@@ -502,13 +537,13 @@ class SeparateCompiler
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
+                               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 r = new SeparateRuntimeFunction(pd)
+                               var r = pd.separate_runtime_function
                                r.compile_to_c(self)
-                               if true or cd.bound_mtype.ctype != "val*" then
-                                       var r2 = new VirtualRuntimeFunction(pd)
-                                       r2.compile_to_c(self)
-                               end
+                               var r2 = pd.virtual_runtime_function
+                               r2.compile_to_c(self)
                        end
                end
                self.mainmodule = old_module
@@ -517,82 +552,87 @@ class SeparateCompiler
        # Globaly compile the type structure of a live type
        fun compile_type_to_c(mtype: MType)
        do
+               assert not mtype.need_anchor
+               var is_live = mtype isa MClassType and runtime_type_analysis.live_types.has(mtype)
+               var is_cast_live = runtime_type_analysis.live_cast_types.has(mtype)
                var c_name = mtype.c_name
                var v = new SeparateCompilerVisitor(self)
                v.add_decl("/* runtime type {mtype} */")
 
                # extern const struct type_X
-               self.header.add_decl("extern const struct type_{c_name} type_{c_name};")
-               self.header.add_decl("struct type_{c_name} \{")
-               self.header.add_decl("int id;")
-               self.header.add_decl("const char *name;")
-               self.header.add_decl("int color;")
-               self.header.add_decl("short int is_nullable;")
-               self.header.add_decl("const struct types *resolution_table;")
-               self.header.add_decl("int table_size;")
-               self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
-               self.header.add_decl("\};")
+               self.provide_declaration("type_{c_name}", "extern const struct type type_{c_name};")
 
                # const struct type_X
-               v.add_decl("const struct type_{c_name} type_{c_name} = \{")
-               v.add_decl("{self.type_layout.ids[mtype]},")
+               v.add_decl("const struct type type_{c_name} = \{")
+
+               # type id (for cast target)
+               if is_cast_live then
+                       v.add_decl("{type_ids[mtype]},")
+               else
+                       v.add_decl("-1, /*CAST DEAD*/")
+               end
+
+               # type name
                v.add_decl("\"{mtype}\", /* class_name_string */")
-               var layout = self.type_layout
-               if layout isa PHLayout[MType, MType] then
-                       v.add_decl("{layout.masks[mtype]},")
+
+               # type color (for cast target)
+               if is_cast_live then
+                       v.add_decl("{type_colors[mtype]},")
                else
-                       v.add_decl("{layout.pos[mtype]},")
+                       v.add_decl("-1, /*CAST DEAD*/")
                end
+
+               # is_nullable bit
                if mtype isa MNullableType then
                        v.add_decl("1,")
                else
                        v.add_decl("0,")
                end
-               if compile_type_resolution_table(mtype) then
-                       v.add_decl("(struct types*) &resolution_table_{c_name},")
+
+               # resolution table (for receiver)
+               if is_live then
+                       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*/")
+                       else
+                               compile_type_resolution_table(mtype)
+                               v.require_declaration("resolution_table_{c_name}")
+                               v.add_decl("&resolution_table_{c_name},")
+                       end
                else
-                       v.add_decl("NULL,")
+                       v.add_decl("NULL, /*DEAD*/")
                end
-               v.add_decl("{self.type_tables[mtype].length},")
-               v.add_decl("\{")
-               for stype in self.type_tables[mtype] do
-                       if stype == null then
-                               v.add_decl("-1, /* empty */")
-                       else
-                               v.add_decl("{self.type_layout.ids[stype]}, /* {stype} */")
+
+               # cast table (for receiver)
+               if is_live then
+                       v.add_decl("{self.type_tables[mtype].length},")
+                       v.add_decl("\{")
+                       for stype in self.type_tables[mtype] do
+                               if stype == null then
+                                       v.add_decl("-1, /* empty */")
+                               else
+                                       v.add_decl("{type_ids[stype]}, /* {stype} */")
+                               end
                        end
+                       v.add_decl("\},")
+               else
+                       v.add_decl("0, \{\}, /*DEAD TYPE*/")
                end
-               v.add_decl("\},")
                v.add_decl("\};")
        end
 
-       fun compile_type_resolution_table(mtype: MType): Bool do
+       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
-               if not self.resolution_tables.has_key(mclass_type) then return false
-
-               var layout = self.resolution_layout
+               var mclass_type = mtype.as_notnullable.as(MClassType)
 
                # extern const struct resolution_table_X resolution_table_X
-               self.header.add_decl("extern const struct resolution_table_{mtype.c_name} resolution_table_{mtype.c_name};")
-               self.header.add_decl("struct resolution_table_{mtype.c_name} \{")
-               if layout isa PHLayout[MClassType, MType] then
-                       self.header.add_decl("int mask;")
-               end
-               self.header.add_decl("struct type *types[{self.resolution_tables[mclass_type].length}];")
-               self.header.add_decl("\};")
+               self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
 
                # const struct fts_table_X fts_table_X
                var v = new_visitor
-               v.add_decl("const struct resolution_table_{mtype.c_name} resolution_table_{mtype.c_name} = \{")
-               if layout isa PHLayout[MClassType, MType] then
-                       v.add_decl("{layout.masks[mclass_type]},")
-               end
+               v.add_decl("const struct types resolution_table_{mtype.c_name} = \{")
+               v.add_decl("0, /* dummy */")
                v.add_decl("\{")
                for t in self.resolution_tables[mclass_type] do
                        if t == null then
@@ -603,16 +643,16 @@ class SeparateCompiler
                                # the value stored is tv.
                                var tv = t.resolve_for(mclass_type, mclass_type, self.mainmodule, true)
                                # FIXME: What typeids means here? How can a tv not be live?
-                               if self.type_layout.ids.has_key(tv) then
-                                       v.add_decl("(struct type*)&type_{tv.c_name}, /* {t}: {tv} */")
+                               if type_ids.has_key(tv) then
+                                       v.require_declaration("type_{tv.c_name}")
+                                       v.add_decl("&type_{tv.c_name}, /* {t}: {tv} */")
                                else
                                        v.add_decl("NULL, /* empty ({t}: {tv} not a live type) */")
                                end
                        end
                end
-               v.add_decl("\},")
+               v.add_decl("\}")
                v.add_decl("\};")
-               return true
        end
 
        # Globally compile the table of the class mclass
@@ -622,123 +662,126 @@ class SeparateCompiler
        do
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
+               var c_instance_name = mclass.c_instance_name
 
                var vft = self.method_tables[mclass]
                var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
-               v.add_decl("/* runtime class {c_name} */")
+               var rta = runtime_type_analysis
+               var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray"
 
-               self.header.add_decl("struct class_{c_name} \{")
-               self.header.add_decl("int box_kind;")
-               self.header.add_decl("nitmethod_t vft[{vft.length}];")
-               self.header.add_decl("\};")
+               v.add_decl("/* runtime class {c_name} */")
 
                # Build class vft
-               self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
-               v.add_decl("const struct class_{c_name} class_{c_name} = \{")
-               v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
-               v.add_decl("\{")
-               for i in [0 .. vft.length[ do
-                       var mpropdef = vft[i]
-                       if mpropdef == null then
-                               v.add_decl("NULL, /* empty */")
-                       else
-                               if true or mpropdef.mclassdef.bound_mtype.ctype != "val*" then
-                                       v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
+               if not is_dead 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("\{")
+                       for i in [0 .. vft.length[ do
+                               var mpropdef = vft[i]
+                               if mpropdef == null then
+                                       v.add_decl("NULL, /* empty */")
                                else
-                                       v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
+                                       assert mpropdef isa MMethodDef
+                                       if rta != null and not rta.live_methoddefs.has(mpropdef) then
+                                               v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
+                                               continue
+                                       end
+                                       var rf = mpropdef.virtual_runtime_function
+                                       v.require_declaration(rf.c_name)
+                                       v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
                                end
                        end
+                       v.add_decl("\}")
+                       v.add_decl("\};")
                end
-               v.add_decl("\}")
-               v.add_decl("\};")
 
                if mtype.ctype != "val*" then
-                       #Build instance struct
-                       self.header.add_decl("struct instance_{c_name} \{")
-                       self.header.add_decl("const struct type *type;")
-                       self.header.add_decl("const struct class *class;")
-                       self.header.add_decl("{mtype.ctype} value;")
-                       self.header.add_decl("\};")
+                       if mtype.mclass.name == "Pointer" or mtype.mclass.kind != extern_kind then
+                               #Build instance struct
+                               self.header.add_decl("struct instance_{c_instance_name} \{")
+                               self.header.add_decl("const struct type *type;")
+                               self.header.add_decl("const struct class *class;")
+                               self.header.add_decl("{mtype.ctype} value;")
+                               self.header.add_decl("\};")
+                       end
 
-                       if not self.runtime_type_analysis.live_types.has(mtype) then return
+                       if not rta.live_types.has(mtype) then return
 
-                       self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
+                       #Build BOX
+                       self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
-                       v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
-                       v.add("res->type = (struct type*) &type_{c_name};")
-                       v.add("res->class = (struct class*) &class_{c_name};")
+                       v.add("struct instance_{c_instance_name}*res = nit_alloc(sizeof(struct instance_{c_instance_name}));")
+                       v.require_declaration("type_{c_name}")
+                       v.add("res->type = &type_{c_name};")
+                       v.require_declaration("class_{c_name}")
+                       v.add("res->class = &class_{c_name};")
                        v.add("res->value = value;")
                        v.add("return (val*)res;")
                        v.add("\}")
                        return
-               end
-
-               var is_native_array = mclass.name == "NativeArray"
-
-               var sig
-               if is_native_array then
-                       sig = "int length, struct type* type"
-               else
-                       sig = "struct type* type"
-               end
-
-               #Build instance struct
-               #extern const struct instance_array__NativeArray instance_array__NativeArray;
-               self.header.add_decl("struct instance_{c_name} \{")
-               self.header.add_decl("const struct type *type;")
-               self.header.add_decl("const struct class *class;")
-               self.header.add_decl("nitattribute_t attrs[{attrs.length}];")
-               if is_native_array then
-                       # NativeArrays are just a instance header followed by an array of values
+               else if mclass.name == "NativeArray" then
+                       #Build instance struct
+                       self.header.add_decl("struct instance_{c_instance_name} \{")
+                       self.header.add_decl("const struct type *type;")
+                       self.header.add_decl("const struct class *class;")
+                       # NativeArrays are just a instance header followed by a length and an array of values
+                       self.header.add_decl("int length;")
                        self.header.add_decl("val* values[0];")
-               end
-               self.header.add_decl("\};")
-
+                       self.header.add_decl("\};")
 
-               self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
-               v.add_decl("/* allocate {mtype} */")
-               v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
-               var res = v.new_named_var(mtype, "self")
-               res.is_exact = true
-               if is_native_array then
+                       #Build NEW
+                       self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(int length, const struct type* type);")
+                       v.add_decl("/* allocate {mtype} */")
+                       v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{")
+                       var res = v.get_name("self")
+                       v.add_decl("struct instance_{c_instance_name} *{res};")
                        var mtype_elt = mtype.arguments.first
-                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
-               else
-                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
-               end
-               v.add("{res}->type = type;")
-               if v.compiler.modelbuilder.toolcontext.opt_hardening.value then
-                       v.add("if(type == NULL) \{")
-                       v.add_abort("type null")
-                       v.add("\}")
-                       v.add("if(type->resolution_table == NULL) \{")
-                       v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", type->name);")
-                       v.add_abort("type dead")
+                       v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));")
+                       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}->length = length;")
+                       v.add("return (val*){res};")
                        v.add("\}")
+                       return
                end
-               v.add("{res}->class = (struct class*) &class_{c_name};")
 
-               self.generate_init_attr(v, res, mtype)
-               v.add("return {res};")
+               #Build NEW
+               self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
+               v.add_decl("/* allocate {mtype} */")
+               v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
+               if is_dead then
+                       v.add_abort("{mclass} is DEAD")
+               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));")
+                       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
+                       v.add("return {res};")
+               end
                v.add("\}")
-
-               generate_check_init_instance(mtype)
        end
 
-       redef fun generate_check_init_instance(mtype)
+       # Add a dynamic test to ensure that the type referenced by `t` is a live type
+       fun hardening_live_type(v: VISITOR, t: String)
        do
-               if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
-
-               var v = self.new_visitor
-               var c_name = mtype.mclass.c_name
-               var res = new RuntimeVariable("self", mtype, mtype)
-               self.header.add_decl("void CHECK_NEW_{c_name}({mtype.ctype});")
-               v.add_decl("/* allocate {mtype} */")
-               v.add_decl("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{")
-               self.generate_check_attr(v, res, mtype)
+               if not v.compiler.modelbuilder.toolcontext.opt_hardening.value then return
+               v.add("if({t} == NULL) \{")
+               v.add_abort("type null")
+               v.add("\}")
+               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("\}")
        end
 
@@ -757,6 +800,16 @@ class SeparateCompiler
                if self.modelbuilder.toolcontext.opt_tables_metrics.value then
                        display_sizes
                end
+               if self.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                       display_isset_checks
+               end
+               var tc = self.modelbuilder.toolcontext
+               tc.info("# implementation of method invocation",2)
+               var nb_invok_total = modelbuilder.nb_invok_by_tables + modelbuilder.nb_invok_by_direct + modelbuilder.nb_invok_by_inline
+               tc.info("total number of invocations: {nb_invok_total}",2)
+               tc.info("invocations by VFT send:     {modelbuilder.nb_invok_by_tables} ({div(modelbuilder.nb_invok_by_tables,nb_invok_total)}%)",2)
+               tc.info("invocations by direct call:  {modelbuilder.nb_invok_by_direct} ({div(modelbuilder.nb_invok_by_direct,nb_invok_total)}%)",2)
+               tc.info("invocations by inlining:     {modelbuilder.nb_invok_by_inline} ({div(modelbuilder.nb_invok_by_inline,nb_invok_total)}%)",2)
        end
 
        fun display_sizes
@@ -801,6 +854,37 @@ class SeparateCompiler
                end
                print "\t{total}\t{holes}"
        end
+
+       protected var isset_checks_count = 0
+       protected var attr_read_count = 0
+
+       fun display_isset_checks do
+               print "# total number of compiled attribute reads"
+               print "\t{attr_read_count}"
+               print "# total number of compiled isset-checks"
+               print "\t{isset_checks_count}"
+       end
+
+       redef fun compile_nitni_structs
+       do
+               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
+               self.mainmodule = mmodule
+               super
+               self.mainmodule = old_module
+       end
 end
 
 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
@@ -832,22 +916,27 @@ class SeparateCompilerVisitor
                else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
                        return value
                else if value.mtype.ctype == "val*" then
-                       return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
+                       return self.new_expr("((struct instance_{mtype.c_instance_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
                else if mtype.ctype == "val*" then
                        var valtype = value.mtype.as(MClassType)
                        var res = self.new_var(mtype)
-                       if not compiler.runtime_type_analysis.live_types.has(valtype) then
+                       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\"); exit(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*") 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}\"); exit(1);")
+                       self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
                        return res
                end
        end
@@ -859,52 +948,73 @@ class SeparateCompilerVisitor
                if value.mtype.ctype == "val*" then
                        return "{value}->type"
                else
+                       compiler.undead_types.add(value.mtype)
+                       self.require_declaration("type_{value.mtype.c_name}")
                        return "(&type_{value.mtype.c_name})"
                end
        end
 
-       redef fun send(mmethod, arguments)
+       redef fun compile_callsite(callsite, args)
        do
-               if arguments.first.mcasttype.ctype != "val*" then
-                       return self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
+               var rta = compiler.runtime_type_analysis
+               var recv = args.first.mtype
+               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null then
+                       var tgs = rta.live_targets(callsite)
+                       if tgs.length == 1 then
+                               # DIRECT CALL
+                               var mmethod = callsite.mproperty
+                               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args)
+                               var res0 = before_send(mmethod, args)
+                               var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
+                               if res0 != null then
+                                       assert res != null
+                                       self.assign(res0, res)
+                                       res = res0
+                               end
+                               add("\}") # close the before_send
+                               return res
+                       end
                end
+               return super
+       end
+       redef fun send(mmethod, arguments)
+       do
+               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
 
-               var res: nullable RuntimeVariable
-               var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
-               var ret = msignature.return_mtype
-               if mmethod.is_new then
-                       ret = arguments.first.mtype
-                       res = self.new_var(ret)
-               else if ret == null then
-                       res = null
-               else
-                       res = self.new_var(ret)
+               if arguments.first.mcasttype.ctype != "val*" then
+                       # In order to shortcut the primitive, we need to find the most specific method
+                       # Howverr, because of performance (no flattening), we always work on the realmainmodule
+                       var m = self.compiler.mainmodule
+                       self.compiler.mainmodule = self.compiler.realmainmodule
+                       var res = self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
+                       self.compiler.mainmodule = m
+                       return res
                end
 
-               var s = new Buffer
-               var ss = new Buffer
+               return table_send(mmethod, arguments, mmethod.const_color)
+       end
 
+       # Handel common special cases before doing the effective method invocation
+       # This methods handle the `==` and `!=` methods and the case of the null receiver.
+       # Note: a { is open in the generated C, that enclose and protect the effective method invocation.
+       # Client must not forget to close the } after them.
+       #
+       # The value returned is the result of the common special cases.
+       # If not null, client must compine it with the result of their own effective method invocation.
+       #
+       # If `before_send` can shortcut the whole message sending, a dummy `if(0){`
+       # is generated to cancel the effective method invocation that will follow
+       # TODO: find a better approach
+       private fun before_send(mmethod: MMethod, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
+       do
+               var res: nullable RuntimeVariable = null
                var recv = arguments.first
-               s.append("val*")
-               ss.append("{recv}")
-               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
-               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
-                       s.append(", {t.ctype}")
-                       a = self.autobox(a, t)
-                       ss.append(", {a}")
-               end
-
                var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
                var maybenull = recv.mcasttype isa MNullableType and consider_null
                if maybenull then
                        self.add("if ({recv} == NULL) \{")
                        if mmethod.name == "==" then
-                               assert res != null
+                               res = self.new_var(bool_type)
                                var arg = arguments[1]
                                if arg.mcasttype isa MNullableType then
                                        self.add("{res} = ({arg} == NULL);")
@@ -914,7 +1024,7 @@ class SeparateCompilerVisitor
                                        self.add("{res} = 0; /* {arg.inspect} cannot be null */")
                                end
                        else if mmethod.name == "!=" then
-                               assert res != null
+                               res = self.new_var(bool_type)
                                var arg = arguments[1]
                                if arg.mcasttype isa MNullableType then
                                        self.add("{res} = ({arg} != NULL);")
@@ -924,12 +1034,14 @@ class SeparateCompilerVisitor
                                        self.add("{res} = 1; /* {arg.inspect} cannot be null */")
                                end
                        else
-                               self.add_abort("Reciever is null")
+                               self.add_abort("Receiver is null")
                        end
                        self.add("\} else \{")
+               else
+                       self.add("\{")
                end
                if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
-                       assert res != null
+                       if res == null then res = self.new_var(bool_type)
                        # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
                        var arg = arguments[1]
                        if arg.mcasttype isa MNullType then
@@ -938,16 +1050,56 @@ class SeparateCompilerVisitor
                                else
                                        self.add("{res} = 1; /* arg is null and recv is not */")
                                end
-                               if maybenull then
-                                       self.add("\}")
-                               end
-                               return res
+                               self.add("\}") # closes the null case
+                               self.add("if (0) \{") # what follow is useless, CC will drop it
+                       end
+               end
+               return res
+       end
+
+       private fun table_send(mmethod: MMethod, arguments: Array[RuntimeVariable], const_color: String): nullable RuntimeVariable
+       do
+               compiler.modelbuilder.nb_invok_by_tables += 1
+               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 res: nullable RuntimeVariable
+               var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
+               var ret = msignature.return_mtype
+               if mmethod.is_new then
+                       ret = arguments.first.mtype
+                       res = self.new_var(ret)
+               else if ret == null then
+                       res = null
+               else
+                       res = self.new_var(ret)
+               end
+
+               var s = new FlatBuffer
+               var ss = new FlatBuffer
+
+               s.append("val*")
+               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
+                       s.append(", {t.ctype}")
+                       a = self.autobox(a, t)
+                       ss.append(", {a}")
                end
 
+
                var r
                if ret == null then r = "void" else r = ret.ctype
-               var call = "(({r} (*)({s}))({arguments.first}->class->vft[{mmethod.const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
+               self.require_declaration(const_color)
+               var call = "(({r} (*)({s}))({arguments.first}->class->vft[{const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
 
                if res != null then
                        self.add("{res} = {call};")
@@ -955,15 +1107,21 @@ class SeparateCompilerVisitor
                        self.add("{call};")
                end
 
-               if maybenull then
-                       self.add("\}")
+               if res0 != null then
+                       assert res != null
+                       assign(res0,res)
+                       res = res0
                end
 
+               self.add("\}") # closes the null case
+
                return res
        end
 
        redef fun call(mmethoddef, recvtype, arguments)
        do
+               assert arguments.length == mmethoddef.msignature.arity + 1 else debug("Invalid arity for {mmethoddef}. {arguments.length} arguments given.")
+
                var res: nullable RuntimeVariable
                var ret = mmethoddef.msignature.return_mtype
                if mmethoddef.mproperty.is_new then
@@ -976,27 +1134,31 @@ class SeparateCompilerVisitor
                        res = self.new_var(ret)
                end
 
-               if self.compiler.modelbuilder.mpropdef2npropdef.has_key(mmethoddef) and
-               self.compiler.modelbuilder.mpropdef2npropdef[mmethoddef] isa AInternMethPropdef and
-               not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value then
+               if (mmethoddef.is_intern and not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value) or
+                       (compiler.modelbuilder.toolcontext.opt_inline_some_methods.value and mmethoddef.can_inline(self)) then
+                       compiler.modelbuilder.nb_invok_by_inline += 1
+                       if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_inline++;")
                        var frame = new Frame(self, mmethoddef, recvtype, arguments)
                        frame.returnlabel = self.get_name("RET_LABEL")
                        frame.returnvar = res
                        var old_frame = self.frame
                        self.frame = frame
-                       self.add("\{ /* Inline {mmethoddef} ({arguments.join(",")}) */")
+                       self.add("\{ /* Inline {mmethoddef} ({arguments.join(",")}) on {arguments.first.inspect} */")
                        mmethoddef.compile_inside_to_c(self, arguments)
                        self.add("{frame.returnlabel.as(not null)}:(void)0;")
                        self.add("\}")
                        self.frame = old_frame
                        return res
                end
+               compiler.modelbuilder.nb_invok_by_direct += 1
+               if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_direct++;")
 
                # Autobox arguments
                self.adapt_signature(mmethoddef, arguments)
 
+               self.require_declaration(mmethoddef.c_name)
                if res == null then
-                       self.add("{mmethoddef.c_name}({arguments.join(", ")});")
+                       self.add("{mmethoddef.c_name}({arguments.join(", ")}); /* Direct call {mmethoddef} on {arguments.first.inspect}*/")
                        return null
                else
                        self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
@@ -1005,11 +1167,18 @@ class SeparateCompilerVisitor
                return res
        end
 
-       redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
+       redef fun supercall(m: MMethodDef, recvtype: MClassType, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
-               # FIXME implements a polymorphic access in tables
-               m = m.lookup_next_definition(m.mclassdef.mmodule, m.mclassdef.bound_mtype)
-               return self.call(m, recvtype, args)
+               if arguments.first.mcasttype.ctype != "val*" then
+                       # In order to shortcut the primitive, we need to find the most specific method
+                       # However, because of performance (no flattening), we always work on the realmainmodule
+                       var main = self.compiler.mainmodule
+                       self.compiler.mainmodule = self.compiler.realmainmodule
+                       var res = self.monomorphic_super_send(m, recvtype, arguments)
+                       self.compiler.mainmodule = main
+                       return res
+               end
+               return table_send(m.mproperty, arguments, m.const_color)
        end
 
        redef fun vararg_instance(mpropdef, recv, varargs, elttype)
@@ -1046,6 +1215,7 @@ class SeparateCompilerVisitor
                        return res
                end
 
+               self.require_declaration(a.const_color)
                if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
                        self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
                else
@@ -1068,6 +1238,12 @@ class SeparateCompilerVisitor
                var intromclassdef = a.intro.mclassdef
                ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
 
+               if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                       self.compiler.attr_read_count += 1
+                       self.add("count_attr_reads++;")
+               end
+
+               self.require_declaration(a.const_color)
                if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
                        # Get the attribute or a box (ie. always a val*)
                        var cret = self.object_type.as_nullable
@@ -1077,10 +1253,15 @@ class SeparateCompilerVisitor
                        self.add("{res} = {recv}->attrs[{a.const_color}]; /* {a} on {recv.inspect} */")
 
                        # Check for Uninitialized attribute
-                       if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
-                               self.add("if ({res} == NULL) \{")
+                       if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
+                               self.add("if (unlikely({res} == NULL)) \{")
                                self.add_abort("Uninitialized attribute {a.name}")
                                self.add("\}")
+
+                               if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                                       self.compiler.isset_checks_count += 1
+                                       self.add("count_isset_checks++;")
+                               end
                        end
 
                        # Return the attribute or its unboxed version
@@ -1091,10 +1272,14 @@ class SeparateCompilerVisitor
                        self.add("{res} = {recv}->attrs[{a.const_color}].{ret.ctypename}; /* {a} on {recv.inspect} */")
 
                        # Check for Uninitialized attribute
-                       if ret.ctype == "val*" and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
-                               self.add("if ({res} == NULL) \{")
+                       if ret.ctype == "val*" and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
+                               self.add("if (unlikely({res} == NULL)) \{")
                                self.add_abort("Uninitialized attribute {a.name}")
                                self.add("\}")
+                               if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                                       self.compiler.isset_checks_count += 1
+                                       self.add("count_isset_checks++;")
+                               end
                        end
 
                        return res
@@ -1113,6 +1298,7 @@ class SeparateCompilerVisitor
                # Adapt the value to the declared type
                value = self.autobox(value, mtype)
 
+               self.require_declaration(a.const_color)
                if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
                        var attr = "{recv}->attrs[{a.const_color}]"
                        if mtype.ctype != "val*" then
@@ -1120,7 +1306,7 @@ class SeparateCompilerVisitor
                                # The attribute is primitive, thus we store it in a box
                                # The trick is to create the box the first time then resuse the box
                                self.add("if ({attr} != NULL) \{")
-                               self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
+                               self.add("((struct instance_{mtype.c_instance_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
                                self.add("\} else \{")
                                value = self.autobox(value, self.object_type.as_nullable)
                                self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
@@ -1134,27 +1320,46 @@ class SeparateCompilerVisitor
                end
        end
 
+       # Check that mtype is a live open type
+       fun hardening_live_open_type(mtype: MType)
+       do
+               if not compiler.modelbuilder.toolcontext.opt_hardening.value then return
+               self.require_declaration(mtype.const_color)
+               var col = mtype.const_color
+               self.add("if({col} == -1) \{")
+               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
+
+       # Check that mtype it a pointer to a live cast type
+       fun hardening_cast_type(t: String)
+       do
+               if not compiler.modelbuilder.toolcontext.opt_hardening.value then return
+               add("if({t} == NULL) \{")
+               add_abort("cast type null")
+               add("\}")
+               add("if({t}->id == -1 || {t}->color == -1) \{")
+               add("PRINT_ERROR(\"Try to cast on a dead cast type: %s\\n\", {t}->name);")
+               add_abort("cast type dead")
+               add("\}")
+       end
+
        redef fun init_instance(mtype)
        do
+               self.require_declaration("NEW_{mtype.mclass.c_name}")
                var compiler = self.compiler
                if mtype isa MGenericType and mtype.need_anchor then
+                       hardening_live_open_type(mtype)
                        link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
                        var recv = self.frame.arguments.first
                        var recv_type_info = self.type_info(recv)
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
-                       else
-                               return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
-                       end
+                       self.require_declaration(mtype.const_color)
+                       return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
                end
                compiler.undead_types.add(mtype)
-               return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
-       end
-
-       redef fun check_init_instance(value, mtype)
-       do
-               if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
-               self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
+               self.require_declaration("type_{mtype.c_name}")
+               return self.new_expr("NEW_{mtype.mclass.c_name}(&type_{mtype.c_name})", mtype)
        end
 
        redef fun type_test(value, mtype, tag)
@@ -1191,19 +1396,18 @@ class SeparateCompilerVisitor
 
                if ntype.need_anchor then
                        var type_struct = self.get_name("type_struct")
-                       self.add_decl("struct type* {type_struct};")
+                       self.add_decl("const struct type* {type_struct};")
 
                        # Either with resolution_table with a direct resolution
-                       link_unresolved_type(self.frame.mpropdef.mclassdef, ntype)
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               self.add("{type_struct} = {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {ntype.const_color})];")
-                       else
-                               self.add("{type_struct} = {recv_type_info}->resolution_table->types[{ntype.const_color}];")
-                       end
+                       hardening_live_open_type(mtype)
+                       link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
+                       self.require_declaration(mtype.const_color)
+                       self.add("{type_struct} = {recv_type_info}->resolution_table->types[{mtype.const_color}];")
                        if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
                                self.compiler.count_type_test_unresolved[tag] += 1
                                self.add("count_type_test_unresolved_{tag}++;")
                        end
+                       hardening_cast_type(type_struct)
                        self.add("{cltype} = {type_struct}->color;")
                        self.add("{idtype} = {type_struct}->id;")
                        if maybe_null and accept_null == "0" then
@@ -1214,6 +1418,8 @@ class SeparateCompilerVisitor
                        end
                else if ntype isa MClassType then
                        compiler.undead_types.add(mtype)
+                       self.require_declaration("type_{mtype.c_name}")
+                       hardening_cast_type("(&type_{mtype.c_name})")
                        self.add("{cltype} = type_{mtype.c_name}.color;")
                        self.add("{idtype} = type_{mtype.c_name}.id;")
                        if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
@@ -1221,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}\"); exit(1);")
+                       self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
                end
 
                # check color is in table
@@ -1231,9 +1437,6 @@ class SeparateCompilerVisitor
                        self.add("\} else \{")
                end
                var value_type_info = self.type_info(value)
-               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.add("{cltype} = HASH({value_type_info}->color, {idtype});")
-               end
                self.add("if({cltype} >= {value_type_info}->table_size) \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
@@ -1262,7 +1465,8 @@ class SeparateCompilerVisitor
                                self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
                        else
                                var mtype1 = value1.mtype.as(MClassType)
-                               self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */")
+                               self.require_declaration("class_{mtype1.c_name}")
+                               self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name}); /* is_same_type_test */")
                        end
                else
                        self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
@@ -1276,7 +1480,10 @@ class SeparateCompilerVisitor
                self.add_decl("const char* {res};")
                if value.mtype.ctype == "val*" then
                        self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;"
+               else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind then
+                       self.add "{res} = \"{value.mtype.as(MClassType).mclass}\";"
                else
+                       self.require_declaration("type_{value.mtype.c_name}")
                        self.add "{res} = type_{value.mtype.c_name}.name;"
                end
                return res
@@ -1297,7 +1504,8 @@ class SeparateCompilerVisitor
                                self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
                        else
                                var mtype1 = value1.mtype.as(MClassType)
-                               self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});")
+                               self.require_declaration("class_{mtype1.c_name}")
+                               self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name});")
                                self.add("if ({res}) \{")
                                self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
                                self.add("\}")
@@ -1355,12 +1563,12 @@ class SeparateCompilerVisitor
                        end
                end
                if primitive != null then
-                       test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
+                       test.add("((struct instance_{primitive.c_instance_name}*){value1})->value == ((struct instance_{primitive.c_instance_name}*){value2})->value")
                else if can_be_primitive(value1) and can_be_primitive(value2) then
                        test.add("{value1}->class == {value2}->class")
                        var s = new Array[String]
                        for t, v in self.compiler.box_kinds do
-                               s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
+                               s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_instance_name}*){value1})->value == ((struct instance_{t.c_instance_name}*){value2})->value)"
                        end
                        test.add("({s.join(" || ")})")
                else
@@ -1373,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*"
@@ -1400,43 +1607,45 @@ class SeparateCompilerVisitor
                        self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
                end
                self.send(self.get_property("with_native", arrayclass.intro.bound_mtype), [res, nat, length])
-               self.check_init_instance(res, arraytype)
                self.add("\}")
                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}")
                assert mtype isa MGenericType
                var compiler = self.compiler
                if mtype.need_anchor then
+                       hardening_live_open_type(mtype)
                        link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
                        var recv = self.frame.arguments.first
                        var recv_type_info = self.type_info(recv)
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
-                       else
-                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
-                       end
+                       self.require_declaration(mtype.const_color)
+                       return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
                end
                compiler.undead_types.add(mtype)
-               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) &type_{mtype.c_name})", mtype)
+               self.require_declaration("type_{mtype.c_name}")
+               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, &type_{mtype.c_name})", mtype)
        end
 
        redef fun native_array_def(pname, ret_type, arguments)
        do
                var elttype = arguments.first.mtype
                var nclass = self.get_class("NativeArray")
-               var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
+               var recv = "((struct instance_{nclass.c_instance_name}*){arguments[0]})->values"
                if pname == "[]" then
                        self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
                        return
                else if pname == "[]=" then
                        self.add("{recv}[{arguments[1]}]={arguments[2]};")
                        return
+               else if pname == "length" then
+                       self.ret(self.new_expr("((struct instance_{nclass.c_instance_name}*){arguments[0]})->length", ret_type.as(not null)))
+                       return
                else if pname == "copy_to" then
-                       var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
+                       var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values"
                        self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
                        return
                end
@@ -1460,6 +1669,30 @@ class SeparateCompilerVisitor
        end
 end
 
+redef class MMethodDef
+       fun separate_runtime_function: AbstractRuntimeFunction
+       do
+               var res = self.separate_runtime_function_cache
+               if res == null then
+                       res = new SeparateRuntimeFunction(self)
+                       self.separate_runtime_function_cache = res
+               end
+               return res
+       end
+       private var separate_runtime_function_cache: nullable SeparateRuntimeFunction
+
+       fun virtual_runtime_function: AbstractRuntimeFunction
+       do
+               var res = self.virtual_runtime_function_cache
+               if res == null then
+                       res = new VirtualRuntimeFunction(self)
+                       self.virtual_runtime_function_cache = res
+               end
+               return res
+       end
+       private var virtual_runtime_function_cache: nullable VirtualRuntimeFunction
+end
+
 # The C function associated to a methoddef separately compiled
 class SeparateRuntimeFunction
        super AbstractRuntimeFunction
@@ -1481,8 +1714,8 @@ class SeparateRuntimeFunction
 
                var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
 
-               var sig = new Buffer
-               var comment = new Buffer
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
                var ret = msignature.return_mtype
                if ret != null then
                        sig.append("{ret.ctype} ")
@@ -1494,7 +1727,7 @@ class SeparateRuntimeFunction
                end
                sig.append(self.c_name)
                sig.append("({selfvar.mtype.ctype} {selfvar}")
-               comment.append("(self: {selfvar}")
+               comment.append("({selfvar}: {selfvar.mtype}")
                arguments.add(selfvar)
                for i in [0..msignature.arity[ do
                        var mtype = msignature.mparameters[i].mtype
@@ -1511,7 +1744,7 @@ class SeparateRuntimeFunction
                if ret != null then
                        comment.append(": {ret}")
                end
-               compiler.header.add_decl("{sig};")
+               compiler.provide_declaration(self.c_name, "{sig};")
 
                v.add_decl("/* method {self} for {comment} */")
                v.add_decl("{sig} \{")
@@ -1530,6 +1763,7 @@ class SeparateRuntimeFunction
                        v.add("return {frame.returnvar.as(not null)};")
                end
                v.add("\}")
+               if not self.c_name.has_substring("VIRTUAL", 0) then compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})"
        end
 end
 
@@ -1553,8 +1787,8 @@ class VirtualRuntimeFunction
                var frame = new Frame(v, mmethoddef, recv, arguments)
                v.frame = frame
 
-               var sig = new Buffer
-               var comment = new Buffer
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
 
                # Because the function is virtual, the signature must match the one of the original class
                var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
@@ -1570,7 +1804,7 @@ class VirtualRuntimeFunction
                end
                sig.append(self.c_name)
                sig.append("({selfvar.mtype.ctype} {selfvar}")
-               comment.append("(self: {selfvar}")
+               comment.append("({selfvar}: {selfvar.mtype}")
                arguments.add(selfvar)
                for i in [0..msignature.arity[ do
                        var mtype = msignature.mparameters[i].mtype
@@ -1587,7 +1821,7 @@ class VirtualRuntimeFunction
                if ret != null then
                        comment.append(": {ret}")
                end
-               compiler.header.add_decl("{sig};")
+               compiler.provide_declaration(self.c_name, "{sig};")
 
                v.add_decl("/* method {self} for {comment} */")
                v.add_decl("{sig} \{")
@@ -1596,16 +1830,18 @@ class VirtualRuntimeFunction
                end
                frame.returnlabel = v.get_name("RET_LABEL")
 
-               if recv != arguments.first.mtype then
-                       #print "{self} {recv} {arguments.first}"
+               var subret = v.call(mmethoddef, recv, arguments)
+               if ret != null then
+                       assert subret != null
+                       v.assign(frame.returnvar.as(not null), subret)
                end
-               mmethoddef.compile_inside_to_c(v, arguments)
 
                v.add("{frame.returnlabel.as(not null)}:;")
                if ret != null then
                        v.add("return {frame.returnvar.as(not null)};")
                end
                v.add("\}")
+               if not self.c_name.has_substring("VIRTUAL", 0) then compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}--{mmethoddef.location.line_start})"
        end
 
        # TODO ?
@@ -1614,8 +1850,33 @@ end
 
 redef class MType
        fun const_color: String do return "COLOR_{c_name}"
+
+       # C name of the instance type to use
+       fun c_instance_name: String do return c_name
 end
 
+redef class MClassType
+       redef fun c_instance_name do return mclass.c_instance_name
+end
+
+redef class MClass
+       # Extern classes use the C instance of kernel::Pointer
+       fun c_instance_name: String
+       do
+               if kind == extern_kind then
+                       return "kernel__Pointer"
+               else return c_name
+       end
+end
+
+interface PropertyLayoutElement end
+
 redef class MProperty
+       super PropertyLayoutElement
+       fun const_color: String do return "COLOR_{c_name}"
+end
+
+redef class MPropDef
+       super PropertyLayoutElement
        fun const_color: String do return "COLOR_{c_name}"
 end