Merge: GitHub api: Issue events, contributor stats, files
[nit.git] / src / compiler / separate_compiler.nit
index 8152658..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)
@@ -252,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
@@ -1126,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
@@ -1156,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
@@ -1248,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
@@ -1298,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)
@@ -1820,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)
@@ -1892,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
@@ -1953,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