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=-c 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 --- aaaff8e681fc583e8104ff324e7dd2ce8e87eeb7 diff --combined src/compiler/abstract_compiler.nit index 2312544,3f0e8a1..dfe463c --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@@ -120,20 -120,16 +120,16 @@@ redef class ModelBuilde # 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 +185,10 @@@ class MakefileToolchai 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 +307,7 @@@ 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 +332,7 @@@ 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 +367,18 @@@ 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 +484,13 @@@ abstract class AbstractCompile # 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 +523,10 @@@ # 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 +697,11 @@@ extern void nitni_global_ref_decr( stru 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") @@@ -1040,8 -1056,8 +1056,8 @@@ abstract class AbstractCompilerVisito # The current visited AST node var current_node: nullable ANode = null is writable - # The current `Frame` - var frame: nullable Frame = null is writable + # The current `StaticFrame` + var frame: nullable StaticFrame = null is writable # Alias for self.compiler.mainmodule.object_type fun object_type: MClassType do return self.compiler.mainmodule.object_type @@@ -1670,8 -1686,8 +1686,8 @@@ class RuntimeVariabl end end -# A frame correspond to a visited property in a `GlobalCompilerVisitor` -class Frame +# The static context of a visited property in a `AbstractCompilerVisitor` +class StaticFrame type VISITOR: AbstractCompilerVisitor @@@ -2270,7 -2286,7 +2286,7 @@@ redef class AAttrPropde var oldnode = v.current_node v.current_node = self var old_frame = v.frame - var frame = new Frame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv]) + var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv]) v.frame = frame var value @@@ -2309,7 -2325,7 +2325,7 @@@ var oldnode = v.current_node v.current_node = self var old_frame = v.frame - var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv]) + var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv]) v.frame = frame # Force read to check the initialization v.read_attribute(self.mpropdef.mproperty, recv) diff --combined src/compiler/android_platform.nit index 9e47ee5,950125d..b7069e3 --- a/src/compiler/android_platform.nit +++ b/src/compiler/android_platform.nit @@@ -36,6 -36,8 +36,8 @@@ class AndroidPlatfor 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 @@@ -174,8 -176,7 +176,8 @@@ $(call import-module,android/native_app + android:debuggable="{{{not release}}}" + {{{icon_declaration}}}> @@@ -291,40 -292,12 +293,40 @@@ # Move the apk to the target var outname = outfile(compiler.mainmodule) - var src_apk_suffix if release then - src_apk_suffix = "release-unsigned" - else src_apk_suffix = "debug" + var apk_path = "{android_project_root}/bin/{compiler.mainmodule.name}-release-unsigned.apk" - toolcontext.exec_and_check(["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-{src_apk_suffix}.apk", outname], "Android project error") + # Sign APK + var keystore_path= "KEYSTORE".environ + var key_alias= "KEY_ALIAS".environ + var tsa_server= "TSA_SERVER".environ + + if key_alias.is_empty then + toolcontext.fatal_error(null, + "Fatal Error: the environment variable `KEY_ALIAS` must be set to use the `--release` option on Android projects.") + end + + args = ["jarsigner", "-sigalg", "MD5withRSA", "-digestalg", "SHA1", apk_path, key_alias] + + ## Use a custom keystore + if not keystore_path.is_empty then args.add_all(["-keystore", keystore_path]) + + ## Use a TSA server + if not tsa_server.is_empty then args.add_all(["-tsa", tsa_server]) + + toolcontext.exec_and_check(args, "Android project error") + + # Clean output file + if outname.to_path.exists then outname.to_path.delete + + # Align APK + args = ["zipalign", "4", apk_path, outname] + toolcontext.exec_and_check(args, "Android project error") + else + # Move to the expected output path + args = ["mv", "{android_project_root}/bin/{compiler.mainmodule.name}-debug.apk", outname] + toolcontext.exec_and_check(args, "Android project error") + end end end diff --combined src/compiler/separate_compiler.nit index 1f1cf67,2d98fb6..68438c7 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@@ -29,6 -29,9 +29,9 @@@ redef class ToolContex 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 +53,7 @@@ 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 +255,21 @@@ class SeparateCompile 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 @@@ -1248,7 -1245,7 +1245,7 @@@ class SeparateCompilerVisito (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 +1295,11 @@@ # 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 +1817,7 @@@ class SeparateRuntimeFunctio 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 +1889,7 @@@ class VirtualRuntimeFunctio 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 +1950,18 @@@ 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