nitg-s: cleaned useless ClassColoring uses
[nit.git] / src / separate_compiler.nit
index a9f2708..cd9768b 100644 (file)
 # Separate compilation of a Nit program
 module separate_compiler
 
 # Separate compilation of a Nit program
 module separate_compiler
 
-
-import global_compiler # TODO better separation of concerns
+import abstract_compiler
 intrude import coloring
 intrude import coloring
+import rapid_type_analysis
+
+# Add separate compiler specific options
 redef class ToolContext
        # --separate
        var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
 redef class ToolContext
        # --separate
        var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
+       # --no-inline-intern
+       var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
+       # --no-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")
+       # --use-naive-coloring
+       var opt_bm_typing: OptionBool = new OptionBool("Colorize items incrementaly, used to simulate binary matrix typing", "--bm-typing")
+       # --use-mod-perfect-hashing
+       var opt_phmod_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with mod operator)", "--phmod-typing")
+       # --use-and-perfect-hashing
+       var opt_phand_typing: OptionBool = new OptionBool("Replace coloration by perfect hashing (with and operator)", "--phand-typing")
+       # --generic-resolution-tree
+       var opt_typing_table_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for typing and resolution", "--typing-table-metrics")
 
        redef init
        do
                super
                self.option_context.add_option(self.opt_separate)
 
        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_typing_table_metrics)
        end
 end
 
 redef class ModelBuilder
        end
 end
 
 redef class ModelBuilder
-       redef fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
-       do
-               # Hijack the run_global_compiler to run the separate one if requested.
-               if self.toolcontext.opt_separate.value then
-                       run_separate_compiler(mainmodule, runtime_type_analysis)
-               else
-                       super
-               end
-       end
-
        fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
        do
                var time0 = get_time
                self.toolcontext.info("*** COMPILING TO C ***", 1)
 
        fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
        do
                var time0 = get_time
                self.toolcontext.info("*** COMPILING TO C ***", 1)
 
-               var compiler = new SeparateCompiler(mainmodule, runtime_type_analysis, self)
-               var v = new SeparateCompilerVisitor(compiler)
-               compiler.header = v
-               v.add_decl("#include <stdlib.h>")
-               v.add_decl("#include <stdio.h>")
-               v.add_decl("#include <string.h>")
-               v.add_decl("#include <gc/gc.h>")
-               v.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
-               v.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
-
-               # Class abstract representation
-               v.add_decl("struct class \{ nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
-               # Type abstract representation
-               v.add_decl("struct type \{ int id; int color; struct fts_table *fts_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
-               v.add_decl("struct fts_table \{ struct type *fts[1]; \}; /* fts list of a C type representation. */")
-               # Instance abstract representation
-               v.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
-
-               # Declare global instances
-               v.add_decl("extern int glob_argc;")
-               v.add_decl("extern char **glob_argv;")
-               v.add_decl("extern val *glob_sys;")
-
-               # The main function of the C
-
-               v = new SeparateCompilerVisitor(compiler)
-               v.add_decl("int glob_argc;")
-               v.add_decl("char **glob_argv;")
-               v.add_decl("val *glob_sys;")
-               v.add_decl("int main(int argc, char** argv) \{")
-               v.add("glob_argc = argc; glob_argv = argv;")
-               var main_type = mainmodule.sys_type
-               if main_type == null then return # Nothing to compile
-               var glob_sys = v.init_instance(main_type)
-               v.add("glob_sys = {glob_sys};")
-               var main_init = mainmodule.try_get_primitive_method("init", main_type)
-               if main_init != null then
-                       v.send(main_init, [glob_sys])
-               end
-               var main_method = mainmodule.try_get_primitive_method("main", main_type)
-               if main_method != null then
-                       v.send(main_method, [glob_sys])
-               end
-               v.add("\}")
+               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
@@ -97,24 +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
-               var mtypes = compiler.do_global_type_coloring
+               compiler.new_file
+               var mtypes = compiler.do_type_coloring
                for t in mtypes do
                        compiler.compile_type_to_c(t)
                end
 
                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
-
-               # for the class_name and output_class_name methods
-               compiler.compile_class_names
+               compiler.display_stats
 
                write_and_make(compiler)
        end
 
                write_and_make(compiler)
        end
@@ -122,208 +96,325 @@ 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
+       super AbstractCompiler
+
+       # Cache for classid
+       protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
+
+       # The result of the RTA (used to know live types and methods)
+       var runtime_type_analysis: RapidTypeAnalysis
+
+       private var undead_types: Set[MType] = new HashSet[MType]
+       private var partial_types: Set[MType] = new HashSet[MType]
+
+       private var type_layout_builder: TypeLayoutBuilder
+       private var type_layout: nullable TypeLayout
+       private var type_tables: nullable Map[MType, Array[nullable MType]] = null
+
+       private var live_unanchored_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
+
+       private var unanchored_types_colors: nullable Map[MType, Int]
+       private var unanchored_types_tables: nullable Map[MClassType, Array[nullable MType]]
+       private var unanchored_types_masks: nullable Map[MClassType, Int]
+
+       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]]
+       private var ft_masks: nullable Map[MClass, Int]
+
+       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis) do
+               super
+               self.header = new_visitor
+               self.init_layout_builders
+               self.runtime_type_analysis = runtime_type_analysis
+               self.do_property_coloring
+               self.compile_box_kinds
+       end
+
+       protected fun init_layout_builders do
+               # Typing Layout
+               if modelbuilder.toolcontext.opt_bm_typing.value then
+                       self.type_layout_builder = new BMTypeLayoutBuilder(self.mainmodule)
+               else if modelbuilder.toolcontext.opt_phmod_typing.value then
+                       self.type_layout_builder = new PHTypeLayoutBuilder(self.mainmodule, new PHModOperator)
+                       self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
+               else if modelbuilder.toolcontext.opt_phand_typing.value then
+                       self.type_layout_builder = new PHTypeLayoutBuilder(self.mainmodule, new PHAndOperator)
+                       self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
+               else
+                       self.type_layout_builder = new CLTypeLayoutBuilder(self.mainmodule)
+               end
+       end
+
+       redef fun compile_header_structs do
+               self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
+               self.compile_header_attribute_structs
+               self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
+
+               # With unanchored_table, all live type resolution are stored in a big table: unanchored_table
+               self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; struct types *unanchored_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
+
+               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+                       self.header.add_decl("struct types \{ int mask; struct type *types[1]; \}; /* a list types (used for vts, fts and unanchored lists). */")
+               else
+                       self.header.add_decl("struct types \{ struct type *types[1]; \}; /* a list types (used for vts, fts and unanchored lists). */")
+               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
 
 
-       private var undead_types: Set[MClassType] = new HashSet[MClassType]
-       protected var typeids: HashMap[MClassType, Int] protected writable = new HashMap[MClassType, Int]
+       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
+                       self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */")
+               end
+       end
+
+       fun compile_box_kinds
+       do
+               # Collect all bas box class
+               # FIXME: this is not completely fine with a separate compilation scheme
+               for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
+                       var classes = self.mainmodule.model.get_mclasses_by_name(classname)
+                       if classes == null then continue
+                       assert classes.length == 1 else print classes.join(", ")
+                       self.box_kinds[classes.first] = self.box_kinds.length + 1
+               end
+       end
 
 
-       private var type_colors: Map[MClassType, Int] = typeids
-       private var type_tables: nullable Map[MClassType, Array[nullable MClassType]] = null
-       private var livetypes_tables: nullable Map[MClass, Array[nullable Object]]
-       private var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
+       var box_kinds = new HashMap[MClass, Int]
 
 
-       protected var class_colors: Map[MClass, Int] protected writable
+       fun box_kind_of(mclass: MClass): Int
+       do
+               if mclass.mclass_type.ctype == "val*" then
+                       return 0
+               else if mclass.kind == extern_kind then
+                       return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
+               else
+                       return self.box_kinds[mclass]
+               end
 
 
-       protected var method_colors: Map[MMethod, Int] protected writable
-       protected var method_tables: Map[MClass, Array[nullable MMethodDef]] protected writable
+       end
 
 
-       protected var attr_colors: Map[MAttribute, Int] protected writable
-       protected var attr_tables: Map[MClass, Array[nullable MAttributeDef]] protected writable
+       fun compile_color_consts(colors: Map[Object, Int]) do
+               for m, c in colors do
+                       if m isa MProperty then
+                               if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                                       self.header.add_decl("#define {m.const_color} {c}")
+                               else
+                                       self.header.add_decl("extern const int {m.const_color};")
+                                       self.header.add("const int {m.const_color} = {c};")
+                               end
+                       else if m isa MType then
+                               if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                                       self.header.add_decl("#define {m.const_color} {c}")
+                               else
+                                       self.header.add_decl("extern const int {m.const_color};")
+                                       self.header.add("const int {m.const_color} = {c};")
+                               end
+                       end
+               end
+       end
 
 
-       private var ft_colors: Map[MParameterType, Int]
-       private var ft_tables: Map[MClass, Array[nullable MParameterType]]
+       # colorize classe properties
+       fun do_property_coloring do
 
 
-       init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
                # classes coloration
                # classes coloration
