bench/lang: improve bench_typetest_depth
[nit.git] / src / separate_compiler.nit
index 976b066..ee0299d 100644 (file)
 # Separate compilation of a Nit program
 module separate_compiler
 
 # Separate compilation of a Nit program
 module separate_compiler
 
+import abstract_compiler
+import layout_builders
+import rapid_type_analysis
 
 
-import global_compiler # TODO better separation of concerns
-import coloring
-
+# 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
        var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids", "--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-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-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")
        # --use-and-perfect-hashing
        var opt_phand_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with and operator)", "--phand-typing")
+       # --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_no_union_attribute)
+               self.option_context.add_option(self.opt_no_shortcut_equate)
                self.option_context.add_option(self.opt_inline_coloring_numbers)
                self.option_context.add_option(self.opt_bm_typing)
                self.option_context.add_option(self.opt_phmod_typing)
                self.option_context.add_option(self.opt_phand_typing)
                self.option_context.add_option(self.opt_inline_coloring_numbers)
                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_tables_metrics)
        end
 end
 
        end
 end
 
@@ -56,7 +61,8 @@ redef class ModelBuilder
                var time0 = get_time
                self.toolcontext.info("*** COMPILING TO C ***", 1)
 
                var time0 = get_time
                self.toolcontext.info("*** COMPILING TO 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
                for m in mainmodule.in_importation.greaters do
 
                # compile class structures
                for m in mainmodule.in_importation.greaters do
@@ -65,21 +71,24 @@ redef class ModelBuilder
                        end
                end
 
                        end
                end
 
+               # The main function of the C
+               compiler.new_file
+               compiler.compile_main_function
+
                # compile methods
                for m in mainmodule.in_importation.greaters do
                # compile methods
                for m in mainmodule.in_importation.greaters do
+                       compiler.new_file
                        compiler.compile_module_to_c(m)
                end
 
                # compile live & cast type structures
                        compiler.compile_module_to_c(m)
                end
 
                # compile live & cast type structures
+               compiler.new_file
                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
 
-               # compile live generic types selection structures
-               for mclass in model.mclasses do
-                       compiler.compile_live_gentype_to_c(mclass)
-               end
+               compiler.display_stats
 
                write_and_make(compiler)
        end
 
                write_and_make(compiler)
        end
@@ -87,78 +96,64 @@ end
 
 # Singleton that store the knowledge about the separate compilation process
 class SeparateCompiler
 
 # 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]
-       protected var typeids: HashMap[MType, Int] protected writable = new HashMap[MType, Int]
+       super AbstractCompiler
 
 
-       private var type_colors: Map[MType, Int] = typeids
-       private var type_tables: nullable Map[MType, Array[nullable MType]] = null
+       # The result of the RTA (used to know live types and methods)
+       var runtime_type_analysis: RapidTypeAnalysis
 
 
-       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]]
-
-       protected var class_coloring: ClassColoring
-
-       protected var method_colors: Map[MMethod, Int]
-       protected var method_tables: Map[MClass, Array[nullable MMethodDef]]
-
-       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]]
-
-       init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
+       private var undead_types: Set[MType] = new HashSet[MType]
+       private var partial_types: Set[MType] = new HashSet[MType]
+       private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
+
+       private var type_layout: nullable Layout[MType]
+       private var resolution_layout: nullable Layout[MType]
+       protected var method_layout: nullable Layout[MMethod]
+       protected var attr_layout: nullable Layout[MAttribute]
+
+       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis) do
+               super(mainmodule, mmbuilder)
+               self.header = new_visitor
+               self.runtime_type_analysis = runtime_type_analysis
                self.do_property_coloring
                self.compile_box_kinds
        end
 
        redef fun compile_header_structs do
                self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
                self.do_property_coloring
                self.compile_box_kinds
        end
 
        redef fun compile_header_structs do
                self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
-               self.header.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
+               self.compile_header_attribute_structs
                self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
                self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
