nitg*: extern classes a polymorph in Nit, and unboxed only for extern methods
[nit.git] / src / separate_compiler.nit
index 9996f43..43d06c2 100644 (file)
 # Separate compilation of a Nit program
 module separate_compiler
 
 # Separate compilation of a Nit program
 module separate_compiler
 
-
-import global_compiler # TODO better separation of concerns
+import abstract_compiler
 import coloring
 import coloring
+import rapid_type_analysis
 
 
+# Add separate compiler specific options
 redef class ToolContext
        # --separate
        var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
 redef class ToolContext
        # --separate
        var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
-
        # --no-inline-intern
        var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
        # --no-inline-intern
        var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
-
+       # --no-union-attribute
+       var opt_no_union_attribute: OptionBool = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
+       # --no-shortcut-equate
+       var opt_no_shortcut_equate: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
        # --inline-coloring-numbers
        # --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")
-
-       # --generic-resolution-tree
-       var opt_generic_tree: OptionBool = new OptionBool("Use tree representation for live generic types instead of flattened representation", "--generic-resolution-tree")
+       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")
 
        redef init
        do
                super
                self.option_context.add_option(self.opt_separate)
                self.option_context.add_option(self.opt_no_inline_intern)
 
        redef init
        do
                super
                self.option_context.add_option(self.opt_separate)
                self.option_context.add_option(self.opt_no_inline_intern)
-               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_generic_tree)
+               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, 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
        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
        do
                var time0 = get_time
-               self.toolcontext.info("*** COMPILING TO C ***", 1)
+               self.toolcontext.info("*** GENERATING C ***", 1)
 
 
-               var compiler = new SeparateCompiler(mainmodule, runtime_type_analysis, self)
+               var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
+               compiler.compile_header
 
                # compile class structures
 
                # 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
                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.compile_class_to_c(mclass)
                        end
                end
 
                # The main function of the C
+               compiler.new_file("{mainmodule.name}.main")
+               compiler.compile_nitni_global_ref_functions
                compiler.compile_main_function
                compiler.compile_main_function
+               compiler.compile_finalizer_function
 
                # compile methods
                for m in mainmodule.in_importation.greaters do
 
                # compile methods
                for m in mainmodule.in_importation.greaters do
+                       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.compile_module_to_c(m)
                end
 
                # compile live & cast type structures
+               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
                var mtypes = compiler.do_type_coloring
                for t in mtypes do
                        compiler.compile_type_to_c(t)
                end
-
-               if self.toolcontext.opt_generic_tree.value then
-                       # compile live generic types selection structures
-                       for mclass in model.mclasses do
-                               compiler.compile_live_gentype_to_c(mclass)
-                       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
 
                end
 
+               compiler.display_stats
+
+               var time1 = get_time
+               self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
                write_and_make(compiler)
        end
                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
 end
 
 # Singleton that store the knowledge about the separate compilation process
 class SeparateCompiler
-       super GlobalCompiler # TODO better separation of concerns
-
-       private var undead_types: Set[MType] = new HashSet[MType]
-       private var partial_types: Set[MType] = new HashSet[MType]
-       protected var typeids: HashMap[MType, Int] protected writable = new HashMap[MType, Int]
-
-       private var type_colors: Map[MType, Int] = typeids
-       private var type_tables: nullable Map[MType, Array[nullable MType]] = null
+       super AbstractCompiler
 
 
-       private var livetypes_colors: nullable Map[MType, Int]
-       private var livetypes_tables: nullable Map[MClass, Array[nullable Object]]
-       private var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
-       private var live_unanchored_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
+       redef type VISITOR: SeparateCompilerVisitor
 
 
-       private var unanchored_types_colors: nullable Map[MClassType, Int]
-       private var unanchored_types_tables: nullable Map[MClassType, Array[nullable MClassType]]
-       private var unanchored_types_masks: nullable Map[MClassType, Int]
+       # The result of the RTA (used to know live types and methods)
+       var runtime_type_analysis: nullable RapidTypeAnalysis
 
 
-       protected var class_coloring: ClassColoring
-
-       protected var method_colors: Map[MMethod, Int]
-       protected var method_tables: Map[MClass, Array[nullable MMethodDef]]
+       private var undead_types: Set[MType] = new HashSet[MType]
+       private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
 
 
+       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]
        protected var attr_colors: Map[MAttribute, Int]
