sepcomp: move out opt_substitute_monomorph from compile_module_to_c
[nit.git] / src / compiler / separate_compiler.nit
index b14da6a..9273c45 100644 (file)
@@ -29,12 +29,15 @@ 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")
+       var opt_colors_are_symbols = new OptionBool("Store colors as symbols (link-boost)", "--colors-are-symbols")
        # --trampoline-call
        var opt_trampoline_call = new OptionBool("Use an indirection when calling", "--trampoline-call")
        # --substitute-monomorph
-       var opt_substitute_monomorph = new OptionBool("Replace monomorph trampoline with direct call", "--substitute-monomorph")
+       var opt_substitute_monomorph = new OptionBool("Replace monomorph trampoline with direct call (link-boost)", "--substitute-monomorph")
+       # --link-boost
+       var opt_link_boost = new OptionBool("Enable all link-boost optimizations", "--link-boost")
 
        # --inline-coloring-numbers
        var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
@@ -57,7 +60,8 @@ 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, opt_colors_are_symbols, opt_trampoline_call, opt_substitute_monomorph)
+               self.option_context.add_option(self.opt_no_shortcut_equate)
+               self.option_context.add_option(opt_colors_are_symbols, opt_trampoline_call, opt_substitute_monomorph, opt_link_boost)
                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)
@@ -74,6 +78,13 @@ redef class ToolContext
                        tc.opt_direct_call_monomorph.value = true
                        tc.opt_skip_dead_methods.value = true
                end
+               if tc.opt_link_boost.value then
+                       tc.opt_colors_are_symbols.value = true
+                       tc.opt_substitute_monomorph.value = true
+               end
+               if tc.opt_substitute_monomorph.value then
+                       tc.opt_trampoline_call.value = true
+               end
        end
 
        var separate_compiler_phase = new SeparateCompilerPhase(self, null)
@@ -160,6 +171,7 @@ class SeparateCompiler
                compiler.compile_nitni_global_ref_functions
                compiler.compile_main_function
                compiler.compile_finalizer_function
+               compiler.link_mmethods
 
                # compile methods
                for m in mainmodule.in_importation.greaters do
@@ -569,30 +581,65 @@ class SeparateCompiler
                                # Generate trampolines
                                if modelbuilder.toolcontext.opt_trampoline_call.value then
                                        r2.compile_trampolines(self)
-
-                                       # Replace monomorphic call to a trampoline by a direct call to the virtual implementation
-                                       if modelbuilder.toolcontext.opt_substitute_monomorph.value then do
-                                               var m = pd.mproperty
-                                               if rta == null then
-                                                       # Without RTA, monomorphic means alone (uniq name)
-                                                       if m.mpropdefs.length != 1 then break label
-                                               else
-                                                       # With RTA, monomorphic means only live methoddef
-                                                       if not rta.live_methoddefs.has(pd) then break label
-                                                       for md in m.mpropdefs do
-                                                               if md != pd and rta.live_methoddefs.has(md) then break label
-                                                       end
-                                               end
-                                               # Here the trick, GNU ld can substitute symbols with specific values.
-                                               var n2 = "CALL_" + m.const_color
-                                               linker_script.add("{n2} = {r2.c_name};")
-                                       end label
                                end
                        end
                end
                self.mainmodule = old_module
        end
 
+       # Process all introduced methods and compile some linking information (if needed)
+       fun link_mmethods
+       do
+               if not modelbuilder.toolcontext.opt_substitute_monomorph.value then return
+
+               for mmodule in mainmodule.in_importation.greaters do
+                       for cd in mmodule.mclassdefs do
+                               for m in cd.intro_mproperties do
+                                       if not m isa MMethod then continue
+                                       link_mmethod(m)
+                               end
+                       end
+               end
+       end
+
+       # Compile some linking information (if needed)
+       fun link_mmethod(m: MMethod)
+       do
+               var n2 = "CALL_" + m.const_color
+
+               # Replace monomorphic call by a direct call to the virtual implementation
+               var md = is_monomorphic(m)
+               if md != null then
+                       linker_script.add("{n2} = {md.virtual_runtime_function.c_name};")
+               end
+
+       end
+
+       # The single mmethodef called in case of monomorphism.
+       # Returns nul if dead or polymorphic.
+       fun is_monomorphic(m: MMethod): nullable MMethodDef
+       do
+               var rta = runtime_type_analysis
+               if rta == null then
+                       # Without RTA, monomorphic means alone (uniq name)
+                       if m.mpropdefs.length == 1 then
+                               return m.mpropdefs.first
+                       else
+                               return null
+                       end
+               else
+                       # With RTA, monomorphic means only live methoddef
+                       var res: nullable MMethodDef = null
+                       for md in m.mpropdefs do
+                               if rta.live_methoddefs.has(md) then
+                                       if res != null then return null
+                                       res = md
+                               end
+                       end
+                       return res
+               end
+       end
+
        # Globaly compile the type structure of a live type
        fun compile_type_to_c(mtype: MType)
        do
@@ -1985,6 +2032,9 @@ class SeparateRuntimeFunction
                compiler.names[self.c_name] = "{mmethoddef.full_name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})"
        end
 
+       # Compile the trampolines used to implement late-binding.
+       #
+       # See `opt_trampoline_call`.
        fun compile_trampolines(compiler: SeparateCompiler)
        do
                var recv = self.mmethoddef.mclassdef.bound_mtype