-               self.header.add_decl("struct type \{ int id; int color; int livecolor; short int is_nullable; struct vts_table *vts_table; struct fts_table *fts_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
-               self.header.add_decl("struct fts_table \{ struct type *fts[1]; \}; /* fts list of a C type representation. */")
+
+               # With resolution_table_table, all live type resolution are stored in a big table: resolution_table
+               self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; struct types *resolution_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
 
                if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
 
                if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
-                       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 types \{ int mask; struct type *types[1]; \}; /* a list types (used for vts, fts and unresolved lists). */")
                else
                else
-                       self.header.add_decl("struct vts_table \{ struct type *vts[1]; \}; /* vts list of a C type representation. */")
+                       self.header.add_decl("struct types \{ struct type *types[1]; \}; /* a list types (used for vts, fts and unresolved lists). */")
                end
 
                end
 
+               if modelbuilder.toolcontext.opt_phmod_typing.value then
+                       self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
+               else if modelbuilder.toolcontext.opt_phand_typing.value then
+                       self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
+               end
 
                self.header.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
        end
 
 
                self.header.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
        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}\",")
+       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
+                       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
+                               self.header.add_decl("{t.ctype} {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
@@ -189,6 +184,7 @@ class SeparateCompiler
 
        fun compile_color_consts(colors: Map[Object, Int]) do
                for m, c in colors do
 
        fun compile_color_consts(colors: Map[Object, Int]) do
                for m, c in colors do
+                       if color_consts_done.has(m) then continue
                        if m isa MProperty then
                                if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
                                        self.header.add_decl("#define {m.const_color} {c}")
                        if m isa MProperty then
                                if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
                                        self.header.add_decl("#define {m.const_color} {c}")
@@ -204,54 +200,126 @@ class SeparateCompiler
                                        self.header.add("const int {m.const_color} = {c};")
                                end
                        end
                                        self.header.add("const int {m.const_color} = {c};")
                                end
                        end
+                       color_consts_done.add(m)
                end
        end
 
                end
        end
 
+       private var color_consts_done = new HashSet[Object]
+
        # colorize classe properties
        fun do_property_coloring do
        # colorize classe properties
        fun do_property_coloring do
+               var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
 
 
-               # classes coloration
-               self.class_coloring = new ClassColoring(mainmodule)
-               class_coloring.colorize(modelbuilder.model.mclasses)
+               # Layouts
+               var method_layout_builder: PropertyLayoutBuilder[MMethod]
+               var attribute_layout_builder: PropertyLayoutBuilder[MAttribute]
+               if modelbuilder.toolcontext.opt_bm_typing.value then
+                       method_layout_builder = new MMethodBMizer(self.mainmodule)
+                       attribute_layout_builder = new MAttributeBMizer(self.mainmodule)
+               else
+                       method_layout_builder = new MMethodColorer(self.mainmodule)
+                       attribute_layout_builder = new MAttributeColorer(self.mainmodule)
+               end
 
                # methods coloration
 
                # 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)
+               var method_layout = method_layout_builder.build_layout(mclasses)
+               self.method_tables = build_method_tables(mclasses, method_layout)
+               self.compile_color_consts(method_layout.pos)
+               self.method_layout = method_layout
 
                # attributes coloration
 
                # 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)
+               var attr_layout = attribute_layout_builder.build_layout(mclasses)
+               self.attr_tables = build_attr_tables(mclasses, attr_layout)
+               self.compile_color_consts(attr_layout.pos)
+               self.attr_layout = attr_layout
+       end
 
 
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       self.class_coloring = new NaiveClassColoring(mainmodule)
-                       self.class_coloring.colorize(modelbuilder.model.mclasses)
+       fun build_method_tables(mclasses: Set[MClass], layout: Layout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+               var tables = new HashMap[MClass, Array[nullable MPropDef]]
+               for mclass in mclasses do
+                       var table = new Array[nullable MPropDef]
+                       # first, fill table from parents by reverse linearization order
+                       var parents = self.mainmodule.super_mclasses(mclass)
+                       var lin = self.mainmodule.reverse_linearize_mclasses(parents)
+                       for parent in lin do
+                               for mproperty in self.mainmodule.properties(parent) do
+                                       if not mproperty isa MMethod then continue
+                                       var color = layout.pos[mproperty]
+                                       if table.length <= color then
+                                               for i in [table.length .. color[ do
+                                                       table[i] = null
+                                               end
+                                       end
+                                       for mpropdef in mproperty.mpropdefs do
+                                               if mpropdef.mclassdef.mclass == parent then
+                                                       table[color] = mpropdef
+                                               end
+                                       end
+                               end
+                       end
+
+                       # then override with local properties
+                       for mproperty in self.mainmodule.properties(mclass) do
+                               if not mproperty isa MMethod then continue
+                               var color = layout.pos[mproperty]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               for mpropdef in mproperty.mpropdefs do
+                                       if mpropdef.mclassdef.mclass == mclass then
+                                               table[color] = mpropdef
+                                       end
+                               end
+                       end
+                       tables[mclass] = table
                end
                end
+               return tables
+       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 build_attr_tables(mclasses: Set[MClass], layout: Layout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+               var tables = new HashMap[MClass, Array[nullable MPropDef]]
+               for mclass in mclasses do
+                       var table = new Array[nullable MPropDef]
+                       # first, fill table from parents by reverse linearization order
+                       var parents = self.mainmodule.super_mclasses(mclass)
+                       var lin = self.mainmodule.reverse_linearize_mclasses(parents)
+                       for parent in lin do
+                               for mproperty in self.mainmodule.properties(parent) do
+                                       if not mproperty isa MAttribute then continue
+                                       var color = layout.pos[mproperty]
+                                       if table.length <= color then
+                                               for i in [table.length .. color[ do
+                                                       table[i] = null
+                                               end
+                                       end
+                                       for mpropdef in mproperty.mpropdefs do
+                                               if mpropdef.mclassdef.mclass == parent then
+                                                       table[color] = mpropdef
+                                               end
+                                       end
+                               end
+                       end
+
+                       # then override with local properties
+                       for mproperty in self.mainmodule.properties(mclass) do
+                               if not mproperty isa MAttribute then continue
+                               var color = layout.pos[mproperty]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               for mpropdef in mproperty.mpropdefs do
+                                       if mpropdef.mclassdef.mclass == mclass then
+                                               table[color] = mpropdef
+                                       end
+                               end
+                       end
+                       tables[mclass] = table
                end
                end
-               self.compile_color_consts(self.vt_colors)
+               return tables
        end
 
        # colorize live types of the program
        end
 
        # colorize live types of the program
@@ -260,145 +328,169 @@ class SeparateCompiler
                mtypes.add_all(self.runtime_type_analysis.live_types)
                mtypes.add_all(self.runtime_type_analysis.live_cast_types)
                mtypes.add_all(self.undead_types)
                mtypes.add_all(self.runtime_type_analysis.live_types)
                mtypes.add_all(self.runtime_type_analysis.live_cast_types)
                mtypes.add_all(self.undead_types)
+               for c in self.box_kinds.keys do
+                       mtypes.add(c.mclass_type)
+               end
 
 
-               self.undead_types.clear
                for mtype in mtypes do
                for mtype in mtypes do
-                       # add formal types arguments to mtypes
-                       if mtype isa MGenericType then
-                               for ft in mtype.arguments do
-                                       if ft.need_anchor then
-                                               print("Why do we need anchor here ?")
-                                               abort
-                                       end
-                                       self.undead_types.add(ft)
-                               end
-                       end
-                       var mclass_type: MClassType
-                       if mtype isa MNullableType then
-                               mclass_type = mtype.mtype.as(MClassType)
-                       else
-                               mclass_type = mtype.as(MClassType)
-                       end
-
-                       # add virtual types to mtypes
-                       for vt in self.vt_tables[mclass_type.mclass] do
-                               if vt != null then
-                                       var anchored = vt.bound.anchor_to(self.mainmodule, mclass_type)
-                                       self.undead_types.add(anchored)
-                               end
-                       end
+                       retieve_live_partial_types(mtype)
                end
                end
-               mtypes.add_all(self.undead_types)
+               mtypes.add_all(self.partial_types)
 
 
-               # 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
-                       end
+               # Typing Layout
+               var layout_builder: TypingLayoutBuilder[MType]
+               if modelbuilder.toolcontext.opt_bm_typing.value then
+                       layout_builder = new MTypeBMizer(self.mainmodule)
+               else if modelbuilder.toolcontext.opt_phmod_typing.value then
+                       layout_builder = new MTypeHasher(new PHModOperator, self.mainmodule)
+               else if modelbuilder.toolcontext.opt_phand_typing.value then
+                       layout_builder = new MTypeHasher(new PHAndOperator, self.mainmodule)
                else
                else
-                       for mtype in mtypes do
-                               self.typeids[mtype] = self.typeids.length
-                       end
+                       layout_builder = new MTypeColorer(self.mainmodule)
                end
 
                end
 
-               # fts coloration for non-erased compilation
-               var ft_coloring
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       ft_coloring = new NaiveFTColoring(self.class_coloring)
-               else
-                       ft_coloring = new FTColoring(self.class_coloring)
+               # colorize types
+               self.type_layout = layout_builder.build_layout(mtypes)
+               self.type_tables = self.build_type_tables(mtypes)
+
+               # VT and FT are stored with other unresolved types in the big resolution_tables
+               self.compile_resolution_tables(mtypes)
+
+               return mtypes
+       end
+
+       # Build type tables
+       fun build_type_tables(mtypes: Set[MType]): Map[MType, Array[nullable MType]] do
+               var tables = new HashMap[MType, Array[nullable MType]]
+               var layout = self.type_layout
+               for mtype in mtypes do
+                       var table = new Array[nullable MType]
+                       var supers = new HashSet[MType]
+                       supers.add_all(self.mainmodule.super_mtypes(mtype, mtypes))
+                       supers.add(mtype)
+                       for sup in supers do
+                               var color: Int
+                               if layout isa PHLayout[MType, MType] then
+                                       color = layout.hashes[mtype][sup]
+                               else
+                                       color = layout.pos[sup]
+                               end
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               table[color] = sup
+                       end
+                       tables[mtype] = table
                end
                end
-               self.ft_colors = ft_coloring.colorize
-               self.ft_tables = ft_coloring.build_ft_tables
-               self.compile_color_consts(self.ft_colors.as(not null))
+               return tables
+       end
 
 
-               # colorize live entries
-               var entries_coloring
-               if modelbuilder.toolcontext.opt_bm_typing.value then
-                       entries_coloring = new NaiveLiveEntryColoring
-               else
-                       entries_coloring = new LiveEntryColoring
+       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
                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
 
 
-               # colorize types
+               # Compute the table layout with the prefered method
+               var resolution_builder: ResolutionLayoutBuilder
                if modelbuilder.toolcontext.opt_bm_typing.value then
                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)
+                       resolution_builder = new ResolutionBMizer
                else if modelbuilder.toolcontext.opt_phmod_typing.value then
                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("\}")
+                       resolution_builder = new ResolutionHasher(new PHModOperator)
                else if modelbuilder.toolcontext.opt_phand_typing.value then
                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("\}")
+                       resolution_builder = new ResolutionHasher(new PHAndOperator)
                else
                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)
+                       resolution_builder = new ResolutionColorer
                end
                end
+               self.resolution_layout = resolution_builder.build_layout(mtype2unresolved)
+               self.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 self.resolution_layout.pos.has_key(t) then
+                               all_unresolved_types_colors[t] = self.resolution_layout.pos[t]
+                       else
+                               all_unresolved_types_colors[t] = -1
+                       end
+               end
+               self.compile_color_consts(all_unresolved_types_colors)
 
 
-               # for the class_name and output_class_name methods
-               self.compile_class_names
-
-               return mtypes
+               #print "tables"
+               #for k, v in unresolved_types_tables.as(not null) do
+               #       print "{k}: {v.join(", ")}"
+               #end
+               #print ""
        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)
-                       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("][")}];")
+       fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+               var tables = new HashMap[MClassType, Array[nullable MType]]
+               var layout = self.resolution_layout
+               for mclasstype, mtypes in elements do
+                       var table = new Array[nullable MType]
+                       for mtype in mtypes do
+                               var color: Int
+                               if layout isa PHLayout[MClassType, MType] then
+                                       color = layout.hashes[mclasstype][mtype]
+                               else
+                                       color = layout.pos[mtype]
+                               end
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               table[color] = mtype
                        end
                        end
+                       tables[mclasstype] = table
                end
                end
+               return tables
        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 retieve_live_partial_types(mtype: MType) do
+               # add formal types arguments to mtypes
+               if mtype isa MGenericType then
+                       for ft in mtype.arguments do
+                               if ft.need_anchor then
+                                       print("Why do we need anchor here ?")
+                                       abort
                                end
                                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")
+                               self.partial_types.add(ft)
+                               retieve_live_partial_types(ft)
+                       end
+               end
+               var mclass_type: MClassType
+               if mtype isa MNullableType then
+                       mclass_type = mtype.mtype.as(MClassType)
+               else
+                       mclass_type = mtype.as(MClassType)
+               end
+
+               # add virtual types to mtypes
+               for vt in self.mainmodule.properties(mclass_type.mclass) do
+                       if vt isa MVirtualTypeProp then
+                               var anchored = vt.mvirtualtype.lookup_bound(self.mainmodule, mclass_type).anchor_to(self.mainmodule, mclass_type)
+                               self.partial_types.add(anchored)
                        end
                end
        end
                        end
                end
        end
@@ -406,6 +498,8 @@ class SeparateCompiler
        # Separately compile all the method definitions of the module
        fun compile_module_to_c(mmodule: MModule)
        do
        # 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
@@ -418,6 +512,7 @@ class SeparateCompiler
                                end
                        end
                end
                                end
                        end
                end
+               self.mainmodule = old_module
        end
 
        # Globaly compile the type structure of a live type
        end
 
        # Globaly compile the type structure of a live type
@@ -431,44 +526,48 @@ class SeparateCompiler
                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("extern const struct type_{c_name} type_{c_name};")
                self.header.add_decl("struct type_{c_name} \{")
                self.header.add_decl("int id;")
+               self.header.add_decl("const char *name;")
                self.header.add_decl("int color;")
                self.header.add_decl("int color;")
-               self.header.add_decl("int livecolor;")
                self.header.add_decl("short int is_nullable;")
                self.header.add_decl("short int is_nullable;")
-               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("const struct types *resolution_table;")
                self.header.add_decl("int table_size;")
                self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
                self.header.add_decl("\};")
 
                # const struct type_X
                v.add_decl("const struct type_{c_name} type_{c_name} = \{")
                self.header.add_decl("int table_size;")
                self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
                self.header.add_decl("\};")
 
                # 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]},")
-               v.add_decl("{self.livetypes_colors[mtype]},")
+               v.add_decl("{self.type_layout.ids[mtype]},")
+               v.add_decl("\"{mtype}\", /* class_name_string */")
+               var layout = self.type_layout
+               if layout isa PHLayout[MType, MType] then
+                       v.add_decl("{layout.masks[mtype]},")
+               else
+                       v.add_decl("{layout.pos[mtype]},")
+               end
                if mtype isa MNullableType then
                        v.add_decl("1,")
                else
                        v.add_decl("0,")
                end
                if mtype isa MNullableType then
                        v.add_decl("1,")
                else
                        v.add_decl("0,")
                end
-               v.add_decl("&vts_table_{c_name},")
-               v.add_decl("&fts_table_{c_name},")
+               if compile_type_resolution_table(mtype) then
+                       v.add_decl("(struct types*) &resolution_table_{c_name},")
+               else
+                       v.add_decl("NULL,")
+               end
                v.add_decl("{self.type_tables[mtype].length},")
                v.add_decl("\{")
                for stype in self.type_tables[mtype] do
                        if stype == null then
                                v.add_decl("-1, /* empty */")
                        else
                v.add_decl("{self.type_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} */")
+                               v.add_decl("{self.type_layout.ids[stype]}, /* {stype} */")
                        end
                end
                v.add_decl("\},")
                v.add_decl("\};")
                        end
                end
                v.add_decl("\},")
                v.add_decl("\};")
-
-               compile_type_fts_table(mtype)
-               compile_type_vts_table(mtype)
        end
 
        end
 
-       protected fun compile_type_fts_table(mtype: MType) do
+       fun compile_type_resolution_table(mtype: MType): Bool do
 
                var mclass_type: MClassType
                if mtype isa MNullableType then
 
                var mclass_type: MClassType
                if mtype isa MNullableType then
@@ -476,101 +575,45 @@ class SeparateCompiler
                else
                        mclass_type = mtype.as(MClassType)
                end
                else
                        mclass_type = mtype.as(MClassType)
                end
+               if not self.resolution_tables.has_key(mclass_type) then return false
 
 
-               # 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} \{")
-               self.header.add_decl("struct type *fts[{self.ft_tables[mclass_type.mclass].length}];")
-               self.header.add_decl("\};")
+               var layout = self.resolution_layout
 
 
-               # 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} = \{")
-               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}) */")
-                               else
-                                       v.add_decl("NULL, /* empty ({ft} not a live type) */")
-                               end
-                       end
-               end
-               v.add_decl("\},")
-               v.add_decl("\};")
-       end
-
-       protected fun compile_type_vts_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 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
+               # extern const struct resolution_table_X resolution_table_X
+               self.header.add_decl("extern const struct resolution_table_{mtype.c_name} resolution_table_{mtype.c_name};")
+               self.header.add_decl("struct resolution_table_{mtype.c_name} \{")
+               if layout isa PHLayout[MClassType, MType] then
                        self.header.add_decl("int mask;")
                end
                        self.header.add_decl("int mask;")
                end