-       protected var attr_tables: Map[MClass, Array[nullable MAttributeDef]]
 
 
-       protected var vt_colors: Map[MVirtualTypeProp, Int]
-       protected var vt_tables: Map[MClass, Array[nullable MVirtualTypeDef]]
-       protected var vt_masks: nullable Map[MClass, Int]
-
-       private var ft_colors: nullable Map[MParameterType, Int]
-       private var ft_tables: nullable Map[MClass, Array[nullable MParameterType]]
-       private var ft_masks: nullable Map[MClass, Int]
-
-       init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
-               self.do_property_coloring
+       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.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_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.header.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
-               self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
-
-               if modelbuilder.toolcontext.opt_generic_tree.value then
-                       self.header.add_decl("struct type \{ int id; int color; short int is_nullable; int livecolor; struct vts_table *vts_table; struct fts_table *fts_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
-               else
-                       self.header.add_decl("struct type \{ int id; int color; short int is_nullable; struct unanchored_table *unanchored_table; struct vts_table *vts_table; struct fts_table *fts_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
-               end
+               self.compile_header_attribute_structs
+               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; 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
 
 
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("struct fts_table \{ int mask; struct type *fts[1]; \}; /* fts list of a C type representation. */")
-                       self.header.add_decl("struct vts_table \{ int mask; struct type *vts[1]; \}; /* vts list of a C type representation. */")
-                       self.header.add_decl("struct unanchored_table \{ int mask; struct type *types[1]; \}; /* unanchored type list of a C type representation. */")
+       fun compile_header_attribute_structs
+       do
+               if modelbuilder.toolcontext.opt_no_union_attribute.value then
+                       self.header.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
                else
                else
-                       self.header.add_decl("struct fts_table \{ struct type *fts[1]; \}; /* fts list of a C type representation. */")
-                       self.header.add_decl("struct vts_table \{ struct type *vts[1]; \}; /* vts list of a C type representation. */")
-                       self.header.add_decl("struct unanchored_table \{ struct type *types[1]; \}; /* unanchored type list of a C type representation. */")
-               end
+                       self.header.add_decl("typedef union \{")
+                       self.header.add_decl("void* val;")
+                       for c, v in self.box_kinds do
+                               var t = c.mclass_type
 
 
+                               # `Pointer` reuse the `val` field
+                               if t.mclass.name == "Pointer" then continue
 
 
-               self.header.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
-       end
-
-       redef fun compile_class_names do
-               # Build type names table
-               var type_array = new Array[nullable MType]
-               for t, id in typeids do
-                       if id >= type_array.length then
-                               for i in [type_array.length..id[ do
-                                       type_array[i] = null
-                               end
-                       end
-                       type_array[id] = t
-               end
-
-               var v = self.new_visitor
-               self.header.add_decl("extern const char const * class_names[];")
-               v.add("const char const * class_names[] = \{")
-               for t in type_array do
-                       if t == null then
-                               v.add("NULL,")
-                       else
-                               v.add("\"{t}\",")
+                               self.header.add_decl("{t.ctype_extern} {t.ctypename};")
                        end
                        end
+                       self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */")
                end
                end
-               v.add("\};")
        end
 
        fun compile_box_kinds
        end
 
        fun compile_box_kinds
@@ -201,9 +217,11 @@ class SeparateCompiler
 
        fun box_kind_of(mclass: MClass): Int
        do
 
        fun box_kind_of(mclass: MClass): Int
        do
-               if mclass.mclass_type.ctype == "val*" then
+               #var pointer_type = self.mainmodule.pointer_type
+               #if mclass.mclass_type.ctype == "val*" or mclass.mclass_type.is_subtype(self.mainmodule, mclass.mclass_type pointer_type) then
+               if mclass.mclass_type.ctype_extern == "val*" then
                        return 0
                        return 0
-               else if mclass.kind == extern_kind then
+               else if mclass.kind == extern_kind and mclass.name != "NativeString" then
                        return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
                else
                        return self.box_kinds[mclass]
                        return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
                else
                        return self.box_kinds[mclass]
@@ -212,540 +230,437 @@ class SeparateCompiler
        end
 
        fun compile_color_consts(colors: Map[Object, Int]) do
        end
 
        fun compile_color_consts(colors: Map[Object, Int]) do
+               var v = new_visitor
                for m, c in colors do
                for m, c in colors do
-                       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
-                       end
+                       compile_color_const(v, m, c)
                end
        end
 
                end
        end
 
-       # colorize classe properties
-       fun do_property_coloring do
-
-               # classes coloration
-               self.class_coloring = new ClassColoring(mainmodule)
-               class_coloring.colorize(modelbuilder.model.mclasses)
-
-               # methods coloration
-               var method_coloring = new MethodColoring(self.class_coloring)
-               self.method_colors = method_coloring.colorize
-               self.method_tables = method_coloring.build_property_tables
-               self.compile_color_consts(self.method_colors)
-
-               # attributes coloration
-               var attribute_coloring = new AttributeColoring(self.class_coloring)
-               self.attr_colors = attribute_coloring.colorize
-               self.attr_tables = attribute_coloring.build_property_tables
-               self.compile_color_consts(self.attr_colors)
-
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       self.class_coloring = new NaiveClassColoring(mainmodule)
-                       self.class_coloring.colorize(modelbuilder.model.mclasses)
-               end
-
-               # vt coloration
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       var vt_coloring = new NaiveVTColoring(self.class_coloring)
-                       self.vt_colors = vt_coloring.colorize
-                       self.vt_tables = vt_coloring.build_property_tables
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       var vt_coloring = new VTModPerfectHashing(self.class_coloring)
-                       self.vt_colors = vt_coloring.colorize
-                       self.vt_masks = vt_coloring.compute_masks
-                       self.vt_tables = vt_coloring.build_property_tables
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       var vt_coloring = new VTAndPerfectHashing(self.class_coloring)
-                       self.vt_colors = vt_coloring.colorize
-                       self.vt_masks = vt_coloring.compute_masks
-                       self.vt_tables = vt_coloring.build_property_tables
-               else
-                       var vt_coloring = new VTColoring(self.class_coloring)
-                       self.vt_colors = vt_coloring.colorize
-                       self.vt_tables = vt_coloring.build_property_tables
+       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
                end
                end
-               self.compile_color_consts(self.vt_colors)
+               color_consts_done.add(m)
        end
 
        end
 
-       # colorize live types of the program
-       private fun do_type_coloring: Set[MType] do
-               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)
+       private var color_consts_done = new HashSet[Object]
 
 
-               for mtype in mtypes do
-                       retieve_live_partial_types(mtype)
-               end
-               mtypes.add_all(self.partial_types)
+       # colorize classe properties
+       fun do_property_coloring do
 
 
-               # set type unique id
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       var sorted_mtypes = new OrderedSet[MType].from(mtypes)
-                       sorted_mtypes.linearize(new ReverseTypeSorter(self.mainmodule))
-                       for mtype in sorted_mtypes do
-                               self.typeids[mtype] = self.typeids.length + 1
+               var rta = runtime_type_analysis
+
+               # Layouts
+               var poset = mainmodule.flatten_mclass_hierarchy
+               var mclasses = new HashSet[MClass].from(poset)
+               var colorer = new POSetColorer[MClass]
+               colorer.colorize(poset)
+
+               # The dead methods, still need to provide a dead color symbol
+               var dead_methods = new Array[MMethod]
+
+               # 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
-               else
-                       for mtype in mtypes do
-                               self.typeids[mtype] = self.typeids.length
+               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
 
                        end
                end
 
-               # fts coloration for non-erased compilation
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       var ft_coloring = new NaiveFTColoring(self.class_coloring)
-                       self.ft_colors = ft_coloring.colorize
-                       self.ft_tables = ft_coloring.build_ft_tables
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       var ft_coloring = new FTModPerfectHashing(self.class_coloring)
-                       self.ft_colors = ft_coloring.colorize
-                       self.ft_masks = ft_coloring.compute_masks
-                       self.ft_tables = ft_coloring.build_ft_tables
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       var ft_coloring = new FTAndPerfectHashing(self.class_coloring)
-                       self.ft_colors = ft_coloring.colorize
-                       self.ft_masks = ft_coloring.compute_masks
-                       self.ft_tables = ft_coloring.build_ft_tables
+               # 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
                else
-                       var ft_coloring = new FTColoring(self.class_coloring)
-                       self.ft_colors = ft_coloring.colorize
-                       self.ft_tables = ft_coloring.build_ft_tables
+                       super_calls = all_super_calls
                end
                end
-               self.compile_color_consts(self.ft_colors.as(not null))
 
 
-               if modelbuilder.toolcontext.opt_generic_tree.value then
-                       # colorize live entries
-                       var entries_coloring
-                       if modelbuilder.toolcontext.opt_bm_typing.value then
-                               entries_coloring = new NaiveLiveEntryColoring
-                       else
-                               entries_coloring = new LiveEntryColoring
+               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
-                       self.livetypes_colors = entries_coloring.colorize(mtypes)
-                       self.livetypes_tables = entries_coloring.build_livetype_tables(mtypes)
-                       self.livetypes_tables_sizes = entries_coloring.livetypes_tables_sizes
-               else
-                       self.compile_unanchored_tables(mtypes)
-               end
-
-               # colorize types
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       var type_coloring = new NaiveTypeColoring(self.mainmodule, mtypes)
-                       self.type_colors = type_coloring.colorize(mtypes)
-                       self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       var type_coloring = new TypeModPerfectHashing(self.mainmodule, mtypes)
-                       self.type_colors = type_coloring.compute_masks(mtypes, typeids)
-                       self.type_tables = type_coloring.hash_type_tables(mtypes, typeids, type_colors)
-
-                       self.header.add_decl("int HASH(int, int);")
-                       var v = new_visitor
-                       v.add_decl("int HASH(int mask, int id) \{")
-                       v.add_decl("return mask % id;")
-                       v.add_decl("\}")
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       var type_coloring = new TypeAndPerfectHashing(self.mainmodule, mtypes)
-                       self.type_colors = type_coloring.compute_masks(mtypes, typeids)
-                       self.type_tables = type_coloring.hash_type_tables(mtypes, typeids, type_colors)
-
-                       self.header.add_decl("int HASH(int, int);")
-                       var v = new_visitor
-                       v.add_decl("int HASH(int mask, int id) \{")
-                       v.add_decl("return mask & id;")
-                       v.add_decl("\}")
-               else
-                       var type_coloring = new TypeColoring(self.mainmodule, mtypes)
-                       self.type_colors = type_coloring.colorize(mtypes)
-                       self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
                end
 
                end
 
+               # methods coloration
+               var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts)
+               method_colors = meth_colorer.colorize(mmethods)
+               method_tables = build_method_tables(mclasses, super_calls)
+               compile_color_consts(method_colors)
 
 
-               # for the class_name and output_class_name methods
-               self.compile_class_names
+               # 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
 
 
-               return mtypes
+               # attributes coloration
+               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
 
        end
 
-       protected fun compile_unanchored_tables(mtypes: Set[MType]) do
-               var mtype2anchored = new HashMap[MClassType, Set[MClassType]]
-
-               for mtype in self.runtime_type_analysis.live_types do
-                       for cd in mtype.collect_mclassdefs(self.mainmodule) do
-                               if self.live_unanchored_types.has_key(cd) then
-                                       if not mtype2anchored.has_key(mtype) then
-                                               mtype2anchored[mtype] = new HashSet[MClassType]
+       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]
+                       tables[mclass] = table
+
+                       var mproperties = self.mainmodule.properties(mclass)
+                       var mtype = mclass.intro.bound_mtype
+
+                       for mproperty in mproperties do
+                               if not mproperty isa MMethod then continue
+                               if not method_colors.has_key(mproperty) then continue
+                               var color = method_colors[mproperty]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
                                        end
                                        end
-                                       for unanchored in self.live_unanchored_types[cd] do
-                                               var anchored = unanchored.anchor_to(self.mainmodule, mtype)
-                                               if anchored isa MClassType then
-                                                       mtype2anchored[mtype].add(anchored)
-                                               else if anchored isa MNullableType then
-                                                       mtype2anchored[mtype].add(anchored.mtype.as(MClassType))
-                                               else
-                                                       print "NOT YET IMPLEMENTED: try compile_unanchored_tables with {unanchored}"
-                                               end
+                               end
+                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
+                       end
+
+                       for supercall in super_calls do
+                               if not mtype.collect_mclassdefs(mainmodule).has(supercall.mclassdef) then continue
+
+                               var color = method_colors[supercall]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
                                        end
                                end
                                        end
                                end
+                               var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype)
+                               table[color] = mmethoddef
                        end
                        end
-               end
 
 
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       var unanchored_type_coloring = new NaiveUnanchoredTypeColoring
-                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2anchored)
-                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2anchored)
-               else if modelbuilder.toolcontext.opt_phmod_typing.value then
-                       var unanchored_type_coloring = new UnanchoredTypeModPerfectHashing
-                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2anchored)
-                       self.unanchored_types_masks = unanchored_type_coloring.compute_masks(mtype2anchored)
-                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2anchored)
-               else if modelbuilder.toolcontext.opt_phand_typing.value then
-                       var unanchored_type_coloring = new UnanchoredTypeAndPerfectHashing
-                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2anchored)
-                       self.unanchored_types_masks = unanchored_type_coloring.compute_masks(mtype2anchored)
-                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2anchored)
-               else
-                       var unanchored_type_coloring = new UnanchoredTypeColoring
-                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2anchored)
-                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2anchored)
                end
                end
+               return tables
+       end
 
 
-               var unanchored_mtypes = new HashMap[MType, Int]
-               for mclass in modelbuilder.model.mclasses do
-                       var mtype = mclass.mclass_type
-                       if unanchored_types_colors.has_key(mtype) then
-                               unanchored_mtypes[mtype] = unanchored_types_colors[mtype]
-                       else
-                               unanchored_mtypes[mtype] = -1
+       fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
+               var tables = new HashMap[MClass, Array[nullable MPropDef]]
+               for mclass in mclasses do
+                       var table = new Array[nullable MPropDef]
+                       tables[mclass] = table
+
+                       var mproperties = self.mainmodule.properties(mclass)
+                       var mtype = mclass.intro.bound_mtype
+
+                       for mproperty in mproperties do
+                               if not mproperty isa MAttribute then continue
+                               if not attr_colors.has_key(mproperty) then continue
+                               var color = attr_colors[mproperty]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
                        end
                end
                        end
                end
-               for mtype, color in unanchored_types_colors.as(not null) do
-                       unanchored_mtypes[mtype] = color
+               return tables
+       end
+
+       # colorize live types of the program
+       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(live_types)
+               mtypes.add_all(live_cast_types)
+               for c in self.box_kinds.keys do
+                       mtypes.add(c.mclass_type)
                end
                end
