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 <alexandre@moz-code.org>
`--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.
# 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
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)
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)
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
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]
# 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`
# 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
var v = self.new_visitor
v.add_decl("#include <signal.h>")
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")
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
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
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
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)
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
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
# 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
# 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