Merge: Use linker symbols to encode colors
[nit.git] / src / compiler / separate_compiler.nit
index 3645f54..68438c7 100644 (file)
@@ -29,6 +29,9 @@ redef class ToolContext
        var opt_no_union_attribute = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
        # --no-shortcut-equate
        var opt_no_shortcut_equate = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
+       # --colors-are-symbols
+       var opt_colors_are_symbols = new OptionBool("Store colors as symbols (faster)", "--colors-are-symbols")
+
        # --inline-coloring-numbers
        var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
        # --inline-some-methods
@@ -50,7 +53,7 @@ redef class ToolContext
                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_no_shortcut_equate, opt_colors_are_symbols)
                self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
                self.option_context.add_option(self.opt_colo_dead_methods)
                self.option_context.add_option(self.opt_tables_metrics)
@@ -90,45 +93,7 @@ redef class ModelBuilder
                self.toolcontext.info("*** GENERATING C ***", 1)
 
                var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
-               compiler.compile_header
-
-               # compile class structures
-               self.toolcontext.info("Property coloring", 2)
-               compiler.new_file("{mainmodule.name}.classes")
-               compiler.do_property_coloring
-               for m in mainmodule.in_importation.greaters do
-                       for mclass in m.intro_mclasses do
-                               if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
-                               compiler.compile_class_to_c(mclass)
-                       end
-               end
-
-               # The main function of the C
-               compiler.new_file("{mainmodule.name}.main")
-               compiler.compile_nitni_global_ref_functions
-               compiler.compile_main_function
-               compiler.compile_finalizer_function
-
-               # compile methods
-               for m in mainmodule.in_importation.greaters do
-                       self.toolcontext.info("Generate C for module {m}", 2)
-                       compiler.new_file("{m.name}.sep")
-                       compiler.compile_module_to_c(m)
-               end
-
-               # compile live & cast type structures
-               self.toolcontext.info("Type coloring", 2)
-               compiler.new_file("{mainmodule.name}.types")
-               var mtypes = compiler.do_type_coloring
-               for t in mtypes do
-                       compiler.compile_type_to_c(t)
-               end
-               # compile remaining types structures (useless but needed for the symbol resolution at link-time)
-               for t in compiler.undead_types do
-                       if mtypes.has(t) then continue
-                       compiler.compile_type_to_c(t)
-               end
-
+               compiler.do_compilation
                compiler.display_stats
 
                var time1 = get_time
@@ -156,20 +121,72 @@ class SeparateCompiler
        private var undead_types: Set[MType] = new HashSet[MType]
        private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
 
-       private var type_ids: Map[MType, Int]
-       private var type_colors: Map[MType, Int]
-       private var opentype_colors: Map[MType, Int]
-       protected var method_colors: Map[PropertyLayoutElement, Int]
-       protected var attr_colors: Map[MAttribute, Int]
+       private var type_ids: Map[MType, Int] is noinit
+       private var type_colors: Map[MType, Int] is noinit
+       private var opentype_colors: Map[MType, Int] is noinit
+       protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
+       protected var attr_colors: Map[MAttribute, Int] is noinit
 
-       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
-               super(mainmodule, mmbuilder)
+       init do
                var file = new_file("nit.common")
                self.header = new CodeWriter(file)
-               self.runtime_type_analysis = runtime_type_analysis
                self.compile_box_kinds
        end
 