-               self.compile_color_consts(unanchored_mtypes)
 
 
-               #print "tables"
-               #for k, v in unanchored_types_tables.as(not null) do
-               #       print "{k}: {v.join(", ")}"
-               #end
-               #print ""
+               # 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 poset
        end
 
        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
+       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
-                               self.partial_types.add(ft)
-                               retieve_live_partial_types(ft)
                        end
                end
                        end
                end
-               var mclass_type: MClassType
-               if mtype isa MNullableType then
-                       mclass_type = mtype.mtype.as(MClassType)
-               else
-                       mclass_type = mtype.as(MClassType)
-               end
+               return poset
+       end
 
 
-               # add virtual types to mtypes
-               for vt in self.vt_tables[mclass_type.mclass] do
-                       if vt != null then
-                               var anchored = vt.bound.anchor_to(self.mainmodule, mclass_type)
-                               self.partial_types.add(anchored)
+       # Build type tables
+       fun build_type_tables(mtypes: POSet[MType]): Map[MType, Array[nullable MType]] do
+               var tables = new HashMap[MType, Array[nullable MType]]
+               for mtype in mtypes do
+                       var table = new Array[nullable MType]
+                       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
+                                       end
+                               end
+                               table[color] = sup
                        end
                        end
+                       tables[mtype] = table
                end
                end
+               return tables
        end
 
        end
 
-       # declare live generic types tables selection
-       private fun compile_live_gentype_to_c(mclass: MClass) do
-               if mclass.arity > 0 then
-                       if self.livetypes_tables.has_key(mclass) then
-                               var table = self.livetypes_tables[mclass]
-                               var sign = self.livetypes_tables_sizes[mclass]
-                               var table_buffer = new Buffer.from("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}] = \{\n")
-                               compile_livetype_table(table, table_buffer, 1, mclass.arity)
-                               table_buffer.append("\};")
-
-                               var v = new SeparateCompilerVisitor(self)
-                               self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
-                               v.add_decl(table_buffer.to_s)
+       protected fun compile_resolution_tables(mtypes: Set[MType]) do
+               # resolution_tables is used to perform a type resolution at runtime in O(1)
+
+               # During the visit of the body of classes, live_unresolved_types are collected
+               # and associated to
+               # Collect all live_unresolved_types (visited in the body of classes)
+
+               # Determinate fo each livetype what are its possible requested anchored types
+               var mtype2unresolved = new HashMap[MClassType, Set[MType]]
+               for mtype in self.runtime_type_analysis.live_types do
+                       var set = new HashSet[MType]
+                       for cd in mtype.collect_mclassdefs(self.mainmodule) do
+                               if self.live_unresolved_types.has_key(cd) then
+                                       set.add_all(self.live_unresolved_types[cd])
+                               end
+                       end
+                       mtype2unresolved[mtype] = set
+               end
+
+               # Compute the table layout with the prefered method
+               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)
+               var all_unresolved = new HashSet[MType]
+               for t in self.live_unresolved_types.values do
+                       all_unresolved.add_all(t)
+               end
+               var all_unresolved_types_colors = new HashMap[MType, Int]
+               for t in all_unresolved do
+                       if opentype_colors.has_key(t) then
+                               all_unresolved_types_colors[t] = opentype_colors[t]
                        else
                        else
-                               var sign = new Array[Int].filled_with(0, mclass.arity)
-                               var v = new SeparateCompilerVisitor(self)
-                               self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
-                               v.add_decl("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
+                               all_unresolved_types_colors[t] = -1
                        end
                end
                        end
                end
+               self.compile_color_consts(all_unresolved_types_colors)
+
+               #print "tables"
+               #for k, v in unresolved_types_tables.as(not null) do
+               #       print "{k}: {v.join(", ")}"
+               #end
+               #print ""
        end
 
        end
 
-       private fun compile_livetype_table(table: Array[nullable Object], buffer: Buffer, depth: Int, max: Int) do
-               for obj in table do
-                       if obj == null then
-                               if depth == max then
-                                       buffer.append("NULL,\n")
-                               else
-                                       buffer.append("\{\},\n")
+       fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+               var tables = new HashMap[MClassType, Array[nullable MType]]
+               for mclasstype, mtypes in elements do
+                       var table = new Array[nullable MType]
+                       for mtype in mtypes do
+                               var color = opentype_colors[mtype]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
                                end
                                end
-                       else if obj isa MClassType then
-                               buffer.append("(struct type*) &type_{obj.c_name}, /* {obj} */\n")
-                       else if obj isa Array[nullable Object] then
-                               buffer.append("\{\n")
-                               compile_livetype_table(obj, buffer, depth + 1, max)
-                               buffer.append("\},\n")
+                               table[color] = mtype
                        end
                        end
+                       tables[mclasstype] = table
                end
                end
+               return tables
        end
 
        # Separately compile all the method definitions of the module
        fun compile_module_to_c(mmodule: MModule)
        do
        end
 
        # Separately compile all the method definitions of the module
        fun compile_module_to_c(mmodule: MModule)
        do
+               var old_module = self.mainmodule
+               self.mainmodule = mmodule
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
+                               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}"
                                #print "compile {pd} @ {cd} @ {mmodule}"
-                               var r = new SeparateRuntimeFunction(pd)
+                               var r = pd.separate_runtime_function
                                r.compile_to_c(self)
                                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
                        end
                end
+               self.mainmodule = old_module
        end
 
        # Globaly compile the type structure of a live type
        fun compile_type_to_c(mtype: MType)
        do
        end
 
        # 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
                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("int color;")
