X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index f06e61f..38bc466 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -97,7 +97,7 @@ redef class ToolContext end end - var separate_compiler_phase = new SeparateCompilerPhase(self, null) + var separate_compiler_phase = new SeparateCompilerPhase(self, [contracts_phase]) end class SeparateCompilerPhase @@ -149,7 +149,7 @@ class SeparateCompiler private var type_ids: Map[MType, Int] is noinit private var type_colors: Map[MType, Int] is noinit private var opentype_colors: Map[MType, Int] is noinit - private var thunks_to_compile: Set[SeparateRuntimeFunction] = new HashSet[SeparateRuntimeFunction] + private var thunks_to_compile: Set[SeparateRuntimeFunction] = new HashSet[SeparateRuntimeFunction] init do var file = new_file("nit.common") @@ -196,14 +196,14 @@ class SeparateCompiler compiler.compile_types end - fun thunk_todo(thunk: SeparateRuntimeFunction) - do - # Concrete instance of `SeparateRuntimeFunction` are already - # handled by the compiler. Avoid duplicate compilation. - if thunk isa SeparateThunkFunction then - thunks_to_compile.add(thunk) - end - end + fun thunk_todo(thunk: SeparateRuntimeFunction) + do + # Concrete instance of `SeparateRuntimeFunction` are already + # handled by the compiler. Avoid duplicate compilation. + if thunk isa SeparateThunkFunction then + thunks_to_compile.add(thunk) + end + end # Color and compile type structures and cast information fun compile_types @@ -263,7 +263,7 @@ class SeparateCompiler # Collect all bas box class # FIXME: this is not completely fine with a separate compilation scheme for classname in ["Int", "Bool", "Byte", "Char", "Float", "CString", - "Pointer", "Int8", "Int16", "UInt16", "Int32", "UInt32"] do + "Pointer", "Int8", "Int16", "UInt16", "Int32", "UInt32"] do var classes = self.mainmodule.model.get_mclasses_by_name(classname) if classes == null then continue assert classes.length == 1 else print_error classes.join(", ") @@ -283,7 +283,7 @@ class SeparateCompiler return self.box_kinds[self.mainmodule.pointer_type.mclass] else return self.box_kinds[mclass] - end + end end fun compile_color_consts(colors: Map[Object, Int]) do @@ -648,15 +648,15 @@ class SeparateCompiler end end end - var compiled_thunks = new Array[SeparateRuntimeFunction] - # Compile thunks here to write them in the same module they are declared. - for thunk in thunks_to_compile do - if thunk.mmethoddef.mclassdef.mmodule == mmodule then - thunk.compile_to_c(self) - compiled_thunks.add(thunk) - end - end - thunks_to_compile.remove_all(compiled_thunks) + var compiled_thunks = new Array[SeparateRuntimeFunction] + # Compile thunks here to write them in the same module they are declared. + for thunk in thunks_to_compile do + if thunk.mmethoddef.mclassdef.mmodule == mmodule then + thunk.compile_to_c(self) + compiled_thunks.add(thunk) + end + end + thunks_to_compile.remove_all(compiled_thunks) self.mainmodule = old_module end @@ -825,23 +825,14 @@ class SeparateCompiler v.add_decl("\};") end - # Globally compile the table of the class mclass - # In a link-time optimisation compiler, tables are globally computed - # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally - fun compile_class_to_c(mclass: MClass) + protected fun compile_class_vft(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor) do - if mclass.is_broken then return - - var mtype = mclass.intro.bound_mtype - var c_name = mclass.c_name - - var v = new_visitor - + var mclass = ccinfo.mclass + var mtype = ccinfo.mtype var rta = runtime_type_analysis - var is_dead = rta != null and not rta.live_classes.has(mclass) - # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so - # in order to compile and link correctly the C code, these symbols should be declared and defined. - var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind + var c_name = ccinfo.mclass.c_name + var is_dead = ccinfo.is_dead + var need_corpse = ccinfo.need_corpse v.add_decl("/* runtime class {c_name}: {mclass.full_name} (dead={is_dead}; need_corpse={need_corpse})*/") @@ -873,11 +864,24 @@ class SeparateCompiler v.add_decl("\}") v.add_decl("\};") end + end + + # Given a `MClass`, if it's a universal class and if it needs to be handle + # specifically by the compiler, this function will compile it and return + # true. Otherwise, no C code will be written in the visitor and the value + # false will be returned. + fun compile_class_if_universal(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor): Bool + do + var mclass = ccinfo.mclass + var mtype = ccinfo.mtype + var c_name = ccinfo.mclass.c_name + var is_dead = ccinfo.is_dead + var need_corpse = ccinfo.need_corpse if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then # Is a primitive type or the Pointer class, not any other extern class - if mtype.is_tagged then return + if mtype.is_tagged then return true #Build instance struct self.header.add_decl("struct instance_{c_name} \{") @@ -887,7 +891,7 @@ class SeparateCompiler self.header.add_decl("\};") # Pointer is needed by extern types, live or not - if is_dead and mtype.mclass.name != "Pointer" then return + if is_dead and mtype.mclass.name != "Pointer" then return true #Build BOX self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});") @@ -905,7 +909,7 @@ class SeparateCompiler v.add("\}") # A Pointer class also need its constructor - if mtype.mclass.name != "Pointer" then return + if mtype.mclass.name != "Pointer" then return true v = new_visitor self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);") @@ -926,7 +930,7 @@ class SeparateCompiler v.add("return {res};") end v.add("\}") - return + return true else if mclass.name == "NativeArray" then #Build instance struct self.header.add_decl("struct instance_{c_name} \{") @@ -953,30 +957,30 @@ class SeparateCompiler v.add("{res}->length = length;") v.add("return (val*){res};") v.add("\}") - return - else if mclass.name == "RoutineRef" then - self.header.add_decl("struct instance_{c_name} \{") - self.header.add_decl("const struct type *type;") - self.header.add_decl("const struct class *class;") - self.header.add_decl("val* recv;") - self.header.add_decl("nitmethod_t method;") - self.header.add_decl("\};") - - self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type);") - v.add_decl("/* allocate {mtype} */") - v.add_decl("{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type)\{") - var res = v.get_name("self") - v.add_decl("struct instance_{c_name} *{res};") - var alloc = v.nit_alloc("sizeof(struct instance_{c_name})", mclass.full_name) - v.add("{res} = {alloc};") - v.add("{res}->type = type;") - hardening_live_type(v, "type") - v.add("{res}->class = class;") - v.add("{res}->recv = recv;") - v.add("{res}->method = method;") - v.add("return (val*){res};") - v.add("\}") - return + return true + else if mclass.name == "RoutineRef" then + self.header.add_decl("struct instance_{c_name} \{") + self.header.add_decl("const struct type *type;") + self.header.add_decl("const struct class *class;") + self.header.add_decl("val* recv;") + self.header.add_decl("nitmethod_t method;") + self.header.add_decl("\};") + + self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type);") + v.add_decl("/* allocate {mtype} */") + v.add_decl("{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class, const struct type* type)\{") + var res = v.get_name("self") + v.add_decl("struct instance_{c_name} *{res};") + var alloc = v.nit_alloc("sizeof(struct instance_{c_name})", mclass.full_name) + v.add("{res} = {alloc};") + v.add("{res}->type = type;") + hardening_live_type(v, "type") + v.add("{res}->class = class;") + v.add("{res}->recv = recv;") + v.add("{res}->method = method;") + v.add("return (val*){res};") + v.add("\}") + return true else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "CString" then # Is an extern class (other than Pointer and CString) # Pointer is caught in a previous `if`, and CString is internal @@ -1001,8 +1005,17 @@ class SeparateCompiler v.add("return {res};") end v.add("\}") - return + return true end + return false + end + + protected fun compile_default_new(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor) + do + var mclass = ccinfo.mclass + var mtype = ccinfo.mtype + var c_name = ccinfo.mclass.c_name + var is_dead = ccinfo.is_dead #Build NEW self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);") @@ -1036,6 +1049,35 @@ class SeparateCompiler v.add("return {res};") end v.add("\}") + + end + + protected fun build_class_compilation_info(mclass: MClass): ClassCompilationInfo + do + var mtype = mclass.intro.bound_mtype + var rta = runtime_type_analysis + var is_dead = rta != null and not rta.live_classes.has(mclass) + + # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so + # in order to compile and link correctly the C code, these symbols should be declared and defined. + var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind + + var compilation_info = new ClassCompilationInfo(mclass, is_dead, need_corpse) + return compilation_info + end + + # Globally compile the table of the class mclass + # In a link-time optimisation compiler, tables are globally computed + # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally + fun compile_class_to_c(mclass: MClass) + do + var v = new_visitor + var class_info = build_class_compilation_info(mclass) + compile_class_vft(class_info, v) + var is_already_managed = compile_class_if_universal(class_info, v) + if not is_already_managed then + compile_default_new(class_info, v) + end end # Compile structures used to map tagged primitive values to their classes and types. @@ -2188,119 +2230,126 @@ class SeparateCompilerVisitor self.add("{recv}[{i}]={val};") end - redef fun routine_ref_instance(routine_type, recv, mmethoddef) - do - #debug "ENTER ref_instance" - var mmethod = mmethoddef.mproperty - # routine_mclass is the specialized one, e.g: FunRef1, ProcRef2, etc.. - var routine_mclass = routine_type.mclass - - var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null) - var base_routine_mclass = nclasses.first - - # All routine classes use the same `NEW` constructor. - # However, they have different declared `class` and `type` value. - self.require_declaration("NEW_{base_routine_mclass.c_name}") - - var recv_class_cname = recv.mcasttype.as(MClassType).mclass.c_name - var my_recv = recv - - if recv.mtype.is_c_primitive then - my_recv = autobox(recv, mmodule.object_type) - end - var my_recv_mclass_type = my_recv.mtype.as(MClassType) - - # The class of the concrete Routine must exist (e.g ProcRef0, FunRef0, etc.) - self.require_declaration("class_{routine_mclass.c_name}") - self.require_declaration("type_{routine_type.c_name}") - - compiler.undead_types.add(routine_type) - self.require_declaration(mmethoddef.c_name) - - var thunk_function = mmethoddef.callref_thunk(my_recv_mclass_type) - # If the receiver is exact, then there's no need to make a - # polymorph call to the underlying method. - thunk_function.polymorph_call_flag = not my_recv.is_exact - var runtime_function = mmethoddef.virtual_runtime_function - - var is_c_equiv = runtime_function.msignature.c_equiv(thunk_function.msignature) - - var c_ref = thunk_function.c_ref - if is_c_equiv then - var const_color = mmethoddef.mproperty.const_color - c_ref = "{class_info(my_recv)}->vft[{const_color}]" - self.require_declaration(const_color) - else - self.require_declaration(thunk_function.c_name) - compiler.thunk_todo(thunk_function) - end - - # Each RoutineRef points to a receiver AND a callref_thunk - var res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, &type_{routine_type.c_name})", routine_type) - #debug "LEAVING ref_instance" - return res - end - - redef fun routine_ref_call(mmethoddef, arguments) - do - #debug "ENTER ref_call" - compiler.modelbuilder.nb_invok_by_tables += 1 - if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;") - var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null) - var nclass = nclasses.first - var runtime_function = mmethoddef.virtual_runtime_function - - # Save the current receiver since adapt_signature will autobox - # the routine receiver which is not the underlying receiver. - # The underlying receiver has already been adapted in the - # `routine_ref_instance` method. Here we just want to adapt the - # rest of the signature, but it's easier to pass the wrong - # receiver in adapt_signature then discards it with `shift`. - # - # ~~~~nitish - # class A; def toto do print "toto"; end - # var a = new A - # var f = &a.toto <- `a` is the underlying receiver - # f.call <- here `f` is the routine receiver - # ~~~~ - var routine = arguments.first - - # Retrieve the concrete routine type - var original_recv_c = "(((struct instance_{nclass.c_name}*){arguments[0]})->recv)" - var nitmethod = "(({runtime_function.c_funptrtype})(((struct instance_{nclass.c_name}*){arguments[0]})->method))" - if arguments.length > 1 then - adapt_signature(mmethoddef, arguments) - end - - var ret_mtype = runtime_function.called_signature.return_mtype - - if ret_mtype != null then - # `ret` is actually always nullable Object. When invoking - # a callref, we don't have the original callsite information. - # Thus, we need to recompute the return type of the callsite. - ret_mtype = resolve_for(ret_mtype, routine) - end - - # remove the routine's receiver - arguments.shift - var ss = arguments.join(", ") - # replace the receiver with the original one - if arguments.length > 0 then - ss = "{original_recv_c}, {ss}" - else - ss = original_recv_c - end - - arguments.unshift routine # put back the routine ref receiver - add "/* {mmethoddef.mproperty} on {arguments.first.inspect}*/" - var callsite = "{nitmethod}({ss})" - if ret_mtype != null then - var subres = new_expr("{callsite}", ret_mtype) - ret(subres) - else - add("{callsite};") - end - end + redef fun routine_ref_instance(routine_type, recv, callsite) + do + #debug "ENTER ref_instance" + var mmethoddef = callsite.mpropdef + var mmethod = mmethoddef.mproperty + # routine_mclass is the specialized one, e.g: FunRef1, ProcRef2, etc.. + var routine_mclass = routine_type.mclass + + var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null) + var base_routine_mclass = nclasses.first + + # All routine classes use the same `NEW` constructor. + # However, they have different declared `class` and `type` value. + self.require_declaration("NEW_{base_routine_mclass.c_name}") + + var recv_class_cname = recv.mcasttype.as(MClassType).mclass.c_name + var my_recv = recv + + if recv.mtype.is_c_primitive then + my_recv = autobox(recv, mmodule.object_type) + end + var my_recv_mclass_type = my_recv.mtype.as(MClassType) + + # The class of the concrete Routine must exist (e.g ProcRef0, FunRef0, etc.) + self.require_declaration("class_{routine_mclass.c_name}") + self.require_declaration(mmethoddef.c_name) + + var thunk_function = mmethoddef.callref_thunk(my_recv_mclass_type) + # If the receiver is exact, then there's no need to make a + # polymorph call to the underlying method. + thunk_function.polymorph_call_flag = not my_recv.is_exact + var runtime_function = mmethoddef.virtual_runtime_function + + var is_c_equiv = runtime_function.msignature.c_equiv(thunk_function.msignature) + + var c_ref = thunk_function.c_ref + if is_c_equiv then + var const_color = mmethoddef.mproperty.const_color + c_ref = "{class_info(my_recv)}->vft[{const_color}]" + self.require_declaration(const_color) + else + self.require_declaration(thunk_function.c_name) + compiler.thunk_todo(thunk_function) + end + var res: RuntimeVariable + if routine_type.need_anchor then + hardening_live_open_type(routine_type) + link_unresolved_type(self.frame.mpropdef.mclassdef, routine_type) + var recv2 = self.frame.arguments.first + var recv2_type_info = self.type_info(recv2) + self.require_declaration(routine_type.const_color) + res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, {recv2_type_info}->resolution_table->types[{routine_type.const_color}])", routine_type) + else + self.require_declaration("type_{routine_type.c_name}") + compiler.undead_types.add(routine_type) + res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, &type_{routine_type.c_name})", routine_type) + end + return res + end + + redef fun routine_ref_call(mmethoddef, arguments) + do + #debug "ENTER ref_call" + compiler.modelbuilder.nb_invok_by_tables += 1 + if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;") + var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null) + var nclass = nclasses.first + var runtime_function = mmethoddef.virtual_runtime_function + + # Save the current receiver since adapt_signature will autobox + # the routine receiver which is not the underlying receiver. + # The underlying receiver has already been adapted in the + # `routine_ref_instance` method. Here we just want to adapt the + # rest of the signature, but it's easier to pass the wrong + # receiver in adapt_signature then discards it with `shift`. + # + # ~~~~nitish + # class A; def toto do print "toto"; end + # var a = new A + # var f = &a.toto # `a` is the underlying receiver + # f.call # here `f` is the routine receiver + # ~~~~ + var routine = arguments.first + + # Retrieve the concrete routine type + var original_recv_c = "(((struct instance_{nclass.c_name}*){arguments[0]})->recv)" + var nitmethod = "(({runtime_function.c_funptrtype})(((struct instance_{nclass.c_name}*){arguments[0]})->method))" + if arguments.length > 1 then + adapt_signature(mmethoddef, arguments) + end + + var ret_mtype = runtime_function.called_signature.return_mtype + + if ret_mtype != null then + # `ret` is actually always nullable Object. When invoking + # a callref, we don't have the original callsite information. + # Thus, we need to recompute the return type of the callsite. + ret_mtype = resolve_for(ret_mtype, routine) + end + + # remove the routine's receiver + arguments.shift + var ss = arguments.join(", ") + # replace the receiver with the original one + if arguments.length > 0 then + ss = "{original_recv_c}, {ss}" + else + ss = original_recv_c + end + + arguments.unshift routine # put back the routine ref receiver + add "/* {mmethoddef.mproperty} on {arguments.first.inspect}*/" + var callsite = "{nitmethod}({ss})" + if ret_mtype != null then + var subres = new_expr("{callsite}", ret_mtype) + ret(subres) + else + add("{callsite};") + end + end fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do assert mtype.need_anchor @@ -2326,44 +2375,42 @@ redef class MMethodDef return res end - # Returns true if the current method definition differ from - # its original introduction in terms of receiver type. - fun recv_differ_from_intro: Bool - do - var intromclassdef = mproperty.intro.mclassdef - var introrecv = intromclassdef.bound_mtype - return self.mclassdef.bound_mtype != introrecv - end - - # The C thunk function associated to a mmethoddef. Receives only nullable - # Object and cast them to the original mmethoddef signature. - fun callref_thunk(recv_mtype: MClassType): SeparateThunkFunction - do - var res = callref_thunk_cache - if res == null then - #var runtime_function = virtual_runtime_function - var object_type = mclassdef.mmodule.object_type - var nullable_object = object_type.as_nullable - var msignature2 = msignature.change_all_mtype_for(nullable_object) - var intromclassdef = mproperty.intro.mclassdef - - #var introrecv = intromclassdef.bound_mtype - ## If the thunk signature is equivalent to its - ## virtual counterpart, then nothing to do. - #print "recv vs intro : {recv_mtype} vs {introrecv}" - #if msignature2.c_equiv(runtime_function.called_signature) and recv_mtype == introrecv then - # callref_thunk_cache = res - # return runtime_function - #end - # receiver cannot be null - res = new SeparateThunkFunction(self, recv_mtype, msignature2, "THUNK_{c_name}", mclassdef.bound_mtype) - res.polymorph_call_flag = true - callref_thunk_cache = res - end - return res - end - - private var callref_thunk_cache: nullable SeparateThunkFunction + # Returns true if the current method definition differ from + # its original introduction in terms of receiver type. + fun recv_differ_from_intro: Bool + do + var intromclassdef = mproperty.intro.mclassdef + var introrecv = intromclassdef.bound_mtype + return self.mclassdef.bound_mtype != introrecv + end + + # The C thunk function associated to a mmethoddef. Receives only nullable + # Object and cast them to the original mmethoddef signature. + fun callref_thunk(recv_mtype: MClassType): SeparateThunkFunction + do + var res = callref_thunk_cache + if res == null then + var object_type = mclassdef.mmodule.object_type + var nullable_object = object_type.as_nullable + var ps = new Array[MParameter] + + # Replace every argument type by nullable object + for p in msignature.mparameters do + ps.push(new MParameter(p.name, nullable_object, p.is_vararg)) + end + var ret: nullable MType = null + if msignature.return_mtype != null then ret = nullable_object + var msignature2 = new MSignature(ps, ret) + var intromclassdef = mproperty.intro.mclassdef + + res = new SeparateThunkFunction(self, recv_mtype, msignature2, "THUNK_{c_name}", mclassdef.bound_mtype) + res.polymorph_call_flag = true + callref_thunk_cache = res + end + return res + end + + private var callref_thunk_cache: nullable SeparateThunkFunction private var separate_runtime_function_cache: nullable SeparateRuntimeFunction # The C function associated to a mmethoddef, that can be stored into a VFT of a class @@ -2389,7 +2436,7 @@ redef class MMethodDef self.virtual_runtime_function_cache = res return res end - res = new SeparateThunkFunction(self, recv, msignature, "VIRTUAL_{c_name}", mclassdef.bound_mtype) + res = new SeparateThunkFunction(self, recv, msignature, "VIRTUAL_{c_name}", mclassdef.bound_mtype) end return res end @@ -2428,20 +2475,20 @@ class SeparateRuntimeFunction redef fun to_s do return self.mmethoddef.to_s - redef fun msignature - do - return called_signature - end + redef fun msignature + do + return called_signature + end - redef fun recv_mtype - do - return called_recv - end + redef fun recv_mtype + do + return called_recv + end - redef fun return_mtype - do - return called_signature.return_mtype - end + redef fun return_mtype + do + return called_signature.return_mtype + end # The C return type (something or `void`) var c_ret: String is lazy do @@ -2472,32 +2519,32 @@ class SeparateRuntimeFunction # The C type for the function pointer. var c_funptrtype: String is lazy do return "{c_ret}(*){c_sig}" - redef fun declare_signature(v, sig) - do - v.compiler.provide_declaration(c_name, "{sig};") - end + redef fun declare_signature(v, sig) + do + v.compiler.provide_declaration(c_name, "{sig};") + end - redef fun body_to_c(v) - do - var rta = v.compiler.as(SeparateCompiler).runtime_type_analysis - if rta != null and not rta.live_mmodules.has(mmethoddef.mclassdef.mmodule) then + redef fun body_to_c(v) + do + var rta = v.compiler.as(SeparateCompiler).runtime_type_analysis + if rta != null and not rta.live_mmodules.has(mmethoddef.mclassdef.mmodule) then v.add_abort("FATAL: Dead method executed.") - else - super - end - end - - redef fun end_compile_to_c(v) - do - var compiler = v.compiler - compiler.names[self.c_name] = "{mmethoddef.full_name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})" - end - - redef fun build_frame(v, arguments) - do - var recv = mmethoddef.mclassdef.bound_mtype - return new StaticFrame(v, mmethoddef, recv, arguments) - end + else + super + end + end + + redef fun end_compile_to_c(v) + do + var compiler = v.compiler + compiler.names[self.c_name] = "{mmethoddef.full_name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})" + end + + redef fun build_frame(v, arguments) + do + var recv = mmethoddef.mclassdef.bound_mtype + return new StaticFrame(v, mmethoddef, recv, arguments) + end # Compile the trampolines used to implement late-binding. # @@ -2546,10 +2593,38 @@ class SeparateRuntimeFunction end end +# Encapsulates every information needed to compile a class. +# +# The compilation of a class is done by several methods, two of those are +# mandatory : +# - compile_class_to_c : starts the compilation process +# - compile_class_vft : generate the virtual function table +# And one of them is optional : +# - compile_class_if_universal : compiles the rest of the class if its a universal +# type. Universal type are handle in a case-basis, this is why they need special treatment. +# Generally, universal class will have special structure and a custom allocator. +# +# Throughout each step of the class compilation process, some information must be share. +# This class encapsulates the compilation process state. +# (except vft), eg +class ClassCompilationInfo + var mclass: MClass # class to compile + var is_dead: Bool + var need_corpse: Bool + + # Shortcut to access the class's bound type. + var mtype: MClassType is noinit + + init + do + mtype = mclass.intro.bound_mtype + end +end + class SeparateThunkFunction - super ThunkFunction - super SeparateRuntimeFunction - redef var target_recv + super ThunkFunction + super SeparateRuntimeFunction + redef var target_recv end redef class MType