+       redef fun do_compilation
+       do
+               var compiler = self
+               compiler.compile_header
+
+               var c_name = mainmodule.c_name
+
+               # compile class structures
+               modelbuilder.toolcontext.info("Property coloring", 2)
+               compiler.new_file("{c_name}.classes")
+               compiler.do_property_coloring
+               for m in mainmodule.in_importation.greaters do
+                       for mclass in m.intro_mclasses do
+                               #if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
+                               compiler.compile_class_to_c(mclass)
+                       end
+               end
+
+               # The main function of the C
+               compiler.new_file("{c_name}.main")
+               compiler.compile_nitni_global_ref_functions
+               compiler.compile_main_function
+               compiler.compile_finalizer_function
+
+               # compile methods
+               for m in mainmodule.in_importation.greaters do
+                       modelbuilder.toolcontext.info("Generate C for module {m.full_name}", 2)
+                       compiler.new_file("{m.c_name}.sep")
+                       compiler.compile_module_to_c(m)
+               end
+
+               # compile live & cast type structures
+               modelbuilder.toolcontext.info("Type coloring", 2)
+               compiler.new_file("{c_name}.types")
+               compiler.compile_types
+       end
+
+       # Color and compile type structures and cast information
+       fun compile_types
+       do
+               var compiler = self
+
+               var mtypes = compiler.do_type_coloring
+               for t in mtypes do
+                       compiler.compile_type_to_c(t)
+               end
+               # compile remaining types structures (useless but needed for the symbol resolution at link-time)
+               for t in compiler.undead_types do
+                       if mtypes.has(t) then continue
+                       compiler.compile_type_to_c(t)
+               end
+
+       end
+
        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
@@ -238,27 +255,21 @@ class SeparateCompiler
 
        fun compile_color_const(v: SeparateCompilerVisitor, m: Object, color: Int) do
                if color_consts_done.has(m) then return
-               if m isa MProperty then
+               if m isa MEntity then
                        if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
                                self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
-                       else
+                       else if not modelbuilder.toolcontext.opt_colors_are_symbols.value or not v.compiler.target_platform.supports_linker_script then
                                self.provide_declaration(m.const_color, "extern const int {m.const_color};")
                                v.add("const int {m.const_color} = {color};")
-                       end
-               else if m isa MPropDef then
-                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
-                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
-                       else
-                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
-                               v.add("const int {m.const_color} = {color};")
-                       end
-               else if m isa MType then
-                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
-                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
                        else
-                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
-                               v.add("const int {m.const_color} = {color};")
+                               # The color 'C' is the ``address'' of a false static variable 'XC'
+                               self.provide_declaration(m.const_color, "#define {m.const_color} ((long)&X{m.const_color})\nextern const void X{m.const_color};")
+                               if color == -1 then color = 0 # Symbols cannot be negative, so just use 0 for dead things
+                               # Teach the linker that the address of 'XC' is `color`.
+                               linker_script.add("X{m.const_color} = {color};")
                        end
+               else
+                       abort
                end
                color_consts_done.add(m)
        end
@@ -418,13 +429,12 @@ class SeparateCompiler
                var live_cast_types = runtime_type_analysis.live_cast_types
                var mtypes = new HashSet[MType]
                mtypes.add_all(live_types)
-               mtypes.add_all(live_cast_types)
                for c in self.box_kinds.keys do
                        mtypes.add(c.mclass_type)
                end
 
                # Compute colors
-               var poset = poset_from_mtypes(mtypes)
+               var poset = poset_from_mtypes(mtypes, live_cast_types)
                var colorer = new POSetColorer[MType]
                colorer.colorize(poset)
                type_ids = colorer.ids
@@ -437,12 +447,13 @@ class SeparateCompiler
                return poset
        end
 
-       private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do
+       private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
                var poset = new POSet[MType]
                for e in mtypes do
                        poset.add_node(e)
-                       for o in mtypes do
+                       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
@@ -1063,8 +1074,8 @@ class SeparateCompilerVisitor
        do
                var rta = compiler.runtime_type_analysis
                var mmethod = callsite.mproperty
-               # TODO: Inlining of new-style constructors
-               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then
+               # TODO: Inlining of new-style constructors with initializers
+               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and callsite.mpropdef.initializers.is_empty then
                        var tgs = rta.live_targets(callsite)
                        if tgs.length == 1 then
                                # DIRECT CALL
@@ -1112,10 +1123,10 @@ class SeparateCompilerVisitor
                var res: nullable RuntimeVariable = null
                var recv = arguments.first
                var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or mmethod.name == "==" or mmethod.name == "!="