-               self.header.add_decl("short int is_nullable;")
-               if modelbuilder.toolcontext.opt_generic_tree.value then
-                       self.header.add_decl("int livecolor;")
-               else
-                       self.header.add_decl("const struct unanchored_table_{c_name} *types;")
-               end
-               self.header.add_decl("const struct vts_table_{c_name} *vts_table;")
-               self.header.add_decl("const struct fts_table_{c_name} *fts_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
 
                # const struct type_X
-               v.add_decl("const struct type_{c_name} type_{c_name} = \{")
-               v.add_decl("{self.typeids[mtype]},")
-               v.add_decl("{self.type_colors[mtype]},")
-               if mtype isa MNullableType then
-                       v.add_decl("1,")
-               else
-                       v.add_decl("0,")
-               end
-               if modelbuilder.toolcontext.opt_generic_tree.value then
-                       v.add_decl("{self.livetypes_colors[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
                else
-                       if (not mtype isa MNullableType and self.unanchored_types_tables.has_key(mtype.as(MClassType))) or (mtype isa MNullableType and self.unanchored_types_tables.has_key(mtype.mtype.as(MClassType))) then
-                               v.add_decl("&unanchored_table_{c_name},")
-                       else
-                               v.add_decl("NULL,")
-                       end
-               end
-               v.add_decl("&vts_table_{c_name},")
-               v.add_decl("&fts_table_{c_name},")
-               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.typeids[stype]}, /* {stype} */")
-                       end
+                       v.add_decl("-1, /*CAST DEAD*/")
                end
                end
-               v.add_decl("\},")
-               v.add_decl("\};")
 
 
-               compile_type_fts_table(mtype)
-               compile_type_vts_table(mtype)
-               compile_type_unanchored_table(mtype)
-       end
+               # type name
+               v.add_decl("\"{mtype}\", /* class_name_string */")
 
 
-       protected fun compile_type_fts_table(mtype: MType) do
+               # type color (for cast target)
+               if is_cast_live then
+                       v.add_decl("{type_colors[mtype]},")
+               else
+                       v.add_decl("-1, /*CAST DEAD*/")
+               end
 
 
-               var mclass_type: MClassType
+               # is_nullable bit
                if mtype isa MNullableType then
                if mtype isa MNullableType then
-                       mclass_type = mtype.mtype.as(MClassType)
+                       v.add_decl("1,")
                else
                else
-                       mclass_type = mtype.as(MClassType)
+                       v.add_decl("0,")
                end
 
                end
 
-               # extern const struct fst_table_X fst_table_X
-               self.header.add_decl("extern const struct fts_table_{mtype.c_name} fts_table_{mtype.c_name};")
-               self.header.add_decl("struct fts_table_{mtype.c_name} \{")
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("int mask;")
+               # 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, /*DEAD*/")
                end
                end
-               self.header.add_decl("struct type *fts[{self.ft_tables[mclass_type.mclass].length}];")
-               self.header.add_decl("\};")
 
 
-               # const struct fts_table_X fts_table_X
-               var v = new_visitor
-               v.add_decl("const struct fts_table_{mtype.c_name} fts_table_{mtype.c_name} = \{")
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       v.add_decl("{self.ft_masks[mclass_type.mclass]},")
-               end
-               v.add_decl("\{")
-               for ft in self.ft_tables[mclass_type.mclass] do
-                       if ft == null then
-                               v.add_decl("NULL, /* empty */")
-                       else
-                               var ntype: MType
-                               if ft.mclass == mclass_type.mclass then
-                                       ntype = mclass_type.arguments[ft.rank]
-                               else
-                                       ntype = ft.anchor_to(self.mainmodule, mclass_type)
-                               end
-                               if self.typeids.has_key(ntype) then
-                                       v.add_decl("(struct type*)&type_{ntype.c_name}, /* {ft} ({ntype}) */")
+               # 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
                                else
-                                       v.add_decl("NULL, /* empty ({ft} not a live type) */")
+                                       v.add_decl("{type_ids[stype]}, /* {stype} */")
                                end
                        end
                                end
                        end
+                       v.add_decl("\},")
+               else
+                       v.add_decl("0, \{\}, /*DEAD TYPE*/")
                end
                end
-               v.add_decl("\},")
                v.add_decl("\};")
        end
 
                v.add_decl("\};")
        end
 
-       protected fun compile_type_vts_table(mtype: MType) 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
+               var mclass_type = mtype.as_notnullable.as(MClassType)
 
 
-               # extern const struct vts_table_X vts_table_X
-               self.header.add_decl("extern const struct vts_table_{mtype.c_name} vts_table_{mtype.c_name};")
-               self.header.add_decl("struct vts_table_{mtype.c_name} \{")
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("int mask;")
-               end
-               self.header.add_decl("struct type *vts[{self.vt_tables[mclass_type.mclass].length}];")
-               self.header.add_decl("\};")
+               # extern const struct resolution_table_X resolution_table_X
+               self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
 
 
-               # const struct vts_table_X vts_table_X
+               # const struct fts_table_X fts_table_X
                var v = new_visitor
                var v = new_visitor
-               v.add_decl("const struct vts_table_{mtype.c_name} vts_table_{mtype.c_name} = \{")
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       v.add_decl("{vt_masks[mclass_type.mclass]},")
-               end
+               v.add_decl("const struct types resolution_table_{mtype.c_name} = \{")
+               v.add_decl("0, /* dummy */")
                v.add_decl("\{")
                v.add_decl("\{")
-
-               for vt in self.vt_tables[mclass_type.mclass] do
-                       if vt == null then
+               for t in self.resolution_tables[mclass_type] do
+                       if t == null then
                                v.add_decl("NULL, /* empty */")
                        else
                                v.add_decl("NULL, /* empty */")
                        else
-                               var bound = vt.bound
-                               if bound == null then
-                                       #FIXME how can a bound be null here ?
-                                       print "No bound found for virtual type {vt} ?"
-                                       abort
+                               # The table stores the result of the type resolution
+                               # Therefore, for a receiver `mclass_type`, and a unresolved type `t`
+                               # 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 type_ids.has_key(tv) then
+                                       v.require_declaration("type_{tv.c_name}")
+                                       v.add_decl("&type_{tv.c_name}, /* {t}: {tv} */")
                                else
                                else
-                                       var is_nullable = ""
-                                       if bound isa MNullableType then
-                                               bound = bound.mtype
-                                               is_nullable = "nullable_"
-                                       end
-                                       if bound isa MVirtualType then
-                                               bound = bound.anchor_to(self.mainmodule, mclass_type)
-                                       else if bound isa MParameterType then
-                                               bound = bound.anchor_to(self.mainmodule, mclass_type)
-                                       else if bound isa MGenericType and bound.need_anchor then
-                                               bound = bound.anchor_to(self.mainmodule, mclass_type)
-                                       else if bound isa MClassType then
-                                       else
-                                               print "NOT YET IMPLEMENTED: mtype_to_livetype with type: {bound}"
-                                               abort
-                                       end
-
-                                       if self.typeids.has_key(bound) then
-                                               v.add_decl("(struct type*)&type_{is_nullable}{bound.c_name}, /* {bound} */")
-                                       else
-                                               v.add_decl("NULL, /* dead type {bound} */")
-                                       end
+                                       v.add_decl("NULL, /* empty ({t}: {tv} not a live type) */")
                                end
                        end
                end
                                end
                        end
                end
-               v.add_decl("\},")
+               v.add_decl("\}")
                v.add_decl("\};")
        end
 
                v.add_decl("\};")
        end
 
-       fun compile_type_unanchored_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
-
-               # extern const struct unanchored_table_X unanchored_table_X
-               self.header.add_decl("extern const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name};")
-
-               self.header.add_decl("struct unanchored_table_{mtype.c_name} \{")
-               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.header.add_decl("int mask;")
-               end
-               if not self.unanchored_types_tables.has_key(mclass_type) then
-                       self.header.add_decl("struct type *types[0];")
-               else
-                       self.header.add_decl("struct type *types[{self.unanchored_types_tables[mclass_type].length}];")
-               end
-               self.header.add_decl("\};")
-
-               if self.unanchored_types_tables.has_key(mclass_type) then
-                       # const struct fts_table_X fts_table_X
-                       var v = new_visitor
-                       v.add_decl("const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name} = \{")
-                       if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                               v.add_decl("{self.unanchored_types_masks[mclass_type]},")
-                       end
-                       v.add_decl("\{")
-                       for t in self.unanchored_types_tables[mclass_type] do
-                               if t == null then
-                                       v.add_decl("NULL, /* empty */")
-                               else
-                                       if self.typeids.has_key(t) then
-                                               v.add_decl("(struct type*)&type_{t.c_name}, /* {t} */")
-                                       else
-                                               v.add_decl("NULL, /* empty ({t} not a live type) */")
-                                       end
-                               end
-                       end
-                       v.add_decl("\},")
-                       v.add_decl("\};")
-               end
-       end
-
        # Globally compile the table of the class mclass
        # In a link-time optimisation compiler, tables are globally computed
        # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
        # Globally compile the table of the class mclass
        # In a link-time optimisation compiler, tables are globally computed
        # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
@@ -758,286 +673,278 @@ class SeparateCompiler
                var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
                var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
-               v.add_decl("/* runtime class {c_name} */")
-               var idnum = classids.length
-               var idname = "ID_" + c_name
-               self.classids[mtype] = idname
-               #self.header.add_decl("#define {idname} {idnum} /* {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" and mclass.name != "Pointer"
 
 
-               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
 
                # 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
                                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
                                end
                        end
+                       v.add_decl("\}")
+                       v.add_decl("\};")
                end
                end
-               v.add_decl("\}")
-               v.add_decl("\};")
 
 
-               if mtype.ctype != "val*" then
+               if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then
+                       # Is a primitive type or the Pointer class, not any other extern class
+
                        #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;")
                        #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("{mtype.ctype_extern} value;")
                        self.header.add_decl("\};")
 
                        self.header.add_decl("\};")
 
-                       if not self.runtime_type_analysis.live_types.has(mtype) then return
+                       if not rta.live_types.has(mtype) and mtype.mclass.name != "Pointer" 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_extern});")
                        v.add_decl("/* allocate {mtype} */")
                        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_decl("val* BOX_{mtype.c_name}({mtype.ctype_extern} value) \{")
+                       v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
+                       v.compiler.undead_types.add(mtype)
+                       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("\}")
                        v.add("res->value = value;")
                        v.add("return (val*)res;")
                        v.add("\}")
+
+                       if mtype.mclass.name != "Pointer" then return
+
+                       v = new_visitor
+                       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_{mtype.c_name}));")
+                               v.add("{res}->type = type;")
+                               hardening_live_type(v, "type")
+                               v.require_declaration("class_{c_name}")
+                               v.add("{res}->class = &class_{c_name};")
+                               v.add("((struct instance_{mtype.c_name}*){res})->value = NULL;")
+                               v.add("return {res};")
+                       end
+                       v.add("\}")
                        return
                        return
-               end
+               else if mclass.name == "NativeArray" 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;")
+                       # 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];")
+                       self.header.add_decl("\};")
 
 
-               var is_native_array = mclass.name == "NativeArray"
+                       #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_name} *{res};")
+                       var mtype_elt = mtype.arguments.first
+                       v.add("{res} = nit_alloc(sizeof(struct instance_{c_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
+               else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
+                       # Is an extern class (other than Pointer and NativeString)
+                       # Pointer is caught in a previous `if`, and NativeString is internal
 
 
-               var sig
-               if is_native_array then
-                       sig = "int length, struct type* type"
-               else
-                       sig = "struct type* type"
-               end
+                       var pointer_type = mainmodule.pointer_type
 
 
-               #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
-                       self.header.add_decl("val* values[0];")
+                       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_{pointer_type.c_name}));")
+                               v.add("{res}->type = type;")
+                               hardening_live_type(v, "type")
+                               v.require_declaration("class_{c_name}")
+                               v.add("{res}->class = &class_{c_name};")
+                               v.add("((struct instance_{pointer_type.c_name}*){res})->value = NULL;")
+                               v.add("return {res};")
+                       end
+                       v.add("\}")
+                       return
                end
                end
-               self.header.add_decl("\};")
-
 
 
-               self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
+               #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("/* 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
-                       var mtype_elt = mtype.arguments.first
-                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
+               v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
+               if is_dead then
+                       v.add_abort("{mclass} is DEAD")
                else
                else
-                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
+                       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
                end
-               #v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
-               v.add("{res}->type = type;")
-               v.add("{res}->class = (struct class*) &class_{c_name};")
-
-               self.generate_init_attr(v, res, mtype)
-               v.add("return {res};")
                v.add("\}")
                v.add("\}")
-
-               generate_check_init_instance(mtype)
        end
 
        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
        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
 
        redef fun new_visitor do return new SeparateCompilerVisitor(self)
                v.add("\}")
        end
 
        redef fun new_visitor do return new SeparateCompilerVisitor(self)
-end
 
 
-# The C function associated to a methoddef separately compiled
-class SeparateRuntimeFunction
-       super AbstractRuntimeFunction
+       # Stats
+
+       private var type_tables: Map[MType, Array[nullable MType]] = new HashMap[MType, Array[nullable MType]]
+       private var resolution_tables: Map[MClassType, Array[nullable MType]] = new HashMap[MClassType, Array[nullable MType]]
+       protected var method_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
+       protected var attr_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
 
 
-       redef fun build_c_name: String
+       redef fun display_stats
        do
        do