-               self.header.add_decl("struct type *vts[{self.vt_tables[mclass_type.mclass].length}];")
+               self.header.add_decl("struct type *types[{self.resolution_tables[mclass_type].length}];")
                self.header.add_decl("\};")
 
                self.header.add_decl("\};")
 
-               # 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]},")
+               v.add_decl("const struct resolution_table_{mtype.c_name} resolution_table_{mtype.c_name} = \{")
+               if layout isa PHLayout[MClassType, MType] then
+                       v.add_decl("{layout.masks[mclass_type]},")
                end
                v.add_decl("\{")
                end
                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 self.type_layout.ids.has_key(tv) then
+                                       v.add_decl("(struct type*)&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
                v.add_decl("\},")
                v.add_decl("\};")
                                end
                        end
                end
                v.add_decl("\},")
                v.add_decl("\};")
+               return true
        end
 
        # Globally compile the table of the class mclass
        end
 
        # Globally compile the table of the class mclass
@@ -586,10 +629,6 @@ class SeparateCompiler
                var v = new_visitor
 
                v.add_decl("/* runtime class {c_name} */")
                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} */")
 
                self.header.add_decl("struct class_{c_name} \{")
                self.header.add_decl("int box_kind;")
 
                self.header.add_decl("struct class_{c_name} \{")
                self.header.add_decl("int box_kind;")
