sepcomp: `compute_resolution_tables` group by classes
[nit.git] / src / compiler / separate_compiler.nit
index f62d733..5b5975f 100644 (file)
@@ -456,14 +456,9 @@ class SeparateCompiler
                # Collect types to colorize
                var live_types = runtime_type_analysis.live_types
                var live_cast_types = runtime_type_analysis.live_cast_types
-               var mtypes = new HashSet[MType]
-               mtypes.add_all(live_types)
-               for c in self.box_kinds.keys do
-                       mtypes.add(c.mclass_type)
-               end
 
                # Compute colors
-               var poset = poset_from_mtypes(mtypes, live_cast_types)
+               var poset = poset_from_mtypes(live_types, live_cast_types)
                var colorer = new POSetColorer[MType]
                colorer.colorize(poset)
                type_ids = colorer.ids
@@ -471,20 +466,42 @@ class SeparateCompiler
                type_tables = build_type_tables(poset)
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
-               self.compile_resolution_tables(mtypes)
+               self.compute_resolution_tables(live_types)
 
                return poset
        end
 
        private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
                var poset = new POSet[MType]
+
+               # Instead of doing the full matrix mtypes X cast_types,
+               # a grouping is done by the base classes of the type so
+               # that we compare only types whose base classes are in inheritance.
+
+               var mtypes_by_class = new MultiHashMap[MClass, MType]
                for e in mtypes do
+                       var c = e.as_notnullable.as(MClassType).mclass
+                       mtypes_by_class[c].add(e)
+                       poset.add_node(e)
+               end
+
+               var casttypes_by_class = new MultiHashMap[MClass, MType]
+               for e in cast_types do
+                       var c = e.as_notnullable.as(MClassType).mclass
+                       casttypes_by_class[c].add(e)
                        poset.add_node(e)
-                       for o in cast_types do
-                               if e == o then continue
-                               poset.add_node(o)
-                               if e.is_subtype(mainmodule, null, o) then
-                                       poset.add_edge(e, o)
+               end
+
+               for c1, ts1 in mtypes_by_class do
+                       for c2 in c1.in_hierarchy(mainmodule).greaters do
+                               var ts2 = casttypes_by_class[c2]
+                               for e in ts1 do
+                                       for o in ts2 do
+                                               if e == o then continue
+                                               if e.is_subtype(mainmodule, null, o) then
+                                                       poset.add_edge(e, o)
+                                               end
+                                       end
                                end
                        end
                end
@@ -510,29 +527,33 @@ class SeparateCompiler
                return tables
        end
 
-       protected fun compile_resolution_tables(mtypes: Set[MType]) do
-               # resolution_tables is used to perform a type resolution at runtime in O(1)
-
+       # resolution_tables is used to perform a type resolution at runtime in O(1)
+       private fun compute_resolution_tables(mtypes: Set[MType]) do
                # During the visit of the body of classes, live_unresolved_types are collected
                # and associated to
                # Collect all live_unresolved_types (visited in the body of classes)
 
                # Determinate fo each livetype what are its possible requested anchored types
-               var mtype2unresolved = new HashMap[MClassType, Set[MType]]
+               var mtype2unresolved = new HashMap[MClass, Set[MType]]
                for mtype in self.runtime_type_analysis.live_types do
-                       var set = new HashSet[MType]
+                       var mclass = mtype.mclass
+                       var set = mtype2unresolved.get_or_null(mclass)
+                       if set == null then
+                               set = new HashSet[MType]
+                               mtype2unresolved[mclass] = set
+                       end
                        for cd in mtype.collect_mclassdefs(self.mainmodule) do
                                if self.live_unresolved_types.has_key(cd) then
                                        set.add_all(self.live_unresolved_types[cd])
                                end
                        end
-                       mtype2unresolved[mtype] = set
                end
 
                # Compute the table layout with the prefered method
-               var colorer = new BucketsColorer[MType, MType]
+               var colorer = new BucketsColorer[MClass, MType]
+
                opentype_colors = colorer.colorize(mtype2unresolved)
-               resolution_tables = self.build_resolution_tables(mtype2unresolved)
+               resolution_tables = self.build_resolution_tables(self.runtime_type_analysis.live_types, mtype2unresolved)
 
                # Compile a C constant for each collected unresolved type.
                # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
@@ -557,9 +578,10 @@ class SeparateCompiler
                #print ""
        end
 
-       fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+       fun build_resolution_tables(elements: Set[MClassType], map: Map[MClass, Set[MType]]): Map[MClassType, Array[nullable MType]] do
                var tables = new HashMap[MClassType, Array[nullable MType]]
-               for mclasstype, mtypes in elements do
+               for mclasstype in elements do
+                       var mtypes = map[mclasstype.mclass]
                        var table = new Array[nullable MType]
                        for mtype in mtypes do
                                var color = opentype_colors[mtype]
@@ -772,8 +794,6 @@ class SeparateCompiler
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
-               var vft = self.method_tables[mclass]
-               var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
                var rta = runtime_type_analysis
@@ -787,7 +807,8 @@ class SeparateCompiler
                        v.add_decl("const struct class class_{c_name} = \{")
                        v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
                        v.add_decl("\{")
-                       for i in [0 .. vft.length[ do
+                       var vft = self.method_tables.get_or_null(mclass)
+                       if vft != null then for i in [0 .. vft.length[ do
                                var mpropdef = vft[i]
                                if mpropdef == null then
                                        v.add_decl("NULL, /* empty */")
@@ -916,13 +937,20 @@ class SeparateCompiler
                else
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
-                       v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       var attrs = self.attr_tables.get_or_null(mclass)
+                       if attrs == null then
+                               v.add("{res} = nit_alloc(sizeof(struct instance));")
+                       else
+                               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       end
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       self.generate_init_attr(v, res, mtype)
-                       v.set_finalizer res
+                       if attrs != null then
+                               self.generate_init_attr(v, res, mtype)
+                               v.set_finalizer res
+                       end
                        v.add("return {res};")
                end
                v.add("\}")
@@ -973,6 +1001,7 @@ class SeparateCompiler
                                v.add_decl("NULL,")
                        else
                                var s = "type_{t.c_name}"
+                               undead_types.add(t.mclass_type)
                                v.require_declaration(s)
                                v.add_decl("&{s},")
                        end
@@ -1170,7 +1199,7 @@ class SeparateCompilerVisitor
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(valtype) then
                                self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
-                               self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
+                               self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")
@@ -1184,7 +1213,7 @@ class SeparateCompilerVisitor
                        # Bad things will appen!
                        var res = self.new_var(mtype)
                        self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
-                       self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
+                       self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); fatal_exit(1);")
                        return res
                end
        end
@@ -1210,7 +1239,7 @@ class SeparateCompilerVisitor
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
                                self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
-                               self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
+                               self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")
@@ -1770,7 +1799,7 @@ class SeparateCompilerVisitor
                                self.add("count_type_test_resolved_{tag}++;")
                        end
                else
-                       self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
+                       self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); fatal_exit(1);")
                end
 
                # check color is in table