sep_compiler: optionally use a trampoline before the vft call
authorJean Privat <jean@pryen.org>
Sat, 7 Feb 2015 15:45:28 +0000 (22:45 +0700)
committerJean Privat <jean@pryen.org>
Tue, 10 Feb 2015 03:26:08 +0000 (10:26 +0700)
Signed-off-by: Jean Privat <jean@pryen.org>

share/man/nitc.md
src/compiler/separate_compiler.nit

index f98d50d..75da7c8 100644 (file)
@@ -274,6 +274,36 @@ will increase.
 :   Do not compile dead methods (semi-global).
     Need `--rta`.
 
+## LINK-BOOST OPTIMIZATIONS
+
+In `--separate` and in `--erasure` modes, some optimization can be gained by hijacking the linker process.
+
+Warning: these optimisations are not portable since they use extra features of the GNU linker `ld`.
+However, there is very few reasons to not use them if GNU `ld` is available.
+
+`--link-boost`
+:   Enable all link-boost optimizations.
+
+`--colors-are-symbols`
+:   Store colors as symbols instead of static data.
+
+    By default, the various identifiers used to implement OO-mechanisms are stored as genuine constant static variables.
+
+    This option uses linker symbols to encode these identifiers.
+    This makes the compiled program faster since less indirections are required to get the values.
+    It also produces executables that are a little bit smaller since static memory does not have to store the colors.
+
+`--substitute-monomorph`
+:   Replace monomorphic trampolines with direct call.
+
+    Late-binding is implemented with *trampolines*, that are small functions that just select and jump the to right implementations.
+    If, at link-time, is it known that the target will always by the same implementation then all calls to the trampoline are replaced by
+    direct calls to this single implementation.
+
+    Note that using trampolines as indirection slows down the executable.
+    However, it is expected that the gain of monomorphic direct-calls overcompensates the additional indirections in polymorphic trampoline-calls.
+
+    Note: automatically enable option `--trampoline-call`.
 
 ## DANGEROUS OPTIMIZATIONS
 
@@ -329,21 +359,13 @@ Usually you do not need them since they make the generated code slower.
 `--colo-dead-methods`
 :   Force colorization of dead methods.
 
-`--colors-are-symbols`
-:   Store colors as symbols instead of static data.
-
-    By default, the various identifiers used to implement OO-mechanisms are stored as genuine constant static variables.
-
-    This option uses linker symbols to encode these identifiers.
-    This makes the compiled program faster since less indirections are required to get the values.
-    It also produces executables that are a little bit smaller since static memory does not have to store the colors.
-
-    Warning: the usage of linker symbols is not portable on all toolchains (eg. Mac OS X).
-    Also, this option does nothing on some platforms (like android).
-
 `--no-gcc-directive`
 :   Disable advanced gcc directives for optimization.
 
+`--trampoline-call`
+:   Use an indirection when calling.
+
+    Just add the trampolines of `--substitute-monomorph` without doing any aditionnal optimizations.
 
 ## INTERNAL OPTIONS
 
index 437840e..6b7a004 100644 (file)
@@ -31,6 +31,8 @@ redef class ToolContext
        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")
+       # --trampoline-call
+       var opt_trampoline_call = new OptionBool("Use an indirection when calling", "--trampoline-call")
 
        # --inline-coloring-numbers
        var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
@@ -53,7 +55,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, opt_colors_are_symbols)
+               self.option_context.add_option(self.opt_no_shortcut_equate, opt_colors_are_symbols, opt_trampoline_call)
                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)
@@ -561,6 +563,11 @@ class SeparateCompiler
                                r.compile_to_c(self)
                                var r2 = pd.virtual_runtime_function
                                if r2 != r then r2.compile_to_c(self)
+
+                               # Generate trampolines
+                               if modelbuilder.toolcontext.opt_trampoline_call.value then
+                                       r2.compile_trampolines(self)
+                               end
                        end
                end
                self.mainmodule = old_module
@@ -1204,8 +1211,15 @@ class SeparateCompilerVisitor
                        ss.append(", {a}")
                end
 
-               self.require_declaration(const_color)
-               var call = "(({runtime_function.c_funptrtype})({arguments.first}->class->vft[{const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
+               var call
+               if not compiler.modelbuilder.toolcontext.opt_trampoline_call.value then
+                       self.require_declaration(const_color)
+                       call = "(({runtime_function.c_funptrtype})({arguments.first}->class->vft[{const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
+               else
+                       var callsym = "CALL_" + const_color
+                       self.require_declaration(callsym)
+                       call = "{callsym}({ss}) /* {mmethod} on {arguments.first.inspect}*/"
+               end
 
                if res != null then
                        self.add("{res} = {call};")
@@ -1949,6 +1963,47 @@ class SeparateRuntimeFunction
                v.add("\}")
                compiler.names[self.c_name] = "{mmethoddef.full_name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})"
        end
+
+       fun compile_trampolines(compiler: SeparateCompiler)
+       do
+               var recv = self.mmethoddef.mclassdef.bound_mtype
+               var selfvar = arguments.first
+               var ret = called_signature.return_mtype
+
+               if mmethoddef.is_intro and recv.ctype == "val*" then
+                       var m = mmethoddef.mproperty
+                       var n2 = "CALL_" + m.const_color
+                       compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};")
+                       var v2 = compiler.new_visitor
+                       v2.add "{c_ret} {n2}{c_sig} \{"
+                       v2.require_declaration(m.const_color)
+                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       if ret != null then
+                               v2.add "return {call}"
+                       else
+                               v2.add call
+                       end
+
+                       v2.add "\}"
+
+               end
+               if mmethoddef.has_supercall and recv.ctype == "val*" then
+                       var m = mmethoddef
+                       var n2 = "CALL_" + m.const_color
+                       compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};")
+                       var v2 = compiler.new_visitor
+                       v2.add "{c_ret} {n2}{c_sig} \{"
+                       v2.require_declaration(m.const_color)
+                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       if ret != null then
+                               v2.add "return {call}"
+                       else
+                               v2.add call
+                       end
+
+                       v2.add "\}"
+               end
+       end
 end
 
 redef class MEntity