@@ -671,8 +710,16 @@ class SeparateCompiler
                else
                        v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
                end
                else
                        v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
                end
-               #v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
                v.add("{res}->type = type;")
                v.add("{res}->type = type;")
+               if v.compiler.modelbuilder.toolcontext.opt_hardening.value then
+                       v.add("if(type == NULL) \{")
+                       v.add_abort("type null")
+                       v.add("\}")
+                       v.add("if(type->resolution_table == NULL) \{")
+                       v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", type->name);")
+                       v.add_abort("type dead")
+                       v.add("\}")
+               end
                v.add("{res}->class = (struct class*) &class_{c_name};")
 
                self.generate_init_attr(v, res, mtype)
                v.add("{res}->class = (struct class*) &class_{c_name};")
 
                self.generate_init_attr(v, res, mtype)
@@ -697,174 +744,73 @@ class SeparateCompiler
        end
 
        redef fun new_visitor do return new SeparateCompilerVisitor(self)
        end
 
        redef fun new_visitor do return new SeparateCompilerVisitor(self)
-end
-
-# The C function associated to a methoddef separately compiled
-class SeparateRuntimeFunction
-       super AbstractRuntimeFunction
-
-       redef fun build_c_name: String
-       do
-               return "{mmethoddef.c_name}"
-       end
-
-       redef fun to_s do return self.mmethoddef.to_s
-
-       redef fun compile_to_c(compiler)
-       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("\}")
-       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
 
 
-       redef fun build_c_name: String
-       do
-               return "VIRTUAL_{mmethoddef.c_name}"
-       end
+       # Stats
 
 
-       redef fun to_s do return self.mmethoddef.to_s
+       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 compile_to_c(compiler)
+       redef fun display_stats
        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)};")