-               return "{mmethoddef.c_name}"
+               super
+               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
 
        end
 
-       redef fun to_s do return self.mmethoddef.to_s
-
-       redef fun compile_to_c(compiler)
+       fun display_sizes
        do
        do
-               var mmethoddef = self.mmethoddef
-
-               var recv = self.mmethoddef.mclassdef.bound_mtype
-               var v = compiler.new_visitor
-               var selfvar = new RuntimeVariable("self", recv, recv)
-               var arguments = new Array[RuntimeVariable]
-               var frame = new Frame(v, mmethoddef, recv, arguments)
-               v.frame = frame
-
-               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 ret = msignature.return_mtype
-               if ret != null then
-                       sig.append("{ret.ctype} ")
-               else if mmethoddef.mproperty.is_new then
-                       ret = recv
-                       sig.append("{ret.ctype} ")
-               else
-                       sig.append("void ")
-               end
-               sig.append(self.c_name)
-               sig.append("({selfvar.mtype.ctype} {selfvar}")
-               comment.append("(self: {selfvar}")
-               arguments.add(selfvar)
-               for i in [0..msignature.arity[ do
-                       var mtype = msignature.mparameters[i].mtype
-                       if i == msignature.vararg_rank then
-                               mtype = v.get_class("Array").get_mtype([mtype])
-                       end
-                       comment.append(", {mtype}")
-                       sig.append(", {mtype.ctype} p{i}")
-                       var argvar = new RuntimeVariable("p{i}", mtype, mtype)
-                       arguments.add(argvar)
-               end
-               sig.append(")")
-               comment.append(")")
-               if ret != null then
-                       comment.append(": {ret}")
-               end
-               compiler.header.add_decl("{sig};")
-
-               v.add_decl("/* method {self} for {comment} */")
-               v.add_decl("{sig} \{")
-               if ret != null then
-                       frame.returnvar = v.new_var(ret)
-               end
-               frame.returnlabel = v.get_name("RET_LABEL")
-
-               if recv != arguments.first.mtype then
-                       #print "{self} {recv} {arguments.first}"
-               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("\}")
+               print "# size of subtyping tables"
+               print "\ttotal \tholes"
+               var total = 0
+               var holes = 0
+               for t, table in type_tables do
+                       total += table.length
+                       for e in table do if e == null then holes += 1
+               end
+               print "\t{total}\t{holes}"
+
+               print "# size of resolution tables"
+               print "\ttotal \tholes"
+               total = 0
+               holes = 0
+               for t, table in resolution_tables do
+                       total += table.length
+                       for e in table do if e == null then holes += 1
+               end
+               print "\t{total}\t{holes}"
+
+               print "# size of methods tables"
+               print "\ttotal \tholes"
+               total = 0
+               holes = 0
+               for t, table in method_tables do
+                       total += table.length
+                       for e in table do if e == null then holes += 1
+               end
+               print "\t{total}\t{holes}"
+
+               print "# size of attributes tables"
+               print "\ttotal \tholes"
+               total = 0
+               holes = 0
+               for t, table in attr_tables do
+                       total += table.length
+                       for e in table do if e == null then holes += 1
+               end
+               print "\t{total}\t{holes}"
        end
        end
-end
 
 
-# The C function associated to a methoddef on a primitive type, stored into a VFT of a class
-# The first parameter (the reciever) is always typed by val* in order to accept an object value
-class VirtualRuntimeFunction
-       super AbstractRuntimeFunction
+       protected var isset_checks_count = 0
+       protected var attr_read_count = 0
 
 
-       redef fun build_c_name: String
-       do
-               return "VIRTUAL_{mmethoddef.c_name}"
+       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
 
        end
 
-       redef fun to_s do return self.mmethoddef.to_s
-
-       redef fun compile_to_c(compiler)
+       redef fun compile_nitni_structs
        do
        do
-               var mmethoddef = self.mmethoddef
-
-               var recv = self.mmethoddef.mclassdef.bound_mtype
-               var v = compiler.new_visitor
-               var selfvar = new RuntimeVariable("self", v.object_type, recv)
-               var arguments = new Array[RuntimeVariable]
-               var frame = new Frame(v, mmethoddef, recv, arguments)
-               v.frame = frame
-
-               var sig = new Buffer
-               var comment = new Buffer
-
-               # Because the function is virtual, the signature must match the one of the original class
-               var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
-               var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
-               var ret = msignature.return_mtype
-               if ret != null then
-                       sig.append("{ret.ctype} ")
-               else if mmethoddef.mproperty.is_new then
-                       ret = recv
-                       sig.append("{ret.ctype} ")
-               else
-                       sig.append("void ")
-               end
-               sig.append(self.c_name)
-               sig.append("({selfvar.mtype.ctype} {selfvar}")
-               comment.append("(self: {selfvar}")
-               arguments.add(selfvar)
-               for i in [0..msignature.arity[ do
-                       var mtype = msignature.mparameters[i].mtype
-                       if i == msignature.vararg_rank then
-                               mtype = v.get_class("Array").get_mtype([mtype])
-                       end
-                       comment.append(", {mtype}")
-                       sig.append(", {mtype.ctype} p{i}")
-                       var argvar = new RuntimeVariable("p{i}", mtype, mtype)
-                       arguments.add(argvar)
-               end
-               sig.append(")")
-               comment.append(")")
-               if ret != null then
-                       comment.append(": {ret}")
-               end
-               compiler.header.add_decl("{sig};")
-
-               v.add_decl("/* method {self} for {comment} */")
-               v.add_decl("{sig} \{")
-               if ret != null then
-                       frame.returnvar = v.new_var(ret)
-               end
-               frame.returnlabel = v.get_name("RET_LABEL")
-
-               if recv != arguments.first.mtype then
-                       #print "{self} {recv} {arguments.first}"
-               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("\}")
+               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
 
        end
 
-       redef fun call(v, arguments)
+       redef fun finalize_ffi_for_module(mmodule)
        do
        do
-               abort
-               # TODO ?
+               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.
 class SeparateCompilerVisitor
        end
 end
 
 # A visitor on the AST of property definition that generate the C code of a separate compilation process.
 class SeparateCompilerVisitor
-       super GlobalCompilerVisitor # TODO better separation of concerns
+       super AbstractCompilerVisitor
+
+       redef type COMPILER: SeparateCompiler
 
 
-       redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
+       redef fun adapt_signature(m, args)
        do
                var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
                var recv = args.first
        do
                var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
                var recv = args.first
@@ -1053,9 +960,23 @@ class SeparateCompilerVisitor
                end
        end
 
                end
        end
 
-       # Box or unbox a value to another type iff a C type conversion is needed
-       # ENSURE: result.mtype.ctype == mtype.ctype
-       redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
+       redef fun unbox_signature_extern(m, args)
+       do
+               var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
+               var recv = args.first
+               if not m.mproperty.is_init and m.is_extern then
+                       args.first = self.unbox_extern(args.first, m.mclassdef.mclass.mclass_type)
+               end
+               for i in [0..msignature.arity[ do
+                       var t = msignature.mparameters[i].mtype
+                       if i == msignature.vararg_rank then
+                               t = args[i+1].mtype
+                       end
+                       if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t)
+               end
+       end
+
+       redef fun autobox(value, mtype)
        do
                if value.mtype == mtype then
                        return value
        do
                if value.mtype == mtype then
                        return value
@@ -1065,65 +986,142 @@ class SeparateCompilerVisitor
                        return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
                else if mtype.ctype == "val*" then
                        var valtype = value.mtype.as(MClassType)
                        return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
                else if mtype.ctype == "val*" then
                        var valtype = value.mtype.as(MClassType)
+                       if mtype isa MClassType and mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
+                               valtype = compiler.mainmodule.pointer_type
+                       end
                        var res = self.new_var(mtype)
                        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("/*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
                                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
                        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}) */")
                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
 
                        return res
                end
        end
 
-       redef fun send(mmethod, arguments)
+       redef fun unbox_extern(value, mtype)
        do
        do
-               if arguments.first.mcasttype.ctype != "val*" then
-                       return self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
+               if mtype isa MClassType and mtype.mclass.kind == extern_kind and
+                  mtype.mclass.name != "NativeString" then
+                       var pointer_type = compiler.mainmodule.pointer_type
+                       var res = self.new_var_extern(mtype)
+                       self.add "{res} = ((struct instance_{pointer_type.c_name}*){value})->value; /* unboxing {value.mtype} */"
+                       return res
+               else
+                       return value
                end
                end
+       end
 
 
-               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
+       redef fun box_extern(value, mtype)
+       do
+               if mtype isa MClassType and mtype.mclass.kind == extern_kind and
+                  mtype.mclass.name != "NativeString" then
+                       var valtype = compiler.mainmodule.pointer_type
+                       var res = self.new_var(mtype)
+                       if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
+                               self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
+                               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}); /* boxing {value.mtype} */")
+                       self.require_declaration("type_{mtype.c_name}")
+                       self.add("{res}->type = &type_{mtype.c_name};")
+                       self.require_declaration("class_{mtype.c_name}")
+                       self.add("{res}->class = &class_{mtype.c_name};")
+                       return res
                else
                else
-                       res = self.new_var(ret)
+                       return value
                end
                end
+       end
 
 
-               var s = new Buffer
-               var ss = new Buffer
+       # Return a C expression returning the runtime type structure of the value
+       # The point of the method is to works also with primitives types.
+       fun type_info(value: RuntimeVariable): String
+       do
+               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
 
 
-               var recv = arguments.first
-               s.append("val*")
-               ss.append("{recv}")
-               self.varargize(msignature, 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
+       redef fun compile_callsite(callsite, args)
+       do
+               var rta = compiler.runtime_type_analysis
+               var recv = args.first.mtype
+               var mmethod = callsite.mproperty
+               # TODO: Inlining of new-style constructors
+               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then
+                       var tgs = rta.live_targets(callsite)
+                       if tgs.length == 1 then
+                               # DIRECT CALL
+                               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
-                       s.append(", {t.ctype}")
-                       a = self.autobox(a, t)
-                       ss.append(", {a}")
                end
                end
+               return super
+       end
+       redef fun send(mmethod, arguments)
+       do
+               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
+
+               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
+
+               return table_send(mmethod, arguments, mmethod.const_color)
+       end
 
 
-               var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
+       # 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
+               var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.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
                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);")
                                var arg = arguments[1]
                                if arg.mcasttype isa MNullableType then
                                        self.add("{res} = ({arg} == NULL);")
@@ -1133,7 +1131,7 @@ class SeparateCompilerVisitor
                                        self.add("{res} = 0; /* {arg.inspect} cannot be null */")
                                end
                        else if mmethod.name == "!=" then
                                        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);")
                                var arg = arguments[1]
                                if arg.mcasttype isa MNullableType then
                                        self.add("{res} = ({arg} != NULL);")
@@ -1143,14 +1141,72 @@ class SeparateCompilerVisitor
                                        self.add("{res} = 1; /* {arg.inspect} cannot be null */")
                                end
                        else
                                        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 \{")
                        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
+                       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
+                               if mmethod.name == "==" then
+                                       self.add("{res} = 0; /* arg is null but recv is not */")
+                               else
+                                       self.add("{res} = 1; /* arg is null and recv is not */")
+                               end
+                               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
 
                end
 
+
                var r
                if ret == null then r = "void" else r = ret.ctype
                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};")
 
                if res != null then
                        self.add("{res} = {call};")
@@ -1158,15 +1214,21 @@ class SeparateCompilerVisitor
                        self.add("{call};")
                end
 
                        self.add("{call};")
                end
 
-               if maybenull then
-                       self.add("\}")
+               if res0 != null then
+                       assert res != null
+                       assign(res0,res)
+                       res = res0
                end
 
                end
 
+               self.add("\}") # closes the null case
+
                return res
        end
 
        redef fun call(mmethoddef, recvtype, arguments)
        do
                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
                var res: nullable RuntimeVariable
                var ret = mmethoddef.msignature.return_mtype
                if mmethoddef.mproperty.is_new then
@@ -1179,27 +1241,31 @@ class SeparateCompilerVisitor
                        res = self.new_var(ret)
                end
 
                        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
                        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
                        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)
 
 
                # Autobox arguments
                self.adapt_signature(mmethoddef, arguments)
 