-               var maybenull = recv.mcasttype isa MNullableType and consider_null
+               var maybenull = (recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType) and consider_null
                if maybenull then
                        self.add("if ({recv} == NULL) \{")
-                       if mmethod.name == "==" then
+                       if mmethod.name == "==" or mmethod.name == "is_same_instance" then
                                res = self.new_var(bool_type)
                                var arg = arguments[1]
                                if arg.mcasttype isa MNullableType then
@@ -1142,15 +1153,15 @@ class SeparateCompilerVisitor
                else
                        self.add("\{")
                end
-               if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
-                       if res == null then res = self.new_var(bool_type)
-                       # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
+               if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=" or mmethod.name == "is_same_instance") then
+                       # Recv is not null, thus if 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
+                               if res == null then res = self.new_var(bool_type)
+                               if mmethod.name == "!=" then
                                        self.add("{res} = 1; /* arg is null and recv is not */")
+                               else # `==` and `is_same_instance`
+                                       self.add("{res} = 0; /* arg is null but recv is not */")
                                end
                                self.add("\}") # closes the null case
                                self.add("if (0) \{") # what follow is useless, CC will drop it
@@ -1172,10 +1183,7 @@ class SeparateCompilerVisitor
                var res: nullable RuntimeVariable
                var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
                var ret = msignature.return_mtype
-               if mmethod.is_new then
-                       ret = arguments.first.mtype
-                       res = self.new_var(ret)
-               else if ret == null then
+               if ret == null then
                        res = null
                else
                        res = self.new_var(ret)
@@ -1226,10 +1234,7 @@ class SeparateCompilerVisitor
 
                var res: nullable RuntimeVariable
                var ret = mmethoddef.msignature.return_mtype
-               if mmethoddef.mproperty.is_new then
-                       ret = arguments.first.mtype
-                       res = self.new_var(ret)
-               else if ret == null then
+               if ret == null then
                        res = null
                else
                        ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
@@ -1240,7 +1245,7 @@ class SeparateCompilerVisitor
                        (compiler.modelbuilder.toolcontext.opt_inline_some_methods.value and mmethoddef.can_inline(self)) then
                        compiler.modelbuilder.nb_invok_by_inline += 1
                        if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_inline++;")
-                       var frame = new Frame(self, mmethoddef, recvtype, arguments)
+                       var frame = new StaticFrame(self, mmethoddef, recvtype, arguments)
                        frame.returnlabel = self.get_name("RET_LABEL")
                        frame.returnvar = res
                        var old_frame = self.frame
@@ -1290,11 +1295,11 @@ class SeparateCompilerVisitor
                # of the method (ie recv) if the static type is unresolved
                # This is more complex than usual because the unresolved type must not be resolved
                # with the current receiver (ie self).
-               # Therefore to isolate the resolution from self, a local Frame is created.
+               # Therefore to isolate the resolution from self, a local StaticFrame 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])
+               var frame = new StaticFrame(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)
@@ -1812,7 +1817,7 @@ class SeparateRuntimeFunction
                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)
+               var frame = new StaticFrame(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)
@@ -1822,9 +1827,6 @@ class SeparateRuntimeFunction
                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
@@ -1887,7 +1889,7 @@ class VirtualRuntimeFunction
                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)
+               var frame = new StaticFrame(v, mmethoddef, recv, arguments)
                v.frame = frame
 
                var sig = new FlatBuffer
@@ -1899,9 +1901,6 @@ class VirtualRuntimeFunction
                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
@@ -1951,20 +1950,18 @@ class VirtualRuntimeFunction
        redef fun call(v, arguments) do abort
 end
 
-redef class MType
-       fun const_color: String do return "COLOR_{c_name}"
+redef class MEntity
+       var const_color: String is lazy do return "COLOR_{c_name}"
 end
 
 interface PropertyLayoutElement end
 
 redef class MProperty
        super PropertyLayoutElement
-       fun const_color: String do return "COLOR_{c_name}"
 end
 
 redef class MPropDef
        super PropertyLayoutElement
-       fun const_color: String do return "COLOR_{c_name}"
 end
 
 redef class AMethPropdef