From: Jean Privat Date: Tue, 13 Jan 2015 01:29:02 +0000 (-0500) Subject: Merge: Use linker symbols to encode colors X-Git-Tag: v0.7.1~34 X-Git-Url: http://nitlanguage.org?hp=c11db51d0cf96cfcfe340e7fe51637496fecc794 Merge: Use linker symbols to encode colors Genuine constant static variables are used to store the colors used in OO mechanisms. This makes the compiler program slower since additional indirections are required to get the values. It also produces a little bit larger executables since static memory has to store the colors. This PR introduce a trick user in the original PRM that uses linker symbols to encode the colors. It is not completely portable so it must be activated with the option `--colors-are-symbols` For numbers (with the traditional nitc/nitc/nitc) before: 0m7.544s after: 0m7.228s (so -4%) Pull-Request: #1093 Reviewed-by: Alexandre Terrasa --- diff --git a/share/man/nitc.md b/share/man/nitc.md index 9c1d562..f98d50d 100644 --- a/share/man/nitc.md +++ b/share/man/nitc.md @@ -329,6 +329,18 @@ 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. diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 2312544..dfe463c 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -120,20 +120,16 @@ redef class ModelBuilder # Simple indirection to `Toolchain::write_and_make` protected fun write_and_make(compiler: AbstractCompiler) do - var platform = compiler.mainmodule.target_platform - var toolchain - if platform == null then - toolchain = new MakefileToolchain(toolcontext) - else - toolchain = platform.toolchain(toolcontext) - end + var platform = compiler.target_platform + var toolchain = platform.toolchain(toolcontext) compile_dir = toolchain.compile_dir toolchain.write_and_make compiler end end redef class Platform - fun toolchain(toolcontext: ToolContext): Toolchain is abstract + # The specific tool-chain associated to the platform + fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext) end class Toolchain @@ -189,10 +185,10 @@ class MakefileToolchain fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) do - var platform = compiler.mainmodule.target_platform - if self.toolcontext.opt_stacktrace.value == "nitstack" and (platform == null or platform.supports_libunwind) then compiler.build_c_to_nit_bindings + var platform = compiler.target_platform + if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings var cc_opt_with_libgc = "-DWITH_LIBGC" - if platform != null and not platform.supports_libgc then cc_opt_with_libgc = "" + if not platform.supports_libgc then cc_opt_with_libgc = "" # Add gc_choser.h to aditionnal bodies var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc) @@ -311,7 +307,7 @@ class MakefileToolchain fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) do var mainmodule = compiler.mainmodule - var platform = compiler.mainmodule.target_platform + var platform = compiler.target_platform var outname = outfile(mainmodule) @@ -336,7 +332,7 @@ class MakefileToolchain makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") var ost = toolcontext.opt_stacktrace.value - if (ost == "libunwind" or ost == "nitstack") and (platform == null or platform.supports_libunwind) then makefile.write("NEED_LIBUNWIND := YesPlease\n") + if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n") # Dynamic adaptations # While `platform` enable complex toolchains, they are statically applied @@ -371,6 +367,18 @@ class MakefileToolchain dep_rules.add(o) end + # Generate linker script, if any + if not compiler.linker_script.is_empty then + var linker_script_path = "{compile_dir}/linker_script" + ofiles.add "linker_script" + var f = new OFStream.open(linker_script_path) + for l in compiler.linker_script do + f.write l + f.write "\n" + end + f.close + end + var java_files = new Array[ExternFile] var pkgconfigs = new Array[String] @@ -476,9 +484,13 @@ abstract class AbstractCompiler # Is hardening asked? (see --hardening) fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value + # The targeted specific platform + var target_platform: Platform is noinit + init do self.realmainmodule = mainmodule + target_platform = mainmodule.target_platform or else new Platform end # Do the full code generation of the program `mainmodule` @@ -511,6 +523,10 @@ abstract class AbstractCompiler # Where global declaration are stored (the main .h) var header: CodeWriter is writable, noinit + # Additionnal linker script for `ld`. + # Mainly used to do specific link-time symbol resolution + var linker_script = new Array[String] + # Provide a declaration that can be requested (before or latter) by a visitor fun provide_declaration(key: String, s: String) do @@ -681,11 +697,11 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); var v = self.new_visitor v.add_decl("#include ") var ost = modelbuilder.toolcontext.opt_stacktrace.value - var platform = mainmodule.target_platform + var platform = target_platform - if platform != null and not platform.supports_libunwind then ost = "none" + if not platform.supports_libunwind then ost = "none" - var no_main = (platform != null and platform.no_main) or modelbuilder.toolcontext.opt_no_main.value + var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value if ost == "nitstack" or ost == "libunwind" then v.add_decl("#define UNW_LOCAL_ONLY") diff --git a/src/compiler/android_platform.nit b/src/compiler/android_platform.nit index 9e47ee5..b7069e3 100644 --- a/src/compiler/android_platform.nit +++ b/src/compiler/android_platform.nit @@ -36,6 +36,8 @@ class AndroidPlatform redef fun supports_libunwind do return false + redef fun supports_linker_script do return false + redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext) end diff --git a/src/compiler/emscripten_platform.nit b/src/compiler/emscripten_platform.nit index 0a262fc..6332098 100644 --- a/src/compiler/emscripten_platform.nit +++ b/src/compiler/emscripten_platform.nit @@ -33,6 +33,7 @@ class EmscriptenPlatform redef fun supports_libunwind do return false redef fun supports_libgc do return false + redef fun supports_linker_script do return false redef fun toolchain(toolcontext) do return new EnscriptenToolchain(toolcontext) end diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index 1f1cf67..68438c7 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -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 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 MPropDef 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 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 @@ -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 diff --git a/src/platform.nit b/src/platform.nit index 8f2edbb..5b7f7a5 100644 --- a/src/platform.nit +++ b/src/platform.nit @@ -103,7 +103,7 @@ end # Sub-classes of `Platform` represent the target platform of a compilation # # Services will be added to this class in other modules. -abstract class Platform +class Platform # Does the platform provide and support the library `unwind`? fun supports_libunwind: Bool do return true @@ -112,4 +112,7 @@ abstract class Platform # Does this platform declare its own main function? If so, we won't generate one in Nit. fun no_main: Bool do return false + + # Does the platform accepts linker scripts? + fun supports_linker_script: Bool do return true end