+               self.require_declaration(mmethoddef.c_name)
                if res == null then
                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(", ")});")
                        return null
                else
                        self.add("{res} = {mmethoddef.c_name}({arguments.join(", ")});")
@@ -1208,11 +1274,65 @@ class SeparateCompilerVisitor
                return res
        end
 
                return res
        end
 
+       redef fun supercall(m: MMethodDef, recvtype: MClassType, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
+       do
+               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)
+       do
+               # A vararg must be stored into an new array
+               # The trick is that the dymaic type of the array may depends on the receiver
+               # of the method (ie recv) if the static type is unresolved
+               # This is more complex than usual because the unresolved type must not be resolved
+               # with the current receiver (ie self).
+               # Therefore to isolate the resolution from self, a local Frame is created.
+               # One can see this implementation as an inlined method of the receiver whose only
+               # job is to allocate the array
+               var old_frame = self.frame
+               var frame = new Frame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
+               self.frame = frame
+               #print "required Array[{elttype}] for recv {recv.inspect}. bound=Array[{self.resolve_for(elttype, recv)}]. selfvar={frame.arguments.first.inspect}"
+               var res = self.array_instance(varargs, elttype)
+               self.frame = old_frame
+               return res
+       end
+
        redef fun isset_attribute(a, recv)
        do
                self.check_recv_notnull(recv)
                var res = self.new_var(bool_type)
        redef fun isset_attribute(a, recv)
        do
                self.check_recv_notnull(recv)
                var res = self.new_var(bool_type)
-               self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
+
+               # What is the declared type of the attribute?
+               var mtype = a.intro.static_mtype.as(not null)
+               var intromclassdef = a.intro.mclassdef
+               mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
+
+               if mtype isa MNullableType then
+                       self.add("{res} = 1; /* easy isset: {a} on {recv.inspect} */")
+                       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
+
+                       if mtype.ctype == "val*" then
+                               self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
+                       else
+                               self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
+                       end
+               end
                return res
        end
 
                return res
        end
 
@@ -1225,22 +1345,52 @@ class SeparateCompilerVisitor
                var intromclassdef = a.intro.mclassdef
                ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
 
                var intromclassdef = a.intro.mclassdef
                ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
 
-               # Get the attribute or a box (ie. always a val*)
-               var cret = self.object_type.as_nullable
-               var res = self.new_var(cret)
-               res.mcasttype = ret
-               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) \{")
-                       self.add_abort("Uninitialized attribute {a.name}")
-                       self.add("\}")
+               if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                       self.compiler.attr_read_count += 1
+                       self.add("count_attr_reads++;")
                end
 
                end
 
-               # Return the attribute or its unboxed version
-               # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
-               return self.autobox(res, ret)
+               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
+                       var res = self.new_var(cret)
+                       res.mcasttype = ret
+
+                       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_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
+                       # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
+                       return self.autobox(res, ret)
+               else
+                       var res = self.new_var(ret)
+                       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_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
+               end
        end
 
        redef fun write_attribute(a, recv, value)
        end
 
        redef fun write_attribute(a, recv, value)
@@ -1254,186 +1404,154 @@ class SeparateCompilerVisitor
 
                # Adapt the value to the declared type
                value = self.autobox(value, mtype)
 
                # Adapt the value to the declared type
                value = self.autobox(value, mtype)
-               var attr = "{recv}->attrs[{a.const_color}]"
-               if mtype.ctype != "val*" then
-                       assert mtype isa MClassType
-                       # 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("\} else \{")
-                       value = self.autobox(value, self.object_type.as_nullable)
-                       self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
-                       self.add("\}")
+
+               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
+                               assert mtype isa MClassType
+                               # 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("\} else \{")
+                               value = self.autobox(value, self.object_type.as_nullable)
+                               self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
+                               self.add("\}")
+                       else
+                               # The attribute is not primitive, thus store it direclty
+                               self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
+                       end
                else
                else
-                       # The attribute is not primitive, thus store it direclty
-                       self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
+                       self.add("{recv}->attrs[{a.const_color}].{mtype.ctypename} = {value}; /* {a} on {recv.inspect} */")
                end
        end
 
                end
        end
 
-       # Build livetype structure retrieving
-       #ENSURE: mtype.need_anchor
-       fun retrieve_anchored_livetype(mtype: MGenericType, buffer: Buffer) do
-               assert mtype.need_anchor
-
-               var compiler = self.compiler.as(SeparateCompiler)
-               for ft in mtype.arguments do
-
-                       var ntype = ft
-                       var s: String = ""
-                       if ntype isa MNullableType then
-                               ntype = ntype.mtype
-                       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
 
 
-                       if ntype isa MParameterType then
-                               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                                       buffer.append("[self->type->fts_table->fts[HASH(self->type->fts_table->mask, {ntype.const_color})]->livecolor]")
-                               else
-                                       buffer.append("[self->type->fts_table->fts[{ntype.const_color}]->livecolor]")
-                               end
-                       else if ntype isa MVirtualType then
-                               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                                       buffer.append("[self->type->vts_table->vts[HASH(self->type->vts_table->mask, {ntype.mproperty.const_color})]->livecolor]")
-                               else
-                                       buffer.append("[self->type->vts_table->vts[{ntype.mproperty.const_color}]->livecolor]")
-                               end
-                       else if ntype isa MGenericType and ntype.need_anchor then
-                               var bbuff = new Buffer
-                               retrieve_anchored_livetype(ntype, bbuff)
-                               buffer.append("[livetypes_{ntype.mclass.c_name}{bbuff.to_s}->livecolor]")
-                       else if ntype isa MClassType then
-                               compiler.undead_types.add(ft)
-                               buffer.append("[type_{ft.c_name}.livecolor]")
-                       else
-                               self.add("printf(\"NOT YET IMPLEMENTED: init_instance(%s, {mtype}).\\n\", \"{ft}\"); exit(1);")
-                       end
-               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
        end
 
        redef fun init_instance(mtype)
        do
-               var compiler = self.compiler.as(SeparateCompiler)
+               self.require_declaration("NEW_{mtype.mclass.c_name}")
+               var compiler = self.compiler
                if mtype isa MGenericType and mtype.need_anchor then
                if mtype isa MGenericType and mtype.need_anchor then
-                       if compiler.modelbuilder.toolcontext.opt_generic_tree.value then
-                               var buff = new Buffer
-                               retrieve_anchored_livetype(mtype, buff)
-                               mtype = self.anchor(mtype).as(MClassType)
-                               return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype)
-                       else
-                               link_unanchored_type(self.frame.mpropdef.mclassdef, mtype)
-                               var recv = self.frame.arguments.first
-                               var recv_boxed = self.autobox(recv, self.object_type)
-                               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_boxed}->type->unanchored_table->types[HASH({recv_boxed}->type->unanchored_table->mask, {mtype.mclass.mclass_type.const_color})])", mtype)
-                               else
-                                       return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_boxed}->type->unanchored_table->types[{mtype.mclass.mclass_type.const_color}])", mtype)
-                               end
-                       end
+                       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)
+                       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)
                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
 
        end
 