+               super
+               if self.modelbuilder.toolcontext.opt_tables_metrics.value then
+                       display_sizes
                end
                end
-               v.add("\}")
        end
 
        end
 
-       redef fun call(v, arguments)
+       fun display_sizes
        do
        do
-               abort
-               # TODO ?
+               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
 
 # 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 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
+       redef type COMPILER: SeparateCompiler
+
+       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
@@ -880,9 +826,7 @@ 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 autobox(value, mtype)
        do
                if value.mtype == mtype then
                        return value
        do
                if value.mtype == mtype then
                        return value
@@ -909,6 +853,17 @@ class SeparateCompilerVisitor
                end
        end
 
                end
        end
 
+       # 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
+                       return "(&type_{value.mtype.c_name})"
+               end
+       end
+
        redef fun send(mmethod, arguments)
        do
                if arguments.first.mcasttype.ctype != "val*" then
        redef fun send(mmethod, arguments)
        do
                if arguments.first.mcasttype.ctype != "val*" then
@@ -933,7 +888,7 @@ class SeparateCompilerVisitor
                var recv = arguments.first
                s.append("val*")
                ss.append("{recv}")
                var recv = arguments.first
                s.append("val*")
                ss.append("{recv}")
-               self.varargize(msignature, arguments)
+               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
                for i in [0..msignature.arity[ do
                        var a = arguments[i+1]
                        var t = msignature.mparameters[i].mtype
                for i in [0..msignature.arity[ do
                        var a = arguments[i+1]
                        var t = msignature.mparameters[i].mtype
@@ -974,6 +929,22 @@ class SeparateCompilerVisitor
                        end
                        self.add("\} else \{")
                end
                        end
                        self.add("\} else \{")
                end
+               if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
+                       assert res != null
+                       # 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
+                               if maybenull then
+                                       self.add("\}")
+                               end
+                               return res
+                       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
@@ -1035,11 +1006,57 @@ class SeparateCompilerVisitor
                return res
        end
 
                return res
        end
 
+       redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
+       do
+               # FIXME implements a polymorphic access in tables
+               m = m.lookup_next_definition(m.mclassdef.mmodule, m.mclassdef.bound_mtype)
+               return self.call(m, recvtype, args)
+       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
+
+               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
 
@@ -1052,22 +1069,37 @@ 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} */")
+               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
 
 
-               # 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("\}")
-               end
+                       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("\}")
+                       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_initialization.value then
+                               self.add("if ({res} == NULL) \{")
+                               self.add_abort("Uninitialized attribute {a.name}")
+                               self.add("\}")
+                       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)
+                       return res
+               end
        end
 
        redef fun write_attribute(a, recv, value)
        end
 
        redef fun write_attribute(a, recv, value)
@@ -1081,66 +1113,40 @@ 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("\}")
-               else
-                       # The attribute is not primitive, thus store it direclty
-                       self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
-               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
-
-                       if ntype isa MParameterType then
-                               buffer.append("[self->type->fts_table->fts[{ntype.const_color}]->livecolor]")
-                       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]")
+               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
                        else
-                               self.add("printf(\"NOT YET IMPLEMENTED: init_instance(%s, {mtype}).\\n\", \"{ft}\"); exit(1);")
+                               # The attribute is not primitive, thus store it direclty
+                               self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
                        end
                        end
+               else
+                       self.add("{recv}->attrs[{a.const_color}].{mtype.ctypename} = {value}; /* {a} on {recv.inspect} */")
                end
        end
 
        redef fun init_instance(mtype)
        do
                end
        end
 
        redef fun init_instance(mtype)
        do
-               var compiler = self.compiler.as(SeparateCompiler)
+               var compiler = self.compiler
                if mtype isa MGenericType and mtype.need_anchor then
                if mtype isa MGenericType and mtype.need_anchor 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)