+               var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
                var class_coloring = new ClassColoring(mainmodule)
                var class_coloring = new ClassColoring(mainmodule)
-               self.class_colors = class_coloring.colorize(mmbuilder.model.mclasses)
+               class_coloring.colorize(mclasses)
 
                # methods coloration
                var method_coloring = new MethodColoring(class_coloring)
                self.method_colors = method_coloring.colorize
                self.method_tables = method_coloring.build_property_tables
 
                # methods coloration
                var method_coloring = new MethodColoring(class_coloring)
                self.method_colors = method_coloring.colorize
                self.method_tables = method_coloring.build_property_tables
+               self.compile_color_consts(self.method_colors)
 
                # attributes coloration
                var attribute_coloring = new AttributeColoring(class_coloring)
                self.attr_colors = attribute_coloring.colorize
                self.attr_tables = attribute_coloring.build_property_tables
 
                # attributes coloration
                var attribute_coloring = new AttributeColoring(class_coloring)
                self.attr_colors = attribute_coloring.colorize
                self.attr_tables = attribute_coloring.build_property_tables
-
-               # fts coloration
-               var ft_coloring = new FTColoring(class_coloring)
-               self.ft_colors = ft_coloring.colorize
-               self.ft_tables = ft_coloring.build_ft_tables
-       end
-
-       protected fun compile_class_names do
-
-               # Build type names table
-               var type_array = new Array[nullable MClassType]
-               for t, i in typeids do
-                       if i >= type_array.length then
-                               type_array[i] = null
-                       end
-                       type_array[i] = t
-               end
-
-               var v = new SeparateCompilerVisitor(self)
-               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}\",")
-                       end
+               self.compile_color_consts(self.attr_colors)
+
+               # vt coloration
+               if modelbuilder.toolcontext.opt_bm_typing.value then
+                       var vt_coloring = new NaiveVTColoring(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(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(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(class_coloring)
+                       self.vt_colors = vt_coloring.colorize
+                       self.vt_tables = vt_coloring.build_property_tables
                end
                end
-               v.add("\};")
+               self.compile_color_consts(self.vt_colors)
        end
 
        # colorize live types of the program
        end
 
        # colorize live types of the program
-       private fun do_global_type_coloring: Set[MClassType] do
-               var mtypes = new HashSet[MClassType]
-               #print "undead types:"
-               #for t in self.undead_types do
-               #       print t
-               #end
-               #print "live types:"
-               #for t in runtime_type_analysis.live_types do
-               #       print t
-               #end
-               #print "cast types:"
-               #for t in runtime_type_analysis.live_cast_types do
-               #       print t
-               #end
-               #print "--"
+       private fun do_type_coloring: Set[MType] do
+               var mtypes = new HashSet[MType]
                mtypes.add_all(self.runtime_type_analysis.live_types)
                mtypes.add_all(self.runtime_type_analysis.live_cast_types)
                mtypes.add_all(self.undead_types)
                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)
-
-               # add formal types arguments to mtypes
-               for mtype in mtypes do
-                       if mtype isa MGenericType then
-                               #TODO do it recursive
-                               for ft in mtype.arguments do
-                                       if ft isa MNullableType then ft = ft.mtype
-                                       mtypes.add(ft.as(MClassType))
-                               end
-                       end
+               for c in self.box_kinds.keys do
+                       mtypes.add(c.mclass_type)
                end
 
                end
 
-               # set type unique id
                for mtype in mtypes do
                for mtype in mtypes do
-                       self.typeids[mtype] = self.typeids.length
+                       retieve_live_partial_types(mtype)
                end
                end
+               mtypes.add_all(self.partial_types)
 
 
-               # build livetypes tables
-               self.livetypes_tables = new HashMap[MClass, Array[nullable Object]]
-               self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
+               # VT and FT are stored with other unresolved types in the big unanchored_tables
+               self.compile_unanchored_tables(mtypes)
+
+               # colorize types
+               self.type_layout = self.type_layout_builder.build_layout(mtypes)
+               self.type_tables = self.build_type_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
                for mtype in mtypes do
-                       if mtype isa MGenericType then
-                               var table: Array[nullable Object]
-                               var sizes: Array[Int]
-                               if livetypes_tables.has_key(mtype.mclass) then
-                                       table = livetypes_tables[mtype.mclass]
+                       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 PHTypeLayout then
+                                       color = layout.hashes[mtype][sup]
                                else
                                else
-                                       table = new Array[nullable Object]
-                                       self.livetypes_tables[mtype.mclass] = table
+                                       color = layout.pos[sup]
                                end
                                end
-                               if livetypes_tables_sizes.has_key(mtype.mclass) then
-                                       sizes = livetypes_tables_sizes[mtype.mclass]
-                               else
-                                       sizes = new Array[Int]
-                                       self.livetypes_tables_sizes[mtype.mclass] = sizes
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
                                end
                                end
-                               build_livetype_table(mtype, 0, table, sizes)
+                               table[color] = sup
                        end
                        end
+                       tables[mtype] = table
                end
                end
-
-               # colorize
-               var type_coloring = new TypeColoring(self.mainmodule, self.runtime_type_analysis)
-               self.type_colors = type_coloring.colorize(mtypes)
-               self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
-
-               return mtypes
+               return tables
        end
 
        end
 
-       # build live gentype table recursively
-       private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do
-               var ft = mtype.arguments[current_rank]
-               if ft isa MNullableType then ft = ft.mtype
-               var id = self.typeids[ft.as(MClassType)]
+       protected fun compile_unanchored_tables(mtypes: Set[MType]) do
+               # Unanchored_tables is used to perform a type resolution at runtime in O(1)
 
 
-               if current_rank >= sizes.length then
-                       sizes[current_rank] = id + 1
-               else if id >= sizes[current_rank] then
-                       sizes[current_rank] = id + 1
-               end
-
-               if id > table.length then
-                       for i in [table.length .. id[ do table[i] = null
-               end
+               # During the visit of the body of classes, live_unanchored_types are collected
+               # and associated to
+               # Collect all live_unanchored_types (visited in the body of classes)
 
 
-               if current_rank == mtype.arguments.length - 1 then
-                       table[id] = mtype
+               # Determinate fo each livetype what are its possible requested anchored types
+               var mtype2unanchored = 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_unanchored_types.has_key(cd) then
+                                       set.add_all(self.live_unanchored_types[cd])
+                               end
+                       end
+                       mtype2unanchored[mtype] = set
+               end
+
+               # Compute the table layout with the prefered method
+               if modelbuilder.toolcontext.opt_bm_typing.value then
+                       var unanchored_type_coloring = new NaiveUnanchoredTypeColoring
+                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
+                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
+               else if modelbuilder.toolcontext.opt_phmod_typing.value then
+                       var unanchored_type_coloring = new UnanchoredTypeModPerfectHashing
+                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
+                       self.unanchored_types_masks = unanchored_type_coloring.compute_masks(mtype2unanchored)
+                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
+               else if modelbuilder.toolcontext.opt_phand_typing.value then
+                       var unanchored_type_coloring = new UnanchoredTypeAndPerfectHashing
+                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
+                       self.unanchored_types_masks = unanchored_type_coloring.compute_masks(mtype2unanchored)
+                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
                else
                else
-                       var ft_table = new Array[nullable Object]
-                       table[id] = ft_table
-                       build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
+                       var unanchored_type_coloring = new UnanchoredTypeColoring
+                       self.unanchored_types_colors = unanchored_type_coloring.colorize(mtype2unanchored)
+                       self.unanchored_types_tables = unanchored_type_coloring.build_tables(mtype2unanchored)
                end
                end
-       end
 
 
-       private fun add_to_livetypes_table(table: Array[nullable Object], ft: MClassType) do
-               var id = self.typeids[ft]
-               for i in [table.length .. id[ do
-                       table[i] = null
+               # Compile a C constant for each collected unanchored type.
+               # Either to a color, or to -1 if the unanchored type is dead (no live receiver can require it)
+               var all_unanchored = new HashSet[MType]
+               for t in self.live_unanchored_types.values do
+                       all_unanchored.add_all(t)
+               end
+               var all_unanchored_types_colors = new HashMap[MType, Int]
+               for t in all_unanchored do
+                       if unanchored_types_colors.has_key(t) then
+                               all_unanchored_types_colors[t] = unanchored_types_colors[t]
+                       else
+                               all_unanchored_types_colors[t] = -1
+                       end
                end
                end
-               table[id] = ft
+               self.compile_color_consts(all_unanchored_types_colors)
+
+               #print "tables"
+               #for k, v in unanchored_types_tables.as(not null) do
+               #       print "{k}: {v.join(", ")}"
+               #end
+               #print ""
        end
 
        end
 
-       private fun compile_livetype_table(table: Array[nullable Object], buffer: Buffer, depth: Int, max: Int) do
-               for obj in table do
-                       if obj == null then
-                               if depth == max then
-                                       buffer.append("NULL,\n")
-                               else
-                                       buffer.append("\{\},\n")
+       fun 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
                        end
                end
-       end
+               var mclass_type: MClassType
+               if mtype isa MNullableType then
+                       mclass_type = mtype.mtype.as(MClassType)
+               else
+                       mclass_type = mtype.as(MClassType)
+               end
 
 
-       # 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("][")}];")
+               # add virtual types to mtypes
+               for vt in self.vt_tables[mclass_type.mclass] do
+                       if vt != null then
+                               var anchored = vt.bound.anchor_to(self.mainmodule, mclass_type)
+                               self.partial_types.add(anchored)
                        end
                end
        end
                        end
                end
        end
@@ -331,6 +422,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
@@ -343,10 +436,11 @@ 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
-       fun compile_type_to_c(mtype: MClassType)
+       fun compile_type_to_c(mtype: MType)
        do
                var c_name = mtype.c_name
                var v = new SeparateCompilerVisitor(self)
        do
                var c_name = mtype.c_name
                var v = new SeparateCompilerVisitor(self)
@@ -356,62 +450,208 @@ 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("const struct fts_table_{c_name} *fts_table;")
+               self.header.add_decl("short int is_nullable;")
+               self.header.add_decl("const struct types *unanchored_table;")
                self.header.add_decl("int table_size;")
                self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
                self.header.add_decl("\};")
 
                self.header.add_decl("int table_size;")
                self.header.add_decl("int type_table[{self.type_tables[mtype].length}];")
                self.header.add_decl("\};")
 
-               # extern const struct fst_table_X fst_table_X
-               self.header.add_decl("extern const struct fts_table_{c_name} fts_table_{c_name};")
-               self.header.add_decl("struct fts_table_{c_name} \{")
-               self.header.add_decl("struct type *fts[{self.ft_tables[mtype.mclass].length}];")
-               self.header.add_decl("\};")
-
                # const struct type_X
                v.add_decl("const struct type_{c_name} type_{c_name} = \{")
                # 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("&fts_table_{c_name},")
+               v.add_decl("{self.type_layout.ids[mtype]},")
+               v.add_decl("\"{mtype}\", /* class_name_string */")
+               var layout = self.type_layout
+               if layout isa PHTypeLayout 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 compile_type_unanchored_table(mtype) then
+                       v.add_decl("(struct types*) &unanchored_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("\};")
+       end
 
 
-               # const struct fst_table_X fst_table_X
-               v.add_decl("const struct fts_table_{c_name} fts_table_{c_name} = \{")
-               v.add_decl("\{")
+       protected fun compile_type_fts_table(mtype: MType): Bool do
+
+               var mclass_type: MClassType
+               if mtype isa MNullableType then
+                       mclass_type = mtype.mtype.as(MClassType)
+               else
+                       mclass_type = mtype.as(MClassType)
+               end
+               if self.ft_tables[mclass_type.mclass].is_empty 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} \{")
+               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+                       self.header.add_decl("int mask;")
+               end
+               self.header.add_decl("struct type *types[{self.ft_tables[mclass_type.mclass].length}];")
+               self.header.add_decl("\};")
 
 
-               for ft in self.ft_tables[mtype.mclass] do
+               # const struct fts_table_X fts_table_X
+               var v = new_visitor
+               v.add_decl("const struct fts_table_{mtype.c_name} fts_table_{mtype.c_name} = \{")
+               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+                       v.add_decl("{self.ft_masks[mclass_type.mclass]},")
+               end
+               v.add_decl("\{")
+               for ft in self.ft_tables[mclass_type.mclass] do
                        if ft == null then
                                v.add_decl("NULL, /* empty */")
                        else
                        if ft == null then
                                v.add_decl("NULL, /* empty */")
                        else
-                               var id = -1
                                var ntype: MType
                                var ntype: MType
-                               if ft.mclass == mtype.mclass then
-                                       ntype = mtype.arguments[ft.rank]
+                               if ft.mclass == mclass_type.mclass then
+                                       ntype = mclass_type.arguments[ft.rank]
                                else
                                else
-                                       ntype = ft.anchor_to(self.mainmodule, mtype)
+                                       ntype = ft.anchor_to(self.mainmodule, mclass_type)
                                end
                                end
-                               if ntype isa MNullableType then ntype = ntype.mtype
-                               var ftype = ntype.as(MClassType)
-                               if self.typeids.has_key(ftype) then
-                                       v.add_decl("(struct type*)&type_{ftype.c_name}, /* {ft} ({ftype}) */")
+                               if self.type_layout.ids.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
                                else
                                        v.add_decl("NULL, /* empty ({ft} not a live type) */")
                                end
                        end
                end
+               v.add_decl("\},")
+               v.add_decl("\};")
+               return true
+       end
+
+       protected fun compile_type_vts_table(mtype: MType): Bool do
+
+               var mclass_type: MClassType
+               if mtype isa MNullableType then
+                       mclass_type = mtype.mtype.as(MClassType)
+               else
+                       mclass_type = mtype.as(MClassType)
+               end
+               if self.vt_tables[mclass_type.mclass].is_empty then return false
+
+               # extern const struct vts_table_X vts_table_X
+               self.header.add_decl("extern const struct vts_table_{mtype.c_name} vts_table_{mtype.c_name};")
+               self.header.add_decl("struct vts_table_{mtype.c_name} \{")
+               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+                       self.header.add_decl("int mask;")
+               end
+               self.header.add_decl("struct type *types[{self.vt_tables[mclass_type.mclass].length}];")
+               self.header.add_decl("\};")
+
+               # const struct vts_table_X vts_table_X
+               var v = new_visitor
+               v.add_decl("const struct vts_table_{mtype.c_name} vts_table_{mtype.c_name} = \{")
+               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+                       v.add_decl("{vt_masks[mclass_type.mclass]},")
+               end
+               v.add_decl("\{")
+
+               for vt in self.vt_tables[mclass_type.mclass] do
+                       if vt == null then
+                               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
+                               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.type_layout.ids.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
+                               end
+                       end
+               end
+               v.add_decl("\},")
+               v.add_decl("\};")
+               return true
+       end
+
+       fun compile_type_unanchored_table(mtype: MType): Bool do
+
+               var mclass_type: MClassType
+               if mtype isa MNullableType then
+                       mclass_type = mtype.mtype.as(MClassType)
+               else
+                       mclass_type = mtype.as(MClassType)
+               end
+               if not self.unanchored_types_tables.has_key(mclass_type) then return false
+
+               # extern const struct unanchored_table_X unanchored_table_X
+               self.header.add_decl("extern const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name};")
+
+               self.header.add_decl("struct unanchored_table_{mtype.c_name} \{")
+               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+                       self.header.add_decl("int mask;")
+               end
+               self.header.add_decl("struct type *types[{self.unanchored_types_tables[mclass_type].length}];")
+               self.header.add_decl("\};")
 
 
+               # const struct fts_table_X fts_table_X
+               var v = new_visitor
+               v.add_decl("const struct unanchored_table_{mtype.c_name} unanchored_table_{mtype.c_name} = \{")
+               if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+                       v.add_decl("{self.unanchored_types_masks[mclass_type]},")
+               end
+               v.add_decl("\{")
+               for t in self.unanchored_types_tables[mclass_type] do
+                       if t == null then
+                               v.add_decl("NULL, /* empty */")
+                       else
+                               # 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
+                                       v.add_decl("NULL, /* empty ({t}: {tv} not a live type) */")
+                               end
+                       end
+               end
                v.add_decl("\},")
                v.add_decl("\};")
                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
@@ -424,7 +664,7 @@ class SeparateCompiler
 
                var vft = self.method_tables[mclass]
                var attrs = self.attr_tables[mclass]
 
                var vft = self.method_tables[mclass]
                var attrs = self.attr_tables[mclass]
-               var v = new SeparateCompilerVisitor(self)
+               var v = new_visitor
 
                v.add_decl("/* runtime class {c_name} */")
                var idnum = classids.length
 
                v.add_decl("/* runtime class {c_name} */")
                var idnum = classids.length
@@ -433,30 +673,14 @@ class SeparateCompiler
                #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
 
                self.header.add_decl("struct class_{c_name} \{")
                #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("nitmethod_t vft[{vft.length}];")
                self.header.add_decl("nitmethod_t vft[{vft.length}];")
-
-               if mtype.ctype != "val*" then
-                       # Is the Nit type is native then the struct is a box with two fields:
-                       # * the `vft` to be polymorph
-                       # * the `value` that contains the native value.
-                       self.header.add_decl("{mtype.ctype} value;")
-               end
-
-               # Collect all attributes and associate them a field in the structure.
-               # Note: we do not try to optimize the order and helps CC to optimize the client code.
-               for cd in mtype.collect_mclassdefs(self.mainmodule) do
-                       for p in cd.intro_mproperties do
-                               if not p isa MAttribute then continue
-                               var t = p.intro.static_mtype.as(not null)
-                               t = t.anchor_to(self.mainmodule, mtype)
-                               self.header.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
-                       end
-               end
                self.header.add_decl("\};")
 
                # Build class vft
                self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
                v.add_decl("const struct class_{c_name} class_{c_name} = \{")
                self.header.add_decl("\};")
 
                # Build class vft
                self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
                v.add_decl("const struct class_{c_name} class_{c_name} = \{")
+               v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
                v.add_decl("\{")
                for i in [0 .. vft.length[ do
                        var mpropdef = vft[i]
                v.add_decl("\{")
                for i in [0 .. vft.length[ do
                        var mpropdef = vft[i]
@@ -481,11 +705,13 @@ class SeparateCompiler
                        self.header.add_decl("{mtype.ctype} value;")
                        self.header.add_decl("\};")
 
                        self.header.add_decl("{mtype.ctype} value;")
                        self.header.add_decl("\};")
 
-                       self.header.add_decl("val* BOX_{c_name}({mtype.ctype}, struct type*);")
+                       if not self.runtime_type_analysis.live_types.has(mtype) then return
+
+                       self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("/* allocate {mtype} */")
-                       v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value, struct type* type) \{")
+                       v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
                        v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
                        v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
-                       v.add("res->type = type;")
+                       v.add("res->type = (struct type*) &type_{c_name};")
                        v.add("res->class = (struct class*) &class_{c_name};")
                        v.add("res->value = value;")
                        v.add("return (val*)res;")
                        v.add("res->class = (struct class*) &class_{c_name};")
                        v.add("res->value = value;")
                        v.add("return (val*)res;")
@@ -526,210 +752,105 @@ 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->unanchored_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};")
 
                v.add("{res}->class = (struct class*) &class_{c_name};")
 
-               for cd in mtype.collect_mclassdefs(self.mainmodule)
-               do
-                       var n = self.modelbuilder.mclassdef2nclassdef[cd]
-                       for npropdef in n.n_propdefs do
-                               if npropdef isa AAttrPropdef then
-                                       npropdef.init_expr(v, res)
-                               end
-                       end
-               end
+               self.generate_init_attr(v, res, mtype)
                v.add("return {res};")
                v.add("\}")
                v.add("return {res};")
                v.add("\}")
-       end
-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}"
+               generate_check_init_instance(mtype)
        end
 
        end
 
-       redef fun to_s do return self.mmethoddef.to_s
-
-       redef fun compile_to_c(compiler)
+       redef fun generate_check_init_instance(mtype)
        do
        do
-               var mmethoddef = self.mmethoddef
+               if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
 
 
-               var recv = self.mmethoddef.mclassdef.bound_mtype
-               var v = new SeparateCompilerVisitor(compiler)
-               var selfvar = new RuntimeVariable("self", recv, recv)
-               var arguments = new Array[RuntimeVariable]
-               var frame = new Frame(v, mmethoddef, recv, arguments)
-               v.frame = frame
+               var v = self.new_visitor
+               var c_name = mtype.mclass.c_name
+               var res = new RuntimeVariable("self", mtype, mtype)
+               self.header.add_decl("void CHECK_NEW_{c_name}({mtype.ctype});")
+               v.add_decl("/* allocate {mtype} */")
+               v.add_decl("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{")
+               self.generate_check_attr(v, res, mtype)
+               v.add("\}")
+       end
 
 
-               var sig = new Buffer
-               var comment = new Buffer
-               var ret = mmethoddef.msignature.return_mtype
-               if ret != null then
-                       ret = v.resolve_for(ret, selfvar)
-                       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..mmethoddef.msignature.arity[ do
-                       var mtype = mmethoddef.msignature.mparameters[i].mtype
-                       if i == mmethoddef.msignature.vararg_rank then
-                               mtype = v.get_class("Array").get_mtype([mtype])
-                       end
-                       mtype = v.resolve_for(mtype, selfvar)
-                       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};")
+       redef fun new_visitor do return new SeparateCompilerVisitor(self)
 
 
-               v.add_decl("/* method {self} for {comment} */")
-               v.add_decl("{sig} \{")
-               if ret != null then
-                       frame.returnvar = v.new_var(ret)
+       # Stats
+
+       redef fun display_stats
+       do
+               super
+               if self.modelbuilder.toolcontext.opt_typing_table_metrics.value then
+                       display_sizes
                end
                end
-               frame.returnlabel = v.get_name("RET_LABEL")
+       end
 
 
-               if recv != arguments.first.mtype then
-                       #print "{self} {recv} {arguments.first}"
+       fun display_sizes
+       do
+               print "# size of tables"
+               print "\trs size\trs hole\tst size\tst hole"
+               var rt_table = 0
+               var rt_holes = 0
+               var st_table = 0
+               var st_holes = 0
+               var rtables = unanchored_types_tables
+               if rtables != null then
+                       for unanch, table in rtables do
+                               rt_table += table.length
+                               for e in table do if e == null then rt_holes += 1
+                       end
                end
                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)};")
+               var ttables = type_tables
+               if ttables != null then
+                       for t, table in ttables do
+                               st_table += table.length
+                               for e in table do if e == null then st_holes += 1
+                       end
                end
                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
-
-       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 = new SeparateCompilerVisitor(compiler)
-               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
-
-       redef fun call(v, arguments)
-       do
-               abort
-               # TODO ?
+               print "\t{rt_table}\t{rt_holes}\t{st_table}\t{st_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 type COMPILER: SeparateCompiler
 
 
-       redef fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
+       redef fun adapt_signature(m, args)
        do
        do
+               var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
                var recv = args.first
                if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
                        args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
                end
                var recv = args.first
                if recv.mtype.ctype != m.mclassdef.mclass.mclass_type.ctype then
                        args.first = self.autobox(args.first, m.mclassdef.mclass.mclass_type)
                end
-               for i in [0..m.msignature.arity[ do
-                       var t = m.msignature.mparameters[i].mtype
-                       if i == m.msignature.vararg_rank then
+               for i in [0..msignature.arity[ do
+                       var t = msignature.mparameters[i].mtype
+                       if i == msignature.vararg_rank then
                                t = args[i+1].mtype
                        end
                                t = args[i+1].mtype
                        end
-                       t = self.resolve_for(t, recv)
                        args[i+1] = self.autobox(args[i+1], t)
                end
        end
 
                        args[i+1] = self.autobox(args[i+1], t)
                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
        do
-               if value.mtype.ctype == mtype.ctype then
+               if value.mtype == mtype then
+                       return value
+               else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
                        return value
                else if value.mtype.ctype == "val*" then
                        return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
                        return value
                else if value.mtype.ctype == "val*" then
                        return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
@@ -741,9 +862,7 @@ class SeparateCompilerVisitor
                                self.add("printf(\"Dead code executed!\\n\"); exit(1);")
                                return res
                        end
                                self.add("printf(\"Dead code executed!\\n\"); exit(1);")
                                return res
                        end
-                       var totype = value.mtype
-                       if totype isa MNullableType then totype = totype.mtype
-                       self.add("{res} = BOX_{valtype.c_name}({value}, (struct type*) &type_{totype.c_name}); /* autobox from {value.mtype} to {mtype} */")
+                       self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
                        return res
                else
                        # Bad things will appen!
                        return res
                else
                        # Bad things will appen!
@@ -754,11 +873,21 @@ 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
        redef fun send(mmethod, arguments)
        do
-               if arguments.first.mtype.ctype != "val*" then
-                       assert arguments.first.mtype == arguments.first.mcasttype
-                       return self.monomorphic_send(mmethod, arguments.first.mtype, arguments)
+               if arguments.first.mcasttype.ctype != "val*" then
+                       return self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
                end
 
                var res: nullable RuntimeVariable
                end
 
                var res: nullable RuntimeVariable
@@ -770,7 +899,6 @@ class SeparateCompilerVisitor
                else if ret == null then
                        res = null
                else
                else if ret == null then
                        res = null
                else
-                       ret = self.resolve_for(ret, arguments.first)
                        res = self.new_var(ret)
                end
 
                        res = self.new_var(ret)
                end
 
@@ -780,7 +908,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
@@ -792,7 +920,8 @@ class SeparateCompilerVisitor
                        ss.append(", {a}")
                end
 
                        ss.append(", {a}")
                end
 
-               var maybenull = recv.mcasttype isa MNullableType
+               var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
+               var maybenull = recv.mcasttype isa MNullableType and consider_null
                if maybenull then
                        self.add("if ({recv} == NULL) \{")
                        if mmethod.name == "==" then
                if maybenull then
                        self.add("if ({recv} == NULL) \{")
                        if mmethod.name == "==" then
@@ -820,11 +949,26 @@ 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 color = self.compiler.as(SeparateCompiler).method_colors[mmethod]
                var r
                if ret == null then r = "void" else r = ret.ctype
                var r
                if ret == null then r = "void" else r = ret.ctype
-               var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
+               var call = "(({r} (*)({s}))({arguments.first}->class->vft[{mmethod.const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
 
                if res != null then
                        self.add("{res} = {call};")
 
                if res != null then
                        self.add("{res} = {call};")
@@ -849,10 +993,26 @@ class SeparateCompilerVisitor
                else if ret == null then
                        res = null
                else
                else if ret == null then
                        res = null
                else
-                       ret = self.resolve_for(ret, arguments.first)
+                       ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
                        res = self.new_var(ret)
                end
 
                        res = self.new_var(ret)
                end
 
+               if self.compiler.modelbuilder.mpropdef2npropdef.has_key(mmethoddef) and
+               self.compiler.modelbuilder.mpropdef2npropdef[mmethoddef] isa AInternMethPropdef and
+               not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value then
+                       var frame = new Frame(self, mmethoddef, recvtype, arguments)
+                       frame.returnlabel = self.get_name("RET_LABEL")
+                       frame.returnvar = res
+                       var old_frame = self.frame
+                       self.frame = frame
+                       self.add("\{ /* Inline {mmethoddef} ({arguments.join(",")}) */")
+                       mmethoddef.compile_inside_to_c(self, arguments)
+                       self.add("{frame.returnlabel.as(not null)}:(void)0;")
+                       self.add("\}")
+                       self.frame = old_frame
+                       return res
+               end
+
                # Autobox arguments
                self.adapt_signature(mmethoddef, arguments)
 
                # Autobox arguments
                self.adapt_signature(mmethoddef, arguments)
 
@@ -866,137 +1026,277 @@ class SeparateCompilerVisitor
                return res
        end
 
                return res
        end
 
-       # Add a check and an abort for a null reciever is needed
-       fun check_recv_notnull(recv: RuntimeVariable)
+       redef fun vararg_instance(mpropdef, recv, varargs, elttype)
        do
        do
-               var maybenull = recv.mcasttype isa MNullableType
-               if maybenull then
-                       self.add("if ({recv} == NULL) \{")
-                       self.add_abort("Reciever is null")
-                       self.add("\}")
-               end
+               # 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 unanchored 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
 
        end
 
-
        redef fun isset_attribute(a, recv)
        do
        redef fun isset_attribute(a, recv)
        do
-               # FIXME: Here we inconditionally return boxed primitive attributes
                self.check_recv_notnull(recv)
                var res = self.new_var(bool_type)
                self.check_recv_notnull(recv)
                var res = self.new_var(bool_type)
-               self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != 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
 
        redef fun read_attribute(a, recv)
        do
                return res
        end
 
        redef fun read_attribute(a, recv)
        do
-               # FIXME: Here we inconditionally return boxed primitive attributes
+               self.check_recv_notnull(recv)
+
+               # What is the declared type of the attribute?
                var ret = a.intro.static_mtype.as(not null)
                var ret = a.intro.static_mtype.as(not null)
-               ret = self.resolve_for(ret, recv)
-               var cret = self.object_type.as_nullable
-               var res = self.new_var(cret)
-               res.mcasttype = ret
+               var intromclassdef = a.intro.mclassdef
+               ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
 
 
-               self.check_recv_notnull(recv)
+               if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
+                       # Get the attribute or a box (ie. always a val*)
+                       var cret = self.object_type.as_nullable
+                       var res = self.new_var(cret)
+                       res.mcasttype = ret
 
 
-               self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */")
-               if not ret isa MNullableType 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} */")
 
 
-               return res
+                       # 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 res
+               end
        end
 
        redef fun write_attribute(a, recv, value)
        do
        end
 
        redef fun write_attribute(a, recv, value)
        do
-               # FIXME: Here we inconditionally box primitive attributes
                self.check_recv_notnull(recv)
                self.check_recv_notnull(recv)
-               value = self.autobox(value, self.object_type.as_nullable)
-               self.add("{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] = {value}; /* {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)
+
+               # Adapt the value to the declared type
+               value = self.autobox(value, mtype)
+
+               if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
+                       var attr = "{recv}->attrs[{a.const_color}]"
+                       if mtype.ctype != "val*" then
+                               assert mtype isa MClassType
+                               # The attribute is primitive, thus we store it in a box
+                               # The trick is to create the box the first time then resuse the box
+                               self.add("if ({attr} != NULL) \{")
+                               self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
+                               self.add("\} else \{")
+                               value = self.autobox(value, self.object_type.as_nullable)
+                               self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
+                               self.add("\}")
+                       else
+                               # The attribute is not primitive, thus store it direclty
+                               self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
+                       end
+               else
+                       self.add("{recv}->attrs[{a.const_color}].{mtype.ctypename} = {value}; /* {a} on {recv.inspect} */")
+               end
        end
 
        # Build livetype structure retrieving
        end
 
        # Build livetype structure retrieving
-       #ENSURE: mtype.need_anchor
+       # ENSURE: mtype.need_anchor
        fun retrieve_anchored_livetype(mtype: MGenericType, buffer: Buffer) do
                assert mtype.need_anchor
 
        fun retrieve_anchored_livetype(mtype: MGenericType, buffer: Buffer) do
                assert mtype.need_anchor
 
-               var compiler = self.compiler.as(SeparateCompiler)
+               var compiler = self.compiler
                for ft in mtype.arguments do
                for ft in mtype.arguments do
-                       if ft isa MParameterType then
-                               var ftcolor = compiler.ft_colors[ft]
-                               buffer.append("[self->type->fts_table->fts[{ftcolor}]->id]")
-                       else if ft isa MGenericType and ft.need_anchor then
+
+                       var ntype = ft
+                       var s: String = ""
+                       if ntype isa MNullableType then
+                               ntype = ntype.mtype
+                       end
+
+                       var recv = self.frame.arguments.first
+                       var recv_type_info = self.type_info(recv)
+                       if ntype isa MParameterType then
+                               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
+                                       buffer.append("[{recv_type_info}->fts_table->types[HASH({recv_type_info}->fts_table->mask, {ntype.const_color})]->livecolor]")
+                               else
+                                       buffer.append("[{recv_type_info}->fts_table->types[{ntype.const_color}]->livecolor]")
+                               end
+                       else if ntype isa MVirtualType then
+                               if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
+                                       buffer.append("[{recv_type_info}->vts_table->types[HASH({recv_type_info}->vts_table->mask, {ntype.mproperty.const_color})]->livecolor]")
+                               else
+                                       buffer.append("[{recv_type_info}->vts_table->types[{ntype.mproperty.const_color}]->livecolor]")
+                               end
+                       else if ntype isa MGenericType and ntype.need_anchor then
                                var bbuff = new Buffer
                                var bbuff = new Buffer
-                               retrieve_anchored_livetype(ft, bbuff)
-                               buffer.append("[livetypes_{ft.mclass.c_name}{bbuff.to_s}->id]")
-                       else if ft isa MClassType then
-                               var typecolor = compiler.type_colors[ft]
-                               buffer.append("[{typecolor}]")
+                               retrieve_anchored_livetype(ntype, bbuff)
+                               buffer.append("[livetypes_{ntype.mclass.c_name}{bbuff.to_s}->livecolor]")
+                       else if ntype isa MClassType then
+                               compiler.undead_types.add(ft)
+                               buffer.append("[type_{ft.c_name}.livecolor]")
                        else
                        else
-                               self.add("printf(\"NOT YET IMPLEMENTED: init_instance(%s, {mtype}).\\n\", \"{ft.inspect}\"); exit(1);")
+                               self.add("printf(\"NOT YET IMPLEMENTED: init_instance(%s, {mtype}).\\n\", \"{ft}\"); exit(1);")
                        end
                end
        end
 
        redef fun init_instance(mtype)
        do
                        end
                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_unanchored_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}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {mtype.const_color})])", mtype)
+                       else
+                               return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->unanchored_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
 
                end
                compiler.undead_types.add(mtype)
                return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
        end
 
-       redef fun type_test(value, mtype)
+       redef fun check_init_instance(value, mtype)
+       do
+               if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
+               self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
+       end
+
+       redef fun type_test(value, mtype, tag)
        do
        do
-               var compiler = self.compiler.as(SeparateCompiler)
+               self.add("/* {value.inspect} isa {mtype} */")
+               var compiler = self.compiler
+
+               var recv = self.frame.arguments.first
+               var recv_type_info = self.type_info(recv)
+
                var res = self.new_var(bool_type)
 
                var cltype = self.get_name("cltype")
                var res = self.new_var(bool_type)
 
                var cltype = self.get_name("cltype")
-               self.add_decl("short int {cltype};")
+               self.add_decl("int {cltype};")
                var idtype = self.get_name("idtype")
                var idtype = self.get_name("idtype")
-               self.add_decl("short int {idtype};")
+               self.add_decl("int {idtype};")
 
 
-               var buff = new Buffer
-               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
+                       accept_null = "1"
+               end
 
 
-               var s: String
-               if mtype isa MNullableType then
-                       mtype = mtype.mtype
-                       s = "{boxed} == NULL ||"
-               else
-                       s = "{boxed} != NULL &&"
-               end
-               if mtype isa MParameterType then
-                       var ftcolor = compiler.ft_colors[mtype]
-                       self.add("{cltype} = self->type->fts_table->fts[{ftcolor}]->color;")
-                       self.add("{idtype} = self->type->fts_table->fts[{ftcolor}]->id;")
-               else if mtype isa MGenericType and mtype.need_anchor then
-                       for ft in mtype.mclass.mclass_type.arguments do
-                               var ftcolor = compiler.ft_colors[ft.as(MParameterType)]
-                               buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
+               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 unanchored_table with a direct resolution
+                       link_unanchored_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}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {ntype.const_color})];")
+                       else
+                               self.add("{type_struct} = {recv_type_info}->unanchored_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
                        end
-                       self.add("{cltype} = livetypes_{mtype.mclass.c_name}{buff.to_s}->color;")
-                       self.add("{idtype} = livetypes_{mtype.mclass.c_name}{buff.to_s}->id;")
-               else if mtype isa MClassType then
+                       self.add("{cltype} = {type_struct}->color;")
+                       self.add("{idtype} = {type_struct}->id;")
+                       if maybe_null and accept_null == "0" then
+                               var is_nullable = self.get_name("is_nullable")
+                               self.add_decl("short int {is_nullable};")
+                               self.add("{is_nullable} = {type_struct}->is_nullable;")
+                               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;")
                        compiler.undead_types.add(mtype)
                        self.add("{cltype} = type_{mtype.c_name}.color;")
                        self.add("{idtype} = type_{mtype.c_name}.id;")
+                       if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
+                               self.compiler.count_type_test_resolved[tag] += 1
+                               self.add("count_type_test_resolved_{tag}++;")
+                       end
                else
                else
-                       self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{boxed.inspect}\"); exit(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 && {cltype} >= {boxed}->type->table_size) \{")
+               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
+                       self.add("{cltype} = HASH({value_type_info}->color, {idtype});")
+               end
+               self.add("if({cltype} >= {value_type_info}->table_size) \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
-               self.add("{res} = {s} {boxed}->type->type_table[{cltype}] == {idtype};")
+               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
@@ -1011,7 +1311,7 @@ class SeparateCompilerVisitor
                        value2 = tmp
                end
                if value1.mtype.ctype != "val*" then
                        value2 = tmp
                end
                if value1.mtype.ctype != "val*" then
-                       if value2.mtype.ctype == value1.mtype.ctype then
+                       if value2.mtype == value1.mtype then
                                self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
                        else if value2.mtype.ctype != "val*" then
                                self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
                                self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
                        else if value2.mtype.ctype != "val*" then
                                self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
@@ -1025,10 +1325,15 @@ class SeparateCompilerVisitor
                return res
        end
 
                return res
        end
 
-       redef fun class_name_string(value1)
+       redef fun class_name_string(value)
        do
                var res = self.get_name("var_class_name")
        do
                var res = self.get_name("var_class_name")
-               self.add_decl("const char* {res} = class_names[self->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
 
@@ -1041,7 +1346,7 @@ class SeparateCompilerVisitor
                        value2 = tmp
                end
                if value1.mtype.ctype != "val*" then
                        value2 = tmp
                end
                if value1.mtype.ctype != "val*" then
-                       if value2.mtype.ctype == value1.mtype.ctype then
+                       if value2.mtype == value1.mtype then
                                self.add("{res} = {value1} == {value2};")
                        else if value2.mtype.ctype != "val*" then
                                self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
                                self.add("{res} = {value1} == {value2};")
                        else if value2.mtype.ctype != "val*" then
                                self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
@@ -1052,46 +1357,128 @@ class SeparateCompilerVisitor
                                self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
                                self.add("\}")
                        end
                                self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
                                self.add("\}")
                        end
+                       return res
+               end
+               var maybe_null = true
+               var test = new Array[String]
+               var t1 = value1.mcasttype
+               if t1 isa MNullableType then
+                       test.add("{value1} != NULL")
+                       t1 = t1.mtype
                else
                else
-                       var s = new Array[String]
-                       # This is just ugly on so many level. this works but must be rewriten
-                       for t in self.compiler.live_primitive_types do
-                               if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
-                               if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
-                               s.add "({value1}->class == (struct class*)&class_{t.c_name} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
+                       maybe_null = false
+               end
+               var t2 = value2.mcasttype
+               if t2 isa MNullableType then
+                       test.add("{value2} != NULL")
+                       t2 = t2.mtype
+               else
+                       maybe_null = false
+               end
+
+               var incompatible = false
+               var primitive
+               if t1.ctype != "val*" then
+                       primitive = t1
+                       if t1 == t2 then
+                               # No need to compare class
+                       else if t2.ctype != "val*" then
+                               incompatible = true
+                       else if can_be_primitive(value2) then
+                               test.add("{value1}->class == {value2}->class")
+                       else
+                               incompatible = true
                        end
                        end
-                       if s.is_empty then
-                               self.add("{res} = {value1} == {value2};")
+               else if t2.ctype != "val*" then
+                       primitive = t2
+                       if can_be_primitive(value1) then
+                               test.add("{value1}->class == {value2}->class")
                        else
                        else
-                               self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class && ({s.join(" || ")}));")
+                               incompatible = true
                        end
                        end
+               else
+                       primitive = null
                end
                end
+
+               if incompatible then
+                       if maybe_null then
+                               self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
+                               return res
+                       else
+                               self.add("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
+                               return res
+                       end
+               end
+               if primitive != null then
+                       test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
+               else if can_be_primitive(value1) and can_be_primitive(value2) then
+                       test.add("{value1}->class == {value2}->class")
+                       var s = new Array[String]
+                       for t, v in self.compiler.box_kinds do
+                               s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
+                       end
+                       test.add("({s.join(" || ")})")
+               else
+                       self.add("{res} = {value1} == {value2};")
+                       return res
+               end
+               self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
                return res
        end
 
                return res
        end
 
+       fun can_be_primitive(value: RuntimeVariable): Bool
+       do
+               var t = value.mcasttype
+               if t isa MNullableType then t = t.mtype
+               if not t isa MClassType then return false
+               var k = t.mclass.kind
+               return k == interface_kind or t.ctype != "val*"
+       end
+
+       fun maybe_null(value: RuntimeVariable): Bool
+       do
+               var t = value.mcasttype
+               return t isa MNullableType or t isa MNullType
+       end
+
        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.check_init_instance(res)
+               self.send(self.get_property("with_native", arrayclass.intro.bound_mtype), [res, nat, length])
+               self.check_init_instance(res, arraytype)
                self.add("\}")
                return res
        end
 
                self.add("\}")
                return res
        end
 
+       fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
+       do
+               var mtype = self.get_class("NativeArray").get_mtype([elttype])
+               assert mtype isa MGenericType
+               var compiler = self.compiler
+               if mtype.need_anchor then
+                       link_unanchored_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}->unanchored_table->types[HASH({recv_type_info}->unanchored_table->mask, {mtype.const_color})])", mtype)
+                       else
+                               return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->unanchored_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
@@ -1112,21 +1499,178 @@ class SeparateCompilerVisitor
 
        redef fun calloc_array(ret_type, arguments)
        do
 
        redef fun calloc_array(ret_type, arguments)
        do
-               var ret = ret_type.as(MClassType)
-               var compiler = self.compiler.as(SeparateCompiler)
-               compiler.undead_types.add(ret)
-               self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]}, (struct type*) &type_{ret_type.c_name})", ret_type))
+               var mclass = self.get_class("ArrayCapable")
+               var ft = mclass.mclass_type.arguments.first.as(MParameterType)
+               var res = self.native_array_instance(ft, arguments[1])
+               self.ret(res)
+       end
+
+       fun link_unanchored_type(mclassdef: MClassDef, mtype: MType) do
+               assert mtype.need_anchor
+               var compiler = self.compiler
+               if not compiler.live_unanchored_types.has_key(self.frame.mpropdef.mclassdef) then
+                       compiler.live_unanchored_types[self.frame.mpropdef.mclassdef] = new HashSet[MType]
+               end
+               compiler.live_unanchored_types[self.frame.mpropdef.mclassdef].add(mtype)
        end
 end
 
        end
 end
 
-redef class MClass
-       # Return the name of the C structure associated to a Nit class
-       fun c_name: String do
-               var res = self.c_name_cache
-               if res != null then return res
-               res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
-               self.c_name_cache = res
-               return res
+# The C function associated to a methoddef separately compiled
+class SeparateRuntimeFunction
+       super AbstractRuntimeFunction
+
+       redef fun build_c_name: String do return "{mmethoddef.c_name}"
+
+       redef fun to_s do return self.mmethoddef.to_s
+
+       redef fun compile_to_c(compiler)
+       do
+               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
-       private var c_name_cache: nullable String
+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}"
+
+       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", 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
+
+       # TODO ?
+       redef fun call(v, arguments) do abort
+end
+
+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
 end