nitg-s: option --use-naive-coloring now affects FT, VT and livegen fabrics coloring
[nit.git] / src / coloring.nit
index d12043b..b8c26d1 100644 (file)
@@ -178,26 +178,25 @@ end
 
 # MClassType coloring
 class TypeColoring
-       super AbstractColoring[MClassType]
+       super AbstractColoring[MType]
 
-       type T: MClassType
+       type T: MType
 
        private var mmodule: MModule
-       private var mtypes: Set[MClassType] = new HashSet[MClassType]
+       private var mtypes: Set[T]
 
        # caches
        private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
        private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
 
-       init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis) do
+       init(mainmodule: MModule, mtypes: Set[T]) do
                super(new TypeSorter(mainmodule), new ReverseTypeSorter(mainmodule))
                self.mmodule = mainmodule
-               self.mtypes.add_all(runtime_type_analysis.live_types)
-               self.mtypes.add_all(runtime_type_analysis.live_cast_types)
+               self.mtypes = mtypes
        end
 
        # Build type tables
-       private fun build_type_tables(mtypes: Set[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
+       fun build_type_tables(mtypes: Set[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
                var tables = new HashMap[T, Array[nullable T]]
 
                for mtype in mtypes do
@@ -235,7 +234,7 @@ class TypeColoring
 
        # Return all direct super elements of an element
        redef fun is_element_mi(element) do
-               return self.mmodule.flatten_mclass_hierarchy[element.mclass].direct_greaters.length > 1
+               return self.super_elements(element).length > 1
        end
 
        # Return all sub elements (directs and indirects) of an element
@@ -254,9 +253,105 @@ class TypeColoring
        end
 end
 
+class NaiveTypeColoring
+       super TypeColoring
+
+       init(mainmodule: MModule, mtypes: Set[T]) do
+               super(mainmodule, mtypes)
+       end
+
+       # naive coloring that use incremental coloring
+       redef fun colorize_elements(elements) do
+               for e in elements do
+                       self.coloration_result[e] = self.coloration_result.length
+               end
+       end
+end
+
+abstract class TypePerfectHashing
+       super TypeColoring
+
+       init(mainmodule: MModule, mtypes: Set[T]) do
+               super(mainmodule, mtypes)
+       end
+
+       fun compute_masks(elements: Set[T], ids: Map[T, Int]): Map[T, Int] do
+               for e in elements do
+                       # Create super type list
+                       var supers = new HashSet[T]
+                       supers.add_all(self.super_elements(e))
+                       supers.add(e)
+                       # Compute the hashing 'mask'
+                       self.coloration_result[e] = compute_mask(supers, ids)
+               end
+               return self.coloration_result
+       end
+
+       # Build type tables
+       fun hash_type_tables(mtypes: Set[T], ids: Map[T, Int], masks: Map[T, Int]): Map[T, Array[nullable T]] do
+               var tables = new HashMap[T, Array[nullable T]]
+
+               for mtype in mtypes do
+                       var table = new Array[nullable T]
+                       var supers = new HashSet[T]
+                       supers.add_all(self.super_elements(mtype))
+                       supers.add(mtype)
+
+                       for sup in supers do
+                               var color = phash(ids[sup], masks[mtype])
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               table[color] = sup
+                       end
+                       tables[mtype] = table
+               end
+               return tables
+       end
+
+       private fun compute_mask(mtypes: Set[T], ids: Map[T, Int]): Int do
+               var mask = 0
+               loop
+                       var used = new List[Int]
+                       for sup in mtypes do
+                               var res = op(mask, ids[sup])
+                               if used.has(res) then
+                                       break
+                               else
+                                       used.add(res)
+                               end
+                       end
+                       if used.length == mtypes.length then break
+                       mask += 1
+               end
+               return mask
+       end
+
+       private fun op(mask: Int, id:Int): Int is abstract
+       private fun phash(id: Int, mask: Int): Int do return op(mask, id)
+end
+
+class TypeModPerfectHashing
+       super TypePerfectHashing
+       init(mainmodule: MModule, mtypes: Set[T]) do
+               super(mainmodule, mtypes)
+       end
+       redef fun op(mask, id) do return mask % id
+end
+
+class TypeAndPerfectHashing
+       super TypePerfectHashing
+       init(mainmodule: MModule, mtypes: Set[T]) do
+               super(mainmodule, mtypes)
+       end
+       redef fun op(mask, id) do return mask.bin_and(id)
+end
+
 # A sorter for linearize list of types
-private class TypeSorter
-       super AbstractSorter[MClassType]
+class TypeSorter
+       super AbstractSorter[MType]
 
        private var mmodule: MModule
 
@@ -273,9 +368,11 @@ private class TypeSorter
 end
 
 # A sorter for reverse linearization
-private class ReverseTypeSorter
+class ReverseTypeSorter
        super TypeSorter
 
+       init(mmodule: MModule) do end
+
        redef fun compare(a, b) do
                if a == b then
                        return 0
@@ -304,12 +401,37 @@ class ClassColoring
                self.mmodule = mainmodule
        end
 
+       # Build type tables
+       fun build_type_tables(mclasses: Array[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
+               var tables = new HashMap[T, Array[nullable T]]
+
+               for mclasse in mclasses do
+                       var table = new Array[nullable T]
+                       var supers = new HashSet[T]
+                       supers.add_all(self.super_elements(mclasse))
+                       supers.add(mclasse)
+                       for sup in supers do
+                               var color = colors[sup]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               table[color] = sup
+                       end
+                       tables[mclasse] = table
+               end
+               return tables
+       end
+
        redef fun super_elements(element) do
                if not self.super_elements_cache.has_key(element) then
                        var supers = new HashSet[T]
-                       for sup in self.mmodule.flatten_mclass_hierarchy[element].greaters do
-                               if element == sup then continue
-                               supers.add(sup)
+                       if self.mmodule.flatten_mclass_hierarchy.has(element) then
+                               for sup in self.mmodule.flatten_mclass_hierarchy[element].greaters do
+                                       if element == sup then continue
+                                       supers.add(sup)
+                               end
                        end
                        self.super_elements_cache[element] = supers
                end
@@ -319,9 +441,11 @@ class ClassColoring
        private fun parent_elements(element: T): Set[T] do
                if not self.parent_elements_cache.has_key(element) then
                        var parents = new HashSet[T]
-                       for parent in self.mmodule.flatten_mclass_hierarchy[element].direct_greaters do
-                               if element == parent then continue
-                               parents.add(parent)
+                       if self.mmodule.flatten_mclass_hierarchy.has(element) then
+                               for parent in self.mmodule.flatten_mclass_hierarchy[element].direct_greaters do
+                                       if element == parent then continue
+                                       parents.add(parent)
+                               end
                        end
                        self.parent_elements_cache[element] = parents
                end
@@ -332,8 +456,10 @@ class ClassColoring
        redef fun sub_elements(element) do
                if not self.sub_elements_cache.has_key(element) then
                        var subs = new HashSet[T]
-                       for sub in self.mmodule.flatten_mclass_hierarchy[element].smallers do
-                               subs.add(sub)
+                       if self.mmodule.flatten_mclass_hierarchy.has(element) then
+                               for sub in self.mmodule.flatten_mclass_hierarchy[element].smallers do
+                                       subs.add(sub)
+                               end
                        end
                        self.sub_elements_cache[element] = subs
                end
@@ -342,10 +468,108 @@ class ClassColoring
 
        # Return all direct super elements of an element
        redef fun is_element_mi(element) do
+               if not self.mmodule.flatten_mclass_hierarchy.has(element) then return false
                return self.mmodule.flatten_mclass_hierarchy[element].direct_greaters.length > 1
        end
 end
 
+# incremental coloring (very naive)
+class NaiveClassColoring
+       super ClassColoring
+
+       init(mainmodule: MModule) do
+               super(mainmodule)
+       end
+
+       # naive coloring that use incremental coloring
+       redef fun colorize_elements(elements: Collection[MClass]) do
+               for e in elements do
+                       self.coloration_result[e] = self.coloration_result.length
+               end
+       end
+end
+
+abstract class ClassPerfectHashing
+       super ClassColoring
+
+       init(mainmodule: MModule) do
+               super(mainmodule)
+       end
+
+       fun compute_masks(elements: Set[T], ids: Map[T, Int]): Map[T, Int] do
+               for e in elements do
+                       # Create super type list
+                       var supers = new HashSet[T]
+                       supers.add_all(self.super_elements(e))
+                       supers.add(e)
+                       # Compute the hashing 'mask'
+                       self.coloration_result[e] = compute_mask(supers, ids)
+               end
+               return self.coloration_result
+       end
+
+       # Build type tables
+       fun hash_type_tables(mtypes: Set[T], ids: Map[T, Int], masks: Map[T, Int]): Map[T, Array[nullable T]] do
+               var tables = new HashMap[T, Array[nullable T]]
+
+               for mtype in mtypes do
+                       var table = new Array[nullable T]
+                       var supers = new HashSet[T]
+                       supers.add_all(self.super_elements(mtype))
+                       supers.add(mtype)
+
+                       for sup in supers do
+                               var color = phash(ids[sup], masks[mtype])
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               table[color] = sup
+                       end
+                       tables[mtype] = table
+               end
+               return tables
+       end
+
+       private fun compute_mask(mtypes: Set[T], ids: Map[T, Int]): Int do
+               var mask = 0
+               loop
+                       var used = new List[Int]
+                       for sup in mtypes do
+                               var res = op(mask, ids[sup])
+                               if used.has(res) then
+                                       break
+                               else
+                                       used.add(res)
+                               end
+                       end
+                       if used.length == mtypes.length then break
+                       mask += 1
+               end
+               return mask
+       end
+
+       private fun op(mask: Int, id:Int): Int is abstract
+       private fun phash(id: Int, mask: Int): Int do return op(mask, id)
+end
+
+class ClassModPerfectHashing
+       super ClassPerfectHashing
+       init(mainmodule: MModule) do
+               super(mainmodule)
+       end
+       redef fun op(mask, id) do return mask % id
+end
+
+class ClassAndPerfectHashing
+       super ClassPerfectHashing
+       init(mainmodule: MModule) do
+               super(mainmodule)
+       end
+       redef fun op(mask, id) do return mask.bin_and(id)
+end
+
 # A sorter for linearize list of classes
 private class ClassSorter
        super AbstractSorter[MClass]
@@ -355,7 +579,7 @@ private class ClassSorter
        redef fun compare(a, b) do
                if a == b then
                        return 0
-               else if self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
+               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
                        return -1
                end
                return 1
@@ -371,7 +595,7 @@ private class ReverseClassSorter
        redef fun compare(a, b) do
                if a == b then
                        return 0
-               else if self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
+               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
                        return 1
                end
                return -1
@@ -391,20 +615,22 @@ class PropertyColoring
                self.class_coloring = class_coloring
        end
 
-       private fun colorize: Map[MPROP, Int] do
+       fun colorize: Map[MPROP, Int] do
                colorize_core_properties
                colorize_crown_properties
                return self.coloration_result
        end
 
-       private fun build_property_tables: Map[MClass, Array[nullable MPROPDEF]] do
+       fun build_property_tables: Map[MClass, Array[nullable MPROPDEF]] do
                var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
 
                for mclass in self.class_coloring.coloration_result.keys do
                        var table = new Array[nullable MPROPDEF]
-
-                       # first, fill table from parents
-                       for parent in self.class_coloring.super_elements(mclass) do
+                       # first, fill table from parents by reverse linearization order
+                       var parents = new OrderedSet[MClass]
+                       parents.add_all(self.class_coloring.super_elements(mclass))
+                       self.class_coloring.reverse_sorter.sort(parents)
+                       for parent in parents do
                                for mproperty in self.properties(parent) do
                                        var color = self.coloration_result[mproperty]
                                        if table.length <= color then
@@ -457,6 +683,7 @@ class PropertyColoring
                                if self.class_coloring.conflicts_graph.has_key(mclass) then
                                        color = max_color(color, self.class_coloring.conflicts_graph[mclass])
                                end
+
                                # colorize
                                colorize_elements(self.properties(mclass), color)
                        end
@@ -497,10 +724,15 @@ class PropertyColoring
        # properties cache
        private var properties_cache: Map[MClass, Set[MPROP]] = new HashMap[MClass, Set[MPROP]]
 
-       # All 'mmethod' associated to all 'mclassdefs' of the class
+       # All 'mproperties' associated to all 'mclassdefs' of the class
        private fun properties(mclass: MClass): Set[MPROP] do
                if not self.properties_cache.has_key(mclass) then
                        var properties = new HashSet[MPROP]
+                       var parents = self.class_coloring.super_elements(mclass)
+                       for parent in parents do
+                               properties.add_all(self.properties(parent))
+                       end
+
                        for mclassdef in mclass.mclassdefs do
                                for mpropdef in mclassdef.mpropdefs do
                                        var mproperty = mpropdef.mproperty
@@ -521,6 +753,7 @@ class MethodColoring
 
        redef type MPROP: MMethod
        redef type MPROPDEF: MMethodDef
+       init(class_coloring: ClassColoring) do end
 end
 
 # MAttribute coloring
@@ -529,6 +762,35 @@ class AttributeColoring
 
        redef type MPROP: MAttribute
        redef type MPROPDEF: MAttributeDef
+       init(class_coloring: ClassColoring) do end
+end
+
+# MVirtualTypeProp coloring
+class VTColoring
+       super PropertyColoring
+
+       redef type MPROP: MVirtualTypeProp
+       redef type MPROPDEF: MVirtualTypeDef
+       init(class_coloring: ClassColoring) do end
+end
+
+class NaiveVTColoring
+       super VTColoring
+
+       init(class_coloring: ClassColoring) do end
+
+       redef fun colorize: Map[MPROP, Int] do
+               var mclasses = new HashSet[MClass]
+               mclasses.add_all(self.class_coloring.core)
+               mclasses.add_all(self.class_coloring.crown)
+               var min_color = 0
+
+               for mclass in mclasses do
+                       min_color = max_color(min_color, mclasses)
+                       colorize_elements(self.properties(mclass), min_color)
+               end
+               return self.coloration_result
+       end
 end
 
 # MParameterType coloring
@@ -540,7 +802,7 @@ class FTColoring
                self.class_coloring = class_coloring
        end
 
-       private fun colorize: Map[MParameterType, Int] do
+       fun colorize: Map[MParameterType, Int] do
                colorize_core_properties
                colorize_crown_properties
                return self.coloration_result
@@ -618,7 +880,7 @@ class FTColoring
                return fts_cache[mclass]
        end
 
-       private fun build_ft_tables: Map[MClass, Array[nullable MParameterType]] do
+       fun build_ft_tables: Map[MClass, Array[nullable MParameterType]] do
                var tables = new HashMap[MClass, Array[nullable MParameterType]]
 
                for mclass in self.class_coloring.coloration_result.keys do
@@ -653,12 +915,206 @@ class FTColoring
        end
 end
 
+class NaiveFTColoring
+       super FTColoring
+
+       init(class_coloring: ClassColoring) do end
+
+       redef fun colorize: Map[MParameterType, Int] do
+               var mclasses = new HashSet[MClass]
+               mclasses.add_all(self.class_coloring.core)
+               mclasses.add_all(self.class_coloring.crown)
+               var min_color = 0
+
+               for mclass in mclasses do
+                       min_color = max_color(min_color, mclasses)
+                       colorize_elements(self.fts(mclass), min_color)
+               end
+               return self.coloration_result
+       end
+end
+
+# Live Entries coloring
+class LiveEntryColoring
+
+       private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
+       private var conflicts_graph_cache: nullable HashMap[MType, Set[MType]]
+       var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
+
+       init do end
+
+       fun colorize(elements: Collection[MType]): Map[MType, Int] do
+               # compute conflicts
+               build_conflicts_graph(elements)
+
+               # colorize graph
+               colorize_elements(elements)
+
+               return coloration_result
+       end
+
+       # Build type tables
+       fun build_livetype_tables(mtypes: Set[MType]): Map[MClass, Array[nullable Object]] do
+               var livetypes_tables = new HashMap[MClass, Array[nullable Object]]
+               self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
+
+               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]
+                               else
+                                       table = new Array[nullable Object]
+                                       livetypes_tables[mtype.mclass] = table
+                               end
+                               if livetypes_tables_sizes.has_key(mtype.mclass) then
+                                       sizes = livetypes_tables_sizes[mtype.mclass]
+                               else
+                                       sizes = new Array[Int]
+                                       livetypes_tables_sizes[mtype.mclass] = sizes
+                               end
+                               build_livetype_table(mtype, 0, table, sizes)
+                       end
+               end
+
+               return livetypes_tables
+       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 not self.coloration_result.has_key(ft) then return
+               var color = self.coloration_result[ft]
+
+               if current_rank >= sizes.length then
+                       sizes[current_rank] = color + 1
+               else if color >= sizes[current_rank] then
+                       sizes[current_rank] = color + 1
+               end
+
+               if color > table.length then
+                       for i in [table.length .. color[ do table[i] = null
+               end
+
+               if current_rank == mtype.arguments.length - 1 then
+                       table[color] = mtype
+               else
+                       var ft_table: Array[nullable Object]
+                       if color < table.length and table[color] != null then
+                               ft_table = table[color].as(Array[nullable Object])
+                       else
+                               ft_table = new Array[nullable Object]
+                       end
+                       table[color] = ft_table
+                       build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
+               end
+       end
+
+       # Colorize a collection of elements
+       fun colorize_elements(elements: Collection[MType]) do
+               var min_color = 0
+
+               for element in elements do
+                       var color = min_color
+                       while not self.is_color_free(element, color) do
+                               color += 1
+                       end
+                       coloration_result[element] = color
+                       color = min_color
+               end
+       end
+
+       # Check if a related element to the element already use the color
+       private fun is_color_free(element: MType, color: Int): Bool do
+               if conflicts_graph.has_key(element) then
+                       for st in conflicts_graph[element] do
+                               if coloration_result.has_key(st) and coloration_result[st] == color then return false
+                       end
+               end
+               return true
+       end
+
+       # look for types in the same generic signatures
+       private fun build_conflicts_graph(elements: Collection[MType]) do
+               # regroup types by classes
+               var genclasses = new HashMap[MClass, Set[MType]]
+               for e in elements do
+                       if e isa MGenericType then
+                               if not genclasses.has_key(e.mclass) then
+                                       genclasses[e.mclass] = new HashSet[MType]
+                               end
+                               genclasses[e.mclass].add(e)
+                       end
+               end
+
+               # for each class
+               self.conflicts_graph_cache = new HashMap[MType, Set[MType]]
+               for mclass, mtypes in genclasses do
+                       # for each rank
+                       for rank in [0..mclass.arity[ do
+                               # for each live type
+                               for mtype in mtypes do
+                                       var mclasstype: MClassType
+                                       if mtype isa MNullableType then
+                                               mclasstype = mtype.mtype.as(MClassType)
+                                       else
+                                               mclasstype = mtype.as(MClassType)
+                                       end
+                                       var ft = mclasstype.arguments[rank]
+                                       for otype in mtypes do
+                                               if mtype == otype then continue
+                                               var oclasstype: MClassType
+                                               if otype isa MNullableType then
+                                                       oclasstype = otype.mtype.as(MClassType)
+                                               else
+                                                       oclasstype = otype.as(MClassType)
+                                               end
+                                               var oft = oclasstype.arguments[rank]
+                                               self.add_conflict(ft, oft)
+                                       end
+                               end
+                       end
+               end
+       end
+
+       private fun add_conflict(mtype: MType, otype: MType) do
+               if mtype == otype then return
+               if not self.conflicts_graph_cache.has_key(mtype) then  self.conflicts_graph_cache[mtype] = new HashSet[MClassType]
+               self.conflicts_graph_cache[mtype].add(otype)
+               if not self.conflicts_graph_cache.has_key(otype) then  self.conflicts_graph_cache[otype] = new HashSet[MClassType]
+               self.conflicts_graph_cache[otype].add(mtype)
+       end
+       private fun conflicts_graph: Map[MType, Set[MType]] do return conflicts_graph_cache.as(not null)
+end
+
+class NaiveLiveEntryColoring
+       super LiveEntryColoring
+
+       init do end
+
+       redef fun colorize_elements(elements: Collection[MType]) do
+               var color = 0
+               for element in elements do
+                       coloration_result[element] = color
+                       color += 1
+               end
+       end
+end
+
+
 # Utils
 
 # An ordered set
-private class OrderedSet[E]
+class OrderedSet[E]
        super Array[E]
 
+       init do end
+
+       init from(elements: Set[E]) do
+               self.add_all(elements)
+       end
+
        redef fun add(e) do
                if not self.has(e) then
                        super(e)
@@ -671,4 +1127,9 @@ private class OrderedSet[E]
                for e in self do if not o.has(e) then res.add(e)
                return res
        end
+
+       # Linearize a set of elements
+       fun linearize(sorter: AbstractSorter[E]) do
+               sorter.sort(self)
+       end
 end
\ No newline at end of file