-
-       redef fun type_test(value, mtype)
+       redef fun type_test(value, mtype, tag)
        do
                self.add("/* {value.inspect} isa {mtype} */")
        do
                self.add("/* {value.inspect} isa {mtype} */")
-               var compiler = self.compiler.as(SeparateCompiler)
+               var compiler = self.compiler
 
                var recv = self.frame.arguments.first
 
                var recv = self.frame.arguments.first
-               var recv_boxed = self.autobox(recv, self.object_type)
+               var recv_type_info = self.type_info(recv)
 
                var res = self.new_var(bool_type)
 
 
                var res = self.new_var(bool_type)
 
-               var type_struct = self.get_name("type_struct")
-               self.add_decl("struct type* {type_struct};")
                var cltype = self.get_name("cltype")
                self.add_decl("int {cltype};")
                var idtype = self.get_name("idtype")
                self.add_decl("int {idtype};")
                var cltype = self.get_name("cltype")
                self.add_decl("int {cltype};")
                var idtype = self.get_name("idtype")
                self.add_decl("int {idtype};")
-               var is_nullable = self.get_name("is_nullable")
-               self.add_decl("short int {is_nullable};")
-
-               var boxed = self.autobox(value, self.object_type)
-
-               if not compiler.modelbuilder.toolcontext.opt_generic_tree.value and mtype.need_anchor then
-                       link_unanchored_type(self.frame.mpropdef.mclassdef, mtype)
-               end
 
 
+               var maybe_null = self.maybe_null(value)
+               var accept_null = "0"
                var ntype = mtype
                if ntype isa MNullableType then
                        ntype = ntype.mtype
                var ntype = mtype
                if ntype isa MNullableType then
                        ntype = ntype.mtype
+                       accept_null = "1"
                end
 
                end
 
-               if ntype isa MParameterType then
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               self.add("{type_struct} = {recv_boxed}->type->fts_table->fts[HASH({recv_boxed}->type->fts_table->mask, {ntype.const_color})];")
-                       else
-                               self.add("{type_struct} = {recv_boxed}->type->fts_table->fts[{ntype.const_color}];")
+               if value.mcasttype.is_subtype(self.frame.mpropdef.mclassdef.mmodule, self.frame.mpropdef.mclassdef.bound_mtype, mtype) then
+                       self.add("{res} = 1; /* easy {value.inspect} isa {mtype}*/")
+                       if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
+                               self.compiler.count_type_test_skipped[tag] += 1
+                               self.add("count_type_test_skipped_{tag}++;")
+                       end
+                       return res
+               end
+
+               if ntype.need_anchor then
+                       var type_struct = self.get_name("type_struct")
+                       self.add_decl("const struct type* {type_struct};")
+
+                       # Either with resolution_table with a direct resolution
+                       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
                        end
+                       hardening_cast_type(type_struct)
                        self.add("{cltype} = {type_struct}->color;")
                        self.add("{idtype} = {type_struct}->id;")
                        self.add("{cltype} = {type_struct}->color;")
                        self.add("{idtype} = {type_struct}->id;")
-                       self.add("{is_nullable} = {type_struct}->is_nullable;")
-               else if ntype isa MGenericType and ntype.need_anchor then
-                       if compiler.modelbuilder.toolcontext.opt_generic_tree.value then
-                               var buff = new Buffer
-                               retrieve_anchored_livetype(ntype, buff)
-                               self.add("{type_struct} = (struct type*)livetypes_{ntype.mclass.c_name}{buff.to_s};")
-                               self.add("{cltype} = {type_struct}->color;")
-                               self.add("{idtype} = {type_struct}->id;")
-                               self.add("{is_nullable} = {type_struct}->is_nullable;")
-                       else
-                               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                                       self.add("{type_struct} = {recv_boxed}->type->unanchored_table->types[HASH({recv_boxed}->type->unanchored_table->mask, {ntype.mclass.mclass_type.const_color})];")
-                               else
-                                       self.add("{type_struct} = {recv_boxed}->type->unanchored_table->types[{ntype.mclass.mclass_type.const_color}];")
-                               end
-                               self.add("{cltype} = {type_struct}->color;")
-                               self.add("{idtype} = {type_struct}->id;")
+                       if maybe_null and accept_null == "0" then
+                               var is_nullable = self.get_name("is_nullable")
+                               self.add_decl("short int {is_nullable};")
                                self.add("{is_nullable} = {type_struct}->is_nullable;")
                                self.add("{is_nullable} = {type_struct}->is_nullable;")
+                               accept_null = is_nullable.to_s
                        end
                else if ntype isa MClassType then
                        compiler.undead_types.add(mtype)
                        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;")
                        self.add("{cltype} = type_{mtype.c_name}.color;")
                        self.add("{idtype} = type_{mtype.c_name}.id;")
-                       self.add("{is_nullable} = type_{mtype.c_name}.is_nullable;")
-               else if ntype isa MVirtualType then
-                       var vtcolor = ntype.mproperty.const_color
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               self.add("{type_struct} = {recv_boxed}->type->vts_table->vts[HASH({recv_boxed}->type->vts_table->mask, {vtcolor})];")
-                       else
-                               self.add("{type_struct} = {recv_boxed}->type->vts_table->vts[{vtcolor}];")
+                       if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
+                               self.compiler.count_type_test_resolved[tag] += 1
+                               self.add("count_type_test_resolved_{tag}++;")
                        end
                        end
-                       self.add("{cltype} = {type_struct}->color;")
-                       self.add("{idtype} = {type_struct}->id;")
-                       self.add("{is_nullable} = {type_struct}->is_nullable;")
                else
                else
-                       self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{boxed.inspect}\"); exit(1);")
-               end
-
-               if mtype isa MNullableType then
-                       self.add("{is_nullable} = 1;")
+                       self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
                end
 
                # check color is in table
                end
 
                # check color is in table
-               self.add("if({boxed} == NULL) \{")
-               self.add("{res} = {is_nullable};")
-               self.add("\} else \{")
-               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                       self.add("{cltype} = HASH({boxed}->type->color, {idtype});")
+               if maybe_null then
+                       self.add("if({value} == NULL) \{")
+                       self.add("{res} = {accept_null};")
+                       self.add("\} else \{")
                end
                end
-               self.add("if({cltype} >= {boxed}->type->table_size) \{")
+               var value_type_info = self.type_info(value)
+               self.add("if({cltype} >= {value_type_info}->table_size) \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
-               self.add("{res} = {boxed}->type->type_table[{cltype}] == {idtype};")
-               self.add("\}")
+               self.add("{res} = {value_type_info}->type_table[{cltype}] == {idtype};")
                self.add("\}")
                self.add("\}")
+               if maybe_null then
+                       self.add("\}")
+               end
 
                return res
        end
 
                return res
        end
@@ -1454,7 +1572,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} = 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 */")
                        end
                else
                        self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
@@ -1465,8 +1584,16 @@ class SeparateCompilerVisitor
        redef fun class_name_string(value)
        do
                var res = self.get_name("var_class_name")
        redef fun class_name_string(value)
        do
                var res = self.get_name("var_class_name")
-               self.add_decl("const char *{res};")
-               self.add("{res} = class_names[{value}->type->id];")
+               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 and
+                       value.mtype.as(MClassType).name != "NativeString" 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
        end
 
                return res
        end
 
@@ -1485,7 +1612,8 @@ class SeparateCompilerVisitor
                                self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
                        else
                                var mtype1 = value1.mtype.as(MClassType)
                                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("\}")
                                self.add("if ({res}) \{")
                                self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
                                self.add("\}")
@@ -1547,7 +1675,7 @@ class SeparateCompilerVisitor
                else if can_be_primitive(value1) and can_be_primitive(value2) then
                        test.add("{value1}->class == {value2}->class")
                        var s = new Array[String]
                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.as(SeparateCompiler).box_kinds do
+                       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)"
                        end
                        test.add("({s.join(" || ")})")
                                s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
                        end
                        test.add("({s.join(" || ")})")
@@ -1561,8 +1689,7 @@ class SeparateCompilerVisitor
 
        fun can_be_primitive(value: RuntimeVariable): Bool
        do
 
        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*"
                if not t isa MClassType then return false
                var k = t.mclass.kind
                return k == interface_kind or t.ctype != "val*"
@@ -1588,35 +1715,27 @@ 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.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
 
                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])
        do
                var mtype = self.get_class("NativeArray").get_mtype([elttype])
+               self.require_declaration("NEW_{mtype.mclass.c_name}")
                assert mtype isa MGenericType
                assert mtype isa MGenericType
-               var compiler = self.compiler.as(SeparateCompiler)
+               var compiler = self.compiler
                if mtype.need_anchor then
                if mtype.need_anchor then
-                       if compiler.modelbuilder.toolcontext.opt_generic_tree.value then
-                               var buff = new Buffer
-                               retrieve_anchored_livetype(mtype, buff)
-                               mtype = self.anchor(mtype).as(MClassType)
-                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype)
-                       else
-                               link_unanchored_type(self.frame.mpropdef.mclassdef, mtype)
-                               var recv = self.frame.arguments.first
-                               var recv_boxed = self.autobox(recv, self.object_type)
-                               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_boxed}->type->unanchored_table->types[HASH({recv_boxed}->type->unanchored_table->mask, {mtype.mclass.mclass_type.const_color})])", mtype)
-                               else
-                                       return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_boxed}->type->unanchored_table->types[{mtype.mclass.mclass_type.const_color}])", mtype)
-                               end
-                       end
+                       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)
+                       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)
                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)
        end
 
        redef fun native_array_def(pname, ret_type, arguments)