+                       link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
+                       var recv = self.frame.arguments.first
+                       var recv_type_info = self.type_info(recv)
+                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
+                               return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
+                       else
+                               return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
+                       end
                end
                compiler.undead_types.add(mtype)
                return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
                end
                compiler.undead_types.add(mtype)
                return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
@@ -1152,81 +1158,91 @@ class SeparateCompilerVisitor
                self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
        end
 
                self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
        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")
-               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)
 
 
+               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
-                       self.add("{type_struct} = {recv_boxed}->type->fts_table->fts[{ntype.const_color}];")
-                       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
-                       var buff = new Buffer
-                       retrieve_anchored_livetype(ntype, buff)
-                       self.add("{type_struct} = livetypes_{ntype.mclass.c_name}{buff.to_s};")
+               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("struct type* {type_struct};")
+
+                       # Either with resolution_table with a direct resolution
+                       link_unresolved_type(self.frame.mpropdef.mclassdef, ntype)
+                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
+                               self.add("{type_struct} = {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {ntype.const_color})];")
+                       else
+                               self.add("{type_struct} = {recv_type_info}->resolution_table->types[{ntype.const_color}];")
+                       end
+                       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
                        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;")
+                       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;")
+                               accept_null = is_nullable.to_s
+                       end
                else if ntype isa MClassType then
                        compiler.undead_types.add(mtype)
                        self.add("{cltype} = type_{mtype.c_name}.color;")
                        self.add("{idtype} = type_{mtype.c_name}.id;")
                else if ntype isa MClassType then
                        compiler.undead_types.add(mtype)
                        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("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); exit(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 maybe_null then
+                       self.add("if({value} == NULL) \{")
+                       self.add("{res} = {accept_null};")
+                       self.add("\} else \{")
+               end
+               var value_type_info = self.type_info(value)
                if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
                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});")
