From: Jean Privat Date: Sat, 7 Feb 2015 15:45:28 +0000 (+0700) Subject: sep_compiler: optionally use a trampoline before the vft call X-Git-Tag: v0.7.2~20^2~5 X-Git-Url: http://nitlanguage.org sep_compiler: optionally use a trampoline before the vft call Signed-off-by: Jean Privat --- diff --git a/share/man/nitc.md b/share/man/nitc.md index f98d50d..75da7c8 100644 --- a/share/man/nitc.md +++ b/share/man/nitc.md @@ -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 diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index 437840e..6b7a004 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -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