@@ -1630,94 +1749,230 @@ class SeparateCompilerVisitor
                else if pname == "[]=" then
                        self.add("{recv}[{arguments[1]}]={arguments[2]};")
                        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_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"
                else if pname == "copy_to" then
                        var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
-                       self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
+                       self.add("memmove({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
                        return
                end
        end
 
        redef fun calloc_array(ret_type, arguments)
        do
                        return
                end
        end
 
        redef fun calloc_array(ret_type, arguments)
        do
-               var ret = ret_type.as(MGenericType)
-               var compiler = self.compiler.as(SeparateCompiler)
-               compiler.undead_types.add(ret)
                var mclass = self.get_class("ArrayCapable")
                var mclass = self.get_class("ArrayCapable")
-               var nclass = self.get_class("NativeArray")
-
-               if compiler.modelbuilder.toolcontext.opt_generic_tree.value then
-                       var ft = mclass.mclass_type.arguments.first.as(MParameterType)
-                       self.ret(self.new_expr("NEW_{nclass.c_name}({arguments[1]}, (struct type*) livetypes_array__NativeArray[self->type->fts_table->fts[{ft.const_color}]->livecolor])", ret_type))
-               else
-                       var res = nclass.get_mtype(mclass.mclass_type.arguments)
-                       link_unanchored_type(self.frame.mpropdef.mclassdef, res)
-                       var recv = self.frame.arguments.first
-                       var recv_boxed = self.autobox(recv, self.object_type)
-                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
-                               self.ret(self.new_expr("NEW_{nclass.c_name}({arguments[1]}, (struct type *) {recv_boxed}->type->unanchored_table->types[HASH({recv_boxed}->type->unanchored_table->mask, {nclass.mclass_type.const_color})])", ret_type))
-                       else
-                               self.ret(self.new_expr("NEW_{nclass.c_name}({arguments[1]}, (struct type *) {recv_boxed}->type->unanchored_table->types[{nclass.mclass_type.const_color}])", ret_type))
-                       end
-               end
+               var ft = mclass.mclass_type.arguments.first.as(MParameterType)
+               var res = self.native_array_instance(ft, arguments[1])
+               self.ret(res)
        end
 
        end
 
-       fun link_unanchored_type(mclassdef: MClassDef, mtype: MType) do
+       fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
                assert mtype.need_anchor
                assert mtype.need_anchor
-               var compiler = self.compiler.as(SeparateCompiler)
-               if not compiler.live_unanchored_types.has_key(self.frame.mpropdef.mclassdef) then
-                       compiler.live_unanchored_types[self.frame.mpropdef.mclassdef] = new HashSet[MType]
+               var compiler = self.compiler
+               if not compiler.live_unresolved_types.has_key(self.frame.mpropdef.mclassdef) then
+                       compiler.live_unresolved_types[self.frame.mpropdef.mclassdef] = new HashSet[MType]
                end
                end
-               compiler.live_unanchored_types[self.frame.mpropdef.mclassdef].add(mtype)
+               compiler.live_unresolved_types[self.frame.mpropdef.mclassdef].add(mtype)
        end
 end
 
        end
 end
 
-redef class MClass
-       # Return the name of the C structure associated to a Nit class
-       fun c_name: String do
-               var res = self.c_name_cache
-               if res != null then return res
-               res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
-               self.c_name_cache = res
+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
                return res
        end
-       private var c_name_cache: nullable String
-end
+       private var separate_runtime_function_cache: nullable SeparateRuntimeFunction
 
 
-redef class MType
-       fun const_color: String do return "COLOR_{c_name}"
+       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
 
 end
 
-redef class MParameterType
-       redef fun c_name
+# The C function associated to a methoddef separately compiled
+class SeparateRuntimeFunction
+       super AbstractRuntimeFunction
+
+       redef fun build_c_name: String do return "{mmethoddef.c_name}"
+
+       redef fun to_s do return self.mmethoddef.to_s
+
+       redef fun compile_to_c(compiler)
        do
        do
-               var res = self.c_name_cache
-               if res != null then return res
-               res = "{self.mclass.c_name}_FT{self.rank}"
-               self.c_name_cache = res
-               return res
+               var mmethoddef = self.mmethoddef
+
+               var recv = self.mmethoddef.mclassdef.bound_mtype
+               var v = compiler.new_visitor
+               var selfvar = new RuntimeVariable("self", recv, recv)
+               var arguments = new Array[RuntimeVariable]
+               var frame = new Frame(v, mmethoddef, recv, arguments)
+               v.frame = frame
+
+               var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
+
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
+               var ret = msignature.return_mtype
+               if ret != null then
+                       sig.append("{ret.ctype} ")
+               else if mmethoddef.mproperty.is_new then
+                       ret = recv
+                       sig.append("{ret.ctype} ")
+               else
+                       sig.append("void ")
+               end
+               sig.append(self.c_name)
+               sig.append("({selfvar.mtype.ctype} {selfvar}")
+               comment.append("({selfvar}: {selfvar.mtype}")
+               arguments.add(selfvar)
+               for i in [0..msignature.arity[ do
+                       var mtype = msignature.mparameters[i].mtype
+                       if i == msignature.vararg_rank then
+                               mtype = v.get_class("Array").get_mtype([mtype])
+                       end
+                       comment.append(", {mtype}")
+                       sig.append(", {mtype.ctype} p{i}")
+                       var argvar = new RuntimeVariable("p{i}", mtype, mtype)
+                       arguments.add(argvar)
+               end
+               sig.append(")")
+               comment.append(")")
+               if ret != null then
+                       comment.append(": {ret}")
+               end
+               compiler.provide_declaration(self.c_name, "{sig};")
+
+               v.add_decl("/* method {self} for {comment} */")
+               v.add_decl("{sig} \{")
+               if ret != null then
+                       frame.returnvar = v.new_var(ret)
+               end
+               frame.returnlabel = v.get_name("RET_LABEL")
+
+               if recv != arguments.first.mtype then
+                       #print "{self} {recv} {arguments.first}"
+               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
 end
 
        end
 end
 
-redef class MNullableType
-       redef fun c_name
+# The C function associated to a methoddef on a primitive type, stored into a VFT of a class
+# The first parameter (the reciever) is always typed by val* in order to accept an object value
+class VirtualRuntimeFunction
+       super AbstractRuntimeFunction
+
+       redef fun build_c_name: String do return "VIRTUAL_{mmethoddef.c_name}"
+
+       redef fun to_s do return self.mmethoddef.to_s
+
+       redef fun compile_to_c(compiler)
        do
        do
-               var res = self.c_name_cache
-               if res != null then return res
-               res = "nullable_{self.mtype.c_name}"
-               self.c_name_cache = res
-               return res
+               var mmethoddef = self.mmethoddef
+
+               var recv = self.mmethoddef.mclassdef.bound_mtype
+               var v = compiler.new_visitor
+               var selfvar = new RuntimeVariable("self", v.object_type, recv)
+               var arguments = new Array[RuntimeVariable]
+               var frame = new Frame(v, mmethoddef, recv, arguments)
+               v.frame = frame
+
+               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
+               var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
+               var ret = msignature.return_mtype
+               if ret != null then
+                       sig.append("{ret.ctype} ")
+               else if mmethoddef.mproperty.is_new then
+                       ret = recv
+                       sig.append("{ret.ctype} ")
+               else
+                       sig.append("void ")
+               end
+               sig.append(self.c_name)
+               sig.append("({selfvar.mtype.ctype} {selfvar}")
+               comment.append("({selfvar}: {selfvar.mtype}")
+               arguments.add(selfvar)
+               for i in [0..msignature.arity[ do
+                       var mtype = msignature.mparameters[i].mtype
+                       if i == msignature.vararg_rank then
+                               mtype = v.get_class("Array").get_mtype([mtype])
+                       end
+                       comment.append(", {mtype}")
+                       sig.append(", {mtype.ctype} p{i}")
+                       var argvar = new RuntimeVariable("p{i}", mtype, mtype)
+                       arguments.add(argvar)
+               end
+               sig.append(")")
+               comment.append(")")
+               if ret != null then
+                       comment.append(": {ret}")
+               end
+               compiler.provide_declaration(self.c_name, "{sig};")
+
+               v.add_decl("/* method {self} for {comment} */")
+               v.add_decl("{sig} \{")
+               if ret != null then
+                       frame.returnvar = v.new_var(ret)
+               end
+               frame.returnlabel = v.get_name("RET_LABEL")
+
+               var subret = v.call(mmethoddef, recv, arguments)
+               if ret != null then
+                       assert subret != null
+                       v.assign(frame.returnvar.as(not null), subret)
+               end
+
+               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
        end
+
+       # TODO ?
+       redef fun call(v, arguments) do abort
+end
+
+redef class MType
+       fun const_color: String do return "COLOR_{c_name}"
 end
 
 end
 
+interface PropertyLayoutElement end
+
 redef class MProperty
 redef class MProperty
-       fun c_name: String do
-               var res = self.c_name_cache
-               if res != null then return res
-               res = "{self.intro.c_name}"
-               self.c_name_cache = res
-               return res
-       end
-       private var c_name_cache: nullable String
+       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
        fun const_color: String do return "COLOR_{c_name}"
 end
+
+redef class AExternInitPropdef
+       # The semi-global compilation does not support inlining calls to extern news
+       redef fun can_inline do return false
+end