X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index 0ad35b9..b14da6a 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -31,6 +31,10 @@ 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") + # --substitute-monomorph + var opt_substitute_monomorph = new OptionBool("Replace monomorph trampoline with direct call", "--substitute-monomorph") # --inline-coloring-numbers var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers") @@ -53,7 +57,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, opt_substitute_monomorph) 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) @@ -560,7 +564,30 @@ class SeparateCompiler var r = pd.separate_runtime_function r.compile_to_c(self) var r2 = pd.virtual_runtime_function - r2.compile_to_c(self) + if r2 != r then r2.compile_to_c(self) + + # Generate trampolines + if modelbuilder.toolcontext.opt_trampoline_call.value then + r2.compile_trampolines(self) + + # Replace monomorphic call to a trampoline by a direct call to the virtual implementation + if modelbuilder.toolcontext.opt_substitute_monomorph.value then do + var m = pd.mproperty + if rta == null then + # Without RTA, monomorphic means alone (uniq name) + if m.mpropdefs.length != 1 then break label + else + # With RTA, monomorphic means only live methoddef + if not rta.live_methoddefs.has(pd) then break label + for md in m.mpropdefs do + if md != pd and rta.live_methoddefs.has(md) then break label + end + end + # Here the trick, GNU ld can substitute symbols with specific values. + var n2 = "CALL_" + m.const_color + linker_script.add("{n2} = {r2.c_name};") + end label + end end end self.mainmodule = old_module @@ -1104,7 +1131,7 @@ class SeparateCompilerVisitor return res end - return table_send(mmethod, arguments, mmethod.const_color) + return table_send(mmethod, arguments, mmethod) end # Handle common special cases before doing the effective method invocation @@ -1170,7 +1197,7 @@ class SeparateCompilerVisitor return res end - private fun table_send(mmethod: MMethod, arguments: Array[RuntimeVariable], const_color: String): nullable RuntimeVariable + private fun table_send(mmethod: MMethod, arguments: Array[RuntimeVariable], mentity: MEntity): nullable RuntimeVariable do compiler.modelbuilder.nb_invok_by_tables += 1 if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;") @@ -1180,8 +1207,10 @@ class SeparateCompilerVisitor var res0 = before_send(mmethod, arguments) + var runtime_function = mmethod.intro.virtual_runtime_function + var msignature = runtime_function.called_signature + var res: nullable RuntimeVariable - var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true) var ret = msignature.return_mtype if ret == null then res = null @@ -1189,10 +1218,8 @@ class SeparateCompilerVisitor res = self.new_var(ret) end - var s = new FlatBuffer var ss = new FlatBuffer - s.append("val*") ss.append("{recv}") for i in [0..msignature.arity[ do var a = arguments[i+1] @@ -1200,16 +1227,20 @@ class SeparateCompilerVisitor if i == msignature.vararg_rank then t = arguments[i+1].mcasttype end - s.append(", {t.ctype}") a = self.autobox(a, t) ss.append(", {a}") end - - var r - if ret == null then r = "void" else r = ret.ctype - self.require_declaration(const_color) - var call = "(({r} (*)({s}))({arguments.first}->class->vft[{const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/" + var const_color = mentity.const_color + 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};") @@ -1285,7 +1316,7 @@ class SeparateCompilerVisitor self.compiler.mainmodule = main return res end - return table_send(m.mproperty, arguments, m.const_color) + return table_send(m.mproperty, arguments, m) end redef fun vararg_instance(mpropdef, recv, varargs, elttype) @@ -1802,7 +1833,20 @@ redef class MMethodDef # Because the function is virtual, the signature must match the one of the original class var intromclassdef = mproperty.intro.mclassdef var recv = intromclassdef.bound_mtype + + res = separate_runtime_function + if res.called_recv == recv then + self.virtual_runtime_function_cache = res + return res + end + var msignature = mproperty.intro.msignature.resolve_for(recv, recv, intromclassdef.mmodule, true) + + if recv.ctype == res.called_recv.ctype and msignature.c_equiv(res.called_signature) then + self.virtual_runtime_function_cache = res + return res + end + res = new SeparateRuntimeFunction(self, recv, msignature, "VIRTUAL_{c_name}") self.virtual_runtime_function_cache = res res.is_thunk = true @@ -1812,6 +1856,23 @@ redef class MMethodDef private var virtual_runtime_function_cache: nullable SeparateRuntimeFunction end +redef class MSignature + # Does the C-version of `self` the same than the C-version of `other`? + fun c_equiv(other: MSignature): Bool + do + if self == other then return true + if arity != other.arity then return false + for i in [0..arity[ do + if mparameters[i].mtype.ctype != other.mparameters[i].mtype.ctype then return false + end + if return_mtype != other.return_mtype then + if return_mtype == null or other.return_mtype == null then return false + if return_mtype.ctype != other.return_mtype.ctype then return false + end + return true + end +end + # The C function associated to a methoddef separately compiled class SeparateRuntimeFunction super AbstractRuntimeFunction @@ -1830,6 +1891,37 @@ class SeparateRuntimeFunction redef fun to_s do return self.mmethoddef.to_s + # The C return type (something or `void`) + var c_ret: String is lazy do + var ret = called_signature.return_mtype + if ret != null then + return ret.ctype + else + return "void" + end + end + + # The C signature (only the parmeter part) + var c_sig: String is lazy do + var sig = new FlatBuffer + sig.append("({called_recv.ctype} self") + for i in [0..called_signature.arity[ do + var mtype = called_signature.mparameters[i].mtype + if i == called_signature.vararg_rank then + mtype = mmethoddef.mclassdef.mmodule.get_primitive_class("Array").get_mtype([mtype]) + end + sig.append(", {mtype.ctype} p{i}") + end + sig.append(")") + return sig.to_s + end + + # The C type for the function pointer. + var c_funptrtype: String is lazy do return "{c_ret}(*){c_sig}" + + # The arguments, as generated by `compile_to_c` + private var arguments: Array[RuntimeVariable] is noinit + redef fun compile_to_c(compiler) do var mmethoddef = self.mmethoddef @@ -1842,17 +1934,14 @@ class SeparateRuntimeFunction v.frame = frame var msignature = called_signature + var ret = called_signature.return_mtype var sig = new FlatBuffer var comment = new FlatBuffer - var ret = msignature.return_mtype - if ret != null then - sig.append("{ret.ctype} ") - else - sig.append("void ") - end + sig.append(c_ret) + sig.append(" ") sig.append(self.c_name) - sig.append("({selfvar.mtype.ctype} {selfvar}") + sig.append(c_sig) comment.append("({selfvar}: {selfvar.mtype}") arguments.add(selfvar) for i in [0..msignature.arity[ do @@ -1861,16 +1950,15 @@ class SeparateRuntimeFunction mtype = v.get_class("Array").get_mtype([mtype]) end comment.append(", {mtype}") - sig.append(", {mtype.ctype} p{i}") var argvar = new RuntimeVariable("p{i}", mtype, mtype) arguments.add(argvar) end - sig.append(")") comment.append(")") if ret != null then comment.append(": {ret}") end compiler.provide_declaration(self.c_name, "{sig};") + self.arguments = arguments.to_a v.add_decl("/* method {self} for {comment} */") v.add_decl("{sig} \{") @@ -1896,6 +1984,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