+                       self.add("{cltype} = HASH({value_type_info}->color, {idtype});")
                end
                end
-               self.add("if({cltype} >= {boxed}->type->table_size) \{")
+               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
@@ -1258,8 +1274,12 @@ 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
+                       self.add "{res} = type_{value.mtype.c_name}.name;"
+               end
                return res
        end
 
                return res
        end
 
@@ -1340,7 +1360,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(" || ")})")
@@ -1369,27 +1389,42 @@ class SeparateCompilerVisitor
 
        redef fun array_instance(array, elttype)
        do
 
        redef fun array_instance(array, elttype)
        do
-               var compiler = self.compiler.as(SeparateCompiler)
                var nclass = self.get_class("NativeArray")
                var nclass = self.get_class("NativeArray")
-               elttype = self.anchor(elttype)
-               var arraytype = self.get_class("Array").get_mtype([elttype])
+               var arrayclass = self.get_class("Array")
+               var arraytype = arrayclass.get_mtype([elttype])
                var res = self.init_instance(arraytype)
                self.add("\{ /* {res} = array_instance Array[{elttype}] */")
                var res = self.init_instance(arraytype)
                self.add("\{ /* {res} = array_instance Array[{elttype}] */")
-               var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
-               nat.is_exact = true
-               compiler.undead_types.add(nat.mtype.as(MClassType))
-               self.add("{nat} = NEW_{nclass.c_name}({array.length}, (struct type *) &type_{nat.mtype.c_name});")
+               var length = self.int_instance(array.length)
+               var nat = native_array_instance(elttype, length)
                for i in [0..array.length[ do
                        var r = self.autobox(array[i], self.object_type)
                        self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
                end
                for i in [0..array.length[ do
                        var r = self.autobox(array[i], self.object_type)
                        self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
                end
-               var length = self.int_instance(array.length)
-               self.send(self.get_property("with_native", arraytype), [res, nat, length])
+               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.check_init_instance(res, arraytype)
                self.add("\}")
                return res
        end
 
+       fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
+       do
+               var mtype = self.get_class("NativeArray").get_mtype([elttype])
+               assert mtype isa MGenericType
+               var compiler = self.compiler
+               if mtype.need_anchor then
+                       link_unresolved_type(self.frame.mpropdef.mclassdef, mtype)
+                       var recv = self.frame.arguments.first
+                       var recv_type_info = self.type_info(recv)
+                       if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
+                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype)
+                       else
+                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype)
+                       end
+               end
+               compiler.undead_types.add(mtype)
+               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) &type_{mtype.c_name})", mtype)
+       end
+
        redef fun native_array_def(pname, ret_type, arguments)
        do
                var elttype = arguments.first.mtype
        redef fun native_array_def(pname, ret_type, arguments)
        do
                var elttype = arguments.first.mtype
