X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/global_compiler.nit b/src/compiler/global_compiler.nit index 9f082df..8f3b437 100644 --- a/src/compiler/global_compiler.nit +++ b/src/compiler/global_compiler.nit @@ -59,6 +59,43 @@ redef class ModelBuilder self.toolcontext.info("*** GENERATING C ***", 1) var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis) + compiler.do_compilation + compiler.display_stats + + var time1 = get_time + self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2) + write_and_make(compiler) + end +end + +# Compiler that use global compilation and perform hard optimisations like: +# * customization +# * switch dispatch +# * inlining +class GlobalCompiler + super AbstractCompiler + + redef type VISITOR: GlobalCompilerVisitor + + # The result of the RTA (used to know live types and methods) + var runtime_type_analysis: RapidTypeAnalysis + + init + do + var file = new_file("{mainmodule.c_name}.nitgg") + self.header = new CodeWriter(file) + self.live_primitive_types = new Array[MClassType] + for t in runtime_type_analysis.live_types do + if t.is_c_primitive or t.mclass.name == "Pointer" then + self.live_primitive_types.add(t) + end + end + end + + redef fun do_compilation + do + var compiler = self + compiler.compile_header if mainmodule.model.get_mclasses_by_name("Pointer") != null then @@ -72,7 +109,7 @@ redef class ModelBuilder # Init instance code (allocate and init-arguments) for t in runtime_type_analysis.live_types do - if t.ctype == "val*" then + if not t.is_c_primitive then compiler.generate_init_instance(t) if t.mclass.kind == extern_kind then compiler.generate_box_instance(t) @@ -89,41 +126,11 @@ redef class ModelBuilder # Compile until all runtime_functions are visited while not compiler.todos.is_empty do var m = compiler.todos.shift - self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3) + modelbuilder.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3) m.compile_to_c(compiler) end - self.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2) - - compiler.display_stats - - var time1 = get_time - self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2) - write_and_make(compiler) - end -end - -# Compiler that use global compilation and perform hard optimisations like: -# * customization -# * switch dispatch -# * inlining -class GlobalCompiler - super AbstractCompiler - - redef type VISITOR: GlobalCompilerVisitor + modelbuilder.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2) - # The result of the RTA (used to know live types and methods) - var runtime_type_analysis: RapidTypeAnalysis - - init - do - var file = new_file("{mainmodule.c_name}.nitgg") - self.header = new CodeWriter(file) - self.live_primitive_types = new Array[MClassType] - for t in runtime_type_analysis.live_types do - if t.ctype != "val*" or t.mclass.name == "Pointer" then - self.live_primitive_types.add(t) - end - end end # Compile class names (for the class_name and output_class_name methods) @@ -144,7 +151,7 @@ class GlobalCompiler if self.classids.has_key(mtype) then return self.classids[mtype] end - print "No classid for {mtype}" + print_error "No classid for {mtype}" abort end @@ -197,6 +204,23 @@ class GlobalCompiler v.add_decl("{mtype.arguments.first.ctype} values[1];") end + if all_routine_types_name.has(mtype.mclass.name) then + v.add_decl("val* recv;") + var c_args = ["val* self"] + var c_ret = "void" + var k = mtype.arguments.length + if mtype.mclass.name.has("Fun") then + c_ret = mtype.arguments.last.ctype + k -= 1 + end + for i in [0..k[ do + var t = mtype.arguments[i] + c_args.push("{t.ctype} p{i}") + end + var c_sig = c_args.join(", ") + v.add_decl("{c_ret} (*method)({c_sig});") + end + if mtype.ctype_extern != "val*" then # Is the Nit type is native then the struct is a box with two fields: # * the `classid` to be polymorph @@ -221,17 +245,33 @@ class GlobalCompiler fun generate_init_instance(mtype: MClassType) do assert self.runtime_type_analysis.live_types.has(mtype) - assert mtype.ctype == "val*" + assert not mtype.is_c_primitive var v = self.new_visitor var is_native_array = mtype.mclass.name == "NativeArray" - + var is_routine_ref = all_routine_types_name.has(mtype.mclass.name) var sig if is_native_array then sig = "int length" else sig = "void" end + if is_routine_ref then + var c_args = ["val* self"] + var c_ret = "void" + var k = mtype.arguments.length + if mtype.mclass.name.has("Fun") then + c_ret = mtype.arguments.last.ctype + k -= 1 + end + for i in [0..k[ do + var t = mtype.arguments[i] + c_args.push("{t.ctype} p{i}") + end + # The underlying method signature + var method_sig = "{c_ret} (*method)({c_args.join(", ")})" + sig = "val* recv, {method_sig}" + end self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig});") v.add_decl("/* allocate {mtype} */") @@ -239,12 +279,15 @@ class GlobalCompiler var res = v.new_var(mtype) res.is_exact = true if is_native_array then - var mtype_elt = mtype.arguments.first - v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));") + v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}) + length*sizeof(val*));") v.add("((struct {mtype.c_name}*){res})->length = length;") else v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}));") end + if is_routine_ref then + v.add("((struct {mtype.c_name}*){res})->recv = recv;") + v.add("((struct {mtype.c_name}*){res})->method = method;") + end v.add("{res}->classid = {self.classid(mtype)};") self.generate_init_attr(v, res, mtype) @@ -296,16 +339,16 @@ class GlobalCompilerVisitor do if value.mtype == mtype then return value - else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then + else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then return value - else if value.mtype.ctype == "val*" then + else if not value.mtype.is_c_primitive then return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) - else if mtype.ctype == "val*" then + else if not mtype.is_c_primitive then var valtype = value.mtype.as(MClassType) var res = self.new_var(mtype) if not compiler.runtime_type_analysis.live_types.has(valtype) then self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */") - self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);") + self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);") return res end self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */") @@ -316,7 +359,7 @@ class GlobalCompilerVisitor # Bad things will appen! var res = self.new_var(mtype) self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */") - self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);") + self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); fatal_exit(1);") return res end end @@ -324,7 +367,7 @@ class GlobalCompilerVisitor redef fun unbox_extern(value, mtype) do if mtype isa MClassType and mtype.mclass.kind == extern_kind and - mtype.mclass.name != "NativeString" then + mtype.mclass.name != "CString" then var res = self.new_var_extern(mtype) self.add "{res} = ((struct {mtype.c_name}*){value})->value; /* unboxing {value.mtype} */" return res @@ -336,13 +379,13 @@ class GlobalCompilerVisitor redef fun box_extern(value, mtype) do if not mtype isa MClassType or mtype.mclass.kind != extern_kind or - mtype.mclass.name == "NativeString" then return value + mtype.mclass.name == "CString" then return value var valtype = value.mtype.as(MClassType) var res = self.new_var(mtype) if not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */") - self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);") + self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);") return res end self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */") @@ -379,32 +422,99 @@ class GlobalCompilerVisitor var recv = "((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->values" if pname == "[]" then self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null))) - return + return true else if pname == "[]=" then self.add("{recv}[{arguments[1]}]={arguments[2]};") - return + return true else if pname == "length" then self.ret(self.new_expr("((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->length", ret_type.as(not null))) - return + return true else if pname == "copy_to" then var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values" self.add("memmove({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));") - return - end + return true + else if pname == "memmove" then + # fun memmove(start: Int, length: Int, dest: NativeArray[E], dest_start: Int) is intern do + var recv1 = "((struct {arguments[3].mcasttype.c_name}*){arguments[3]})->values" + self.add("memmove({recv1}+{arguments[4]}, {recv}+{arguments[1]}, {arguments[2]}*sizeof({elttype.ctype}));") + return true + end + return false end - redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable + redef fun native_array_instance(elttype, length) do - var ret_type = self.get_class("NativeArray").get_mtype([elttype]) + var ret_type = mmodule.native_array_type(elttype) ret_type = anchor(ret_type).as(MClassType) - return self.new_expr("NEW_{ret_type.c_name}({length})", ret_type) + length = autobox(length, compiler.mainmodule.int_type) + return self.new_expr("NEW_{ret_type.c_name}((int){length})", ret_type) end - redef fun calloc_array(ret_type, arguments) + redef fun native_array_get(nat, i) do - self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type)) + var recv = "((struct {nat.mcasttype.c_name}*){nat})->values" + var ret_type = nat.mcasttype.as(MClassType).arguments.first + return self.new_expr("{recv}[{i}]", ret_type) end + redef fun native_array_set(nat, i, val) + do + var recv = "((struct {nat.mcasttype.c_name}*){nat})->values" + self.add("{recv}[{i}]={val};") + end + + redef fun routine_ref_instance(routine_mclass_type, recv, mmethoddef) + do + var method = new CustomizedRuntimeFunction(mmethoddef, recv.mcasttype.as(MClassType)) + var my_recv = recv + if recv.mtype.is_c_primitive then + var object_type = mmodule.object_type + my_recv = autobox(recv, object_type) + end + var thunk = new CustomizedThunkFunction(mmethoddef, my_recv.mtype.as(MClassType)) + thunk.polymorph_call_flag = not my_recv.is_exact #true + #thunk.force_polymorphism = not my_recv.is_exact + compiler.todo(method) + compiler.todo(thunk) + + var res = self.new_expr("NEW_{routine_mclass_type.c_name}({my_recv}, &{thunk.c_name})", routine_mclass_type) + return res + end + + redef fun routine_ref_call(mmethoddef, arguments) + do + var routine = arguments.first + var routine_type = routine.mtype.as(MClassType) + var routine_class = routine_type.mclass + var underlying_recv = "((struct {routine.mcasttype.c_name}*){routine})->recv" + var underlying_method = "((struct {routine.mcasttype.c_name}*){routine})->method" + adapt_signature(mmethoddef, arguments) + arguments.shift + var ss = "{underlying_recv}" + if arguments.length > 0 then + ss = "{ss}, {arguments.join(", ")}" + end + arguments.unshift routine + + var ret_mtype = mmethoddef.msignature.return_mtype + + if ret_mtype != null then + # TODO check for separate compiler + ret_mtype = resolve_for(ret_mtype, routine) + # var temp = ret_mtype + # If mmethoddef has a return type, use the type defined + # in the routine instance instead. + #ret_mtype = routine_type.arguments.last + end + var callsite = "{underlying_method}({ss})" + if ret_mtype != null then + var subres = new_expr("{callsite}", ret_mtype) + ret(subres) + else + add("{callsite};") + end + end + redef fun send(m, args) do var types = self.collect_types(args.first) @@ -419,9 +529,13 @@ class GlobalCompilerVisitor end self.add("/* send {m} on {args.first.inspect} */") - if args.first.mtype.ctype != "val*" then + if args.first.mtype.is_c_primitive then var mclasstype = args.first.mtype.as(MClassType) if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then + self.add("/* skip, dead class {mclasstype} */") + return res + end + if not mclasstype.has_mproperty(self.compiler.mainmodule, m) then self.add("/* skip, no method {m} */") return res end @@ -470,7 +584,7 @@ class GlobalCompilerVisitor var defaultpropdef: nullable MMethodDef = null for t in types do var propdef = m.lookup_first_definition(self.compiler.mainmodule, t) - if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then + if propdef.mclassdef.mclass.name == "Object" and not t.is_c_primitive then defaultpropdef = propdef continue end @@ -498,7 +612,7 @@ class GlobalCompilerVisitor fun check_valid_reciever(recvtype: MClassType) do if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return - print "{recvtype} is not a live type" + print_error "{recvtype} is not a live type" abort end @@ -508,11 +622,6 @@ class GlobalCompilerVisitor private fun get_recvtype(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): MClassType do check_valid_reciever(recvtype) - #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}") - if m.mproperty.is_toplevel then - # Do not customize top-level methods - recvtype = m.mclassdef.bound_mtype - end return recvtype end @@ -545,7 +654,7 @@ class GlobalCompilerVisitor end self.add("/* super {m} on {args.first.inspect} */") - if args.first.mtype.ctype != "val*" then + if args.first.mtype.is_c_primitive then var mclasstype = args.first.mtype.as(MClassType) if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then self.add("/* skip, no method {m} */") @@ -590,8 +699,9 @@ class GlobalCompilerVisitor do var recv = args.first for i in [0..m.msignature.arity[ do - var t = m.msignature.mparameters[i].mtype - if i == m.msignature.vararg_rank then + var mp = m.msignature.mparameters[i] + var t = mp.mtype + if mp.is_vararg then t = args[i+1].mtype end t = self.resolve_for(t, recv) @@ -603,8 +713,9 @@ class GlobalCompilerVisitor do var recv = args.first for i in [0..m.msignature.arity[ do - var t = m.msignature.mparameters[i].mtype - if i == m.msignature.vararg_rank then + var mp = m.msignature.mparameters[i] + var t = mp.mtype + if mp.is_vararg then t = args[i+1].mtype end t = self.resolve_for(t, recv) @@ -621,9 +732,9 @@ class GlobalCompilerVisitor fun bugtype(recv: RuntimeVariable) do - if recv.mtype.ctype != "val*" then return + if recv.mtype.is_c_primitive then return self.add("PRINT_ERROR(\"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");") - self.add("show_backtrace(1);") + self.add("fatal_exit(1);") end redef fun isset_attribute(a, recv) @@ -652,7 +763,7 @@ class GlobalCompilerVisitor ta = self.resolve_for(ta, recv2) var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta) if not ta isa MNullableType then - if ta.ctype == "val*" then + if not ta.is_c_primitive then self.add("{res} = ({attr} != NULL);") else self.add("{res} = 1; /*NOTYET isset on primitive attributes*/") @@ -698,7 +809,7 @@ class GlobalCompilerVisitor ta = self.resolve_for(ta, recv2) var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta) if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then - if ta.ctype == "val*" then + if not ta.is_c_primitive then self.add("if ({res2} == NULL) \{") self.add_abort("Uninitialized attribute {a.name}") self.add("\}") @@ -774,7 +885,7 @@ class GlobalCompilerVisitor var res = self.new_var(bool_type) self.add("/* isa {mtype} on {value.inspect} */") - if value.mtype.ctype != "val*" then + if value.mtype.is_c_primitive then if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then self.add("{res} = 1;") else @@ -809,14 +920,14 @@ class GlobalCompilerVisitor redef fun is_same_type_test(value1, value2) do var res = self.new_var(bool_type) - if value2.mtype.ctype == "val*" then - if value1.mtype.ctype == "val*" then + if not value2.mtype.is_c_primitive then + if not value1.mtype.is_c_primitive then self.add "{res} = {value1}->classid == {value2}->classid;" else self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;" end else - if value1.mtype.ctype == "val*" then + if not value1.mtype.is_c_primitive then self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};" else if value1.mcasttype == value2.mcasttype then self.add "{res} = 1;" @@ -831,7 +942,7 @@ class GlobalCompilerVisitor do var res = self.get_name("var_class_name") self.add_decl("const char* {res};") - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then self.add "{res} = class_names[{value}->classid];" else self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];" @@ -842,15 +953,15 @@ class GlobalCompilerVisitor redef fun equal_test(value1, value2) do var res = self.new_var(bool_type) - if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then + if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then var tmp = value1 value1 = value2 value2 = tmp end - if value1.mtype.ctype != "val*" then + if value1.mtype.is_c_primitive then if value2.mtype == value1.mtype then self.add("{res} = {value1} == {value2};") - else if value2.mtype.ctype != "val*" then + else if value2.mtype.is_c_primitive then self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/") else var mtype1 = value1.mtype.as(MClassType) @@ -887,10 +998,10 @@ class GlobalCompilerVisitor redef fun array_instance(array, elttype) do elttype = self.anchor(elttype) - var arraytype = self.get_class("Array").get_mtype([elttype]) + var arraytype = mmodule.array_type(elttype) var res = self.init_instance(arraytype) self.add("\{ /* {res} = array_instance Array[{elttype}] */") - var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype])) + var nat = self.new_var(mmodule.native_array_type(elttype)) nat.is_exact = true self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});") for i in [0..array.length[ do @@ -904,7 +1015,7 @@ class GlobalCompilerVisitor end end -# A runtime function customized on a specific monomrph receiver type +# A runtime function customized on a specific monomorph receiver type private class CustomizedRuntimeFunction super AbstractRuntimeFunction @@ -949,73 +1060,51 @@ private class CustomizedRuntimeFunction end end - # compile the code customized for the reciever - redef fun compile_to_c(compiler) - do - var recv = self.recv - var mmethoddef = self.mmethoddef - if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then - print("problem: why do we compile {self} for {recv}?") - abort - end + redef fun recv_mtype + do + return recv + end - var v = compiler.new_visitor - var selfvar = new RuntimeVariable("self", recv, recv) - if compiler.runtime_type_analysis.live_types.has(recv) then - selfvar.is_exact = true - end - var arguments = new Array[RuntimeVariable] - var frame = new Frame(v, mmethoddef, recv, arguments) - v.frame = frame + redef var return_mtype - var sig = new FlatBuffer - var comment = new FlatBuffer - var ret = mmethoddef.msignature.return_mtype - if ret != null then - ret = v.resolve_for(ret, selfvar) - sig.append("{ret.ctype} ") - else - sig.append("void ") - end - sig.append(self.c_name) - sig.append("({recv.ctype} {selfvar}") - comment.append("(self: {recv}") - arguments.add(selfvar) - for i in [0..mmethoddef.msignature.arity[ do - var mtype = mmethoddef.msignature.mparameters[i].mtype - if i == mmethoddef.msignature.vararg_rank then - mtype = v.get_class("Array").get_mtype([mtype]) - end - mtype = v.resolve_for(mtype, selfvar) - 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.header.add_decl("{sig};") - - v.add_decl("/* method {self} for {comment} */") - v.add_decl("{sig} \{") - #v.add("printf(\"method {self} for {comment}\\n\");") - if ret != null then - frame.returnvar = v.new_var(ret) - end - frame.returnlabel = v.get_name("RET_LABEL") - - mmethoddef.compile_inside_to_c(v, arguments) - - v.add("{frame.returnlabel.as(not null)}:;") - if ret != null then - v.add("return {frame.returnvar.as(not null)};") + redef fun resolve_receiver(v) + do + var selfvar = new RuntimeVariable("self", recv, recv) + if v.compiler.runtime_type_analysis.live_types.has(recv) then + selfvar.is_exact = true end - v.add("\}") - if not self.c_name.has_substring("VIRTUAL", 0) then compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})" - end + return selfvar + end + + redef fun resolve_return_mtype(v) + do + var selfvar = v.frame.selfvar + if has_return then + var ret = msignature.return_mtype.as(not null) + return_mtype = v.resolve_for(ret, selfvar) + end + end + redef fun resolve_ith_parameter(v, i) + do + var selfvar = v.frame.selfvar + var mp = msignature.mparameters[i] + var mtype = mp.mtype + if mp.is_vararg then + mtype = v.mmodule.array_type(mtype) + end + mtype = v.resolve_for(mtype, selfvar) + return new RuntimeVariable("p{i}", mtype, mtype) + end + + redef fun declare_signature(v, sig) + do + v.compiler.header.add_decl("{sig};") + end + + redef fun end_compile_to_c(v) + do + if not self.c_name.has_substring("VIRTUAL", 0) then v.compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})" + end redef fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do @@ -1023,8 +1112,33 @@ private class CustomizedRuntimeFunction if ret != null then ret = v.resolve_for(ret, arguments.first) end - if self.mmethoddef.can_inline(v) then - var frame = new Frame(v, self.mmethoddef, self.recv, arguments) + + # TODO: remove this guard when gcc warning issue (#2781) is resolved + # WARNING: the next two lines of code is used to prevent inlining. + # Inlining of a callref seems to work all the time. However, + # it will produce some deadcode in certain scenarios (when using nullable type). + # + # ~~~~nitish + # class A[E] + # fun toto(x: E) + # do + # ...do something with x... + # end + # end + # end + # var a = new A[nullable Int] + # var f = &a.toto + # f.call(null) <-- Will produce a proper C callsite, but it will + # -- produce unreachable (dead code) for type checking + # -- and covariance. Thus, creating warnings when + # -- compiling in global. However, if you ignore + # -- those warnings, the binary works perfectly fine. + # ~~~~ + var intromclassdef = self.mmethoddef.mproperty.intro_mclassdef + var is_callref = v.compiler.all_routine_types_name.has(intromclassdef.name) + + if self.mmethoddef.can_inline(v) and not is_callref then + var frame = new StaticFrame(v, self.mmethoddef, self.recv, arguments) frame.returnlabel = v.get_name("RET_LABEL") if ret != null then frame.returnvar = v.new_var(ret) @@ -1050,3 +1164,67 @@ private class CustomizedRuntimeFunction end end end + +class CustomizedThunkFunction + super ThunkFunction + super CustomizedRuntimeFunction + + #var force_polymorphism = false + + redef fun c_name + do + return "THUNK_" + super + end + + redef fun hash + do + return super + c_name.hash + end + + redef fun resolve_receiver(v) + do + var res = super(v) + if res.is_exact then res.is_exact = not polymorph_call_flag + return res + end + + redef fun target_recv + do + # If the targeted method was introduced by a primitive type, + # then target_recv must be set to it. Otherwise, there will + # be a missing cast. Here's an example: + # + # ~~~~nitish + # class Int + # fun mult_by(x:Int):Int do return x * self + # end + # + # var f = &10.mult_by + # ~~~~ + # Here the thunk `f` must box the receiver `10` into an object. + # This is due to the memory representation of a call ref which + # has a pointer to an opaque type `val*`: + # + # ```C + # struct Mult_by_callref_struct { + # classid; + # // The receiver `10` would be here + # val* recv; + # // the targeted receiver is a `long` + # long (*pointer_to_mult_by)(long, long); + # } + # ``` + # + # Thus, every primitive type must be boxed into an `Object` when + # instantiating a callref. + # + # However, if the underlying method was introduced by a primitive + # type then a cast must be invoked to convert our boxed receiver + # to its original primitive type. + var intro_recv = mmethoddef.mproperty.intro_mclassdef.bound_mtype + if intro_recv.is_c_primitive then + return intro_recv + end + return recv_mtype + end +end