@@ -1410,62 +1445,178 @@ class SeparateCompilerVisitor
 
        redef fun calloc_array(ret_type, arguments)
        do
 
        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 ft = mclass.mclass_type.arguments.first.as(MParameterType)
                var mclass = self.get_class("ArrayCapable")
                var ft = mclass.mclass_type.arguments.first.as(MParameterType)
-               self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]}, (struct type*) livetypes_array__NativeArray[self->type->fts_table->fts[{ft.const_color}]->livecolor])", ret_type))
+               var res = self.native_array_instance(ft, arguments[1])
+               self.ret(res)
        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
-               return res
+       fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
+               assert mtype.need_anchor
+               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
+               compiler.live_unresolved_types[self.frame.mpropdef.mclassdef].add(mtype)
        end
        end
-       private var c_name_cache: nullable String
 end
 
 end
 
-redef class MType
-       fun const_color: String do return "COLOR_{c_name}"
-end
+# 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 class MParameterType
-       redef fun 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 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("\}")
        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 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("\}")
        end
        end
+
+       # TODO ?
+       redef fun call(v, arguments) do abort
 end
 
 end
 
-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
+redef class MType
+       fun const_color: String do return "COLOR_{c_name}"
+end
 
 
+redef class MProperty
        fun const_color: String do return "COLOR_{c_name}"
 end
        fun const_color: String do return "COLOR_{c_name}"
 end