X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/separate_erasure_compiler.nit b/src/compiler/separate_erasure_compiler.nit index c370461..813e7fb 100644 --- a/src/compiler/separate_erasure_compiler.nit +++ b/src/compiler/separate_erasure_compiler.nit @@ -46,7 +46,7 @@ redef class ToolContext end end - var erasure_compiler_phase = new ErasureCompilerPhase(self, null) + var erasure_compiler_phase = new ErasureCompilerPhase(self, [contracts_phase]) end class ErasureCompilerPhase @@ -194,74 +194,12 @@ class SeparateErasureCompiler self.header.add_decl("typedef struct instance \{ const struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */") end - redef fun compile_class_to_c(mclass: MClass) + redef fun compile_class_if_universal(ccinfo, v) do - var mtype = mclass.intro.bound_mtype + var mclass = ccinfo.mclass + var mtype = ccinfo.mtype var c_name = mclass.c_name - - var class_table = self.class_tables[mclass] - var v = self.new_visitor - - var rta = runtime_type_analysis - var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind - if not is_dead and rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" then - is_dead = true - end - - v.add_decl("/* runtime class {c_name} */") - - self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};") - v.add_decl("extern const struct type_table type_table_{c_name};") - - # Build class vft - v.add_decl("const struct class class_{c_name} = \{") - v.add_decl("{class_ids[mclass]},") - v.add_decl("\"{mclass.name}\", /* class_name_string */") - v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */") - v.add_decl("{class_colors[mclass]},") - if not is_dead then - if build_class_vts_table(mclass) then - v.require_declaration("vts_table_{c_name}") - v.add_decl("&vts_table_{c_name},") - else - v.add_decl("NULL,") - end - v.add_decl("&type_table_{c_name},") - v.add_decl("\{") - var vft = self.method_tables.get_or_null(mclass) - if vft != null then for i in [0 .. vft.length[ do - var mpropdef = vft[i] - if mpropdef == null then - v.add_decl("NULL, /* empty */") - else - assert mpropdef isa MMethodDef - if rta != null and not rta.live_methoddefs.has(mpropdef) then - v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */") - continue - end - var rf = mpropdef.virtual_runtime_function - v.require_declaration(rf.c_name) - v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mpropdef.full_name} */") - end - end - v.add_decl("\}") - end - v.add_decl("\};") - - # Build class type table - - v.add_decl("const struct type_table type_table_{c_name} = \{") - v.add_decl("{class_table.length},") - v.add_decl("\{") - for msuper in class_table do - if msuper == null then - v.add_decl("-1, /* empty */") - else - v.add_decl("{self.class_ids[msuper]}, /* {msuper} */") - end - end - v.add_decl("\}") - v.add_decl("\};") + var is_dead = ccinfo.is_dead if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then #Build instance struct @@ -281,7 +219,7 @@ class SeparateErasureCompiler v.add("return (val*)res;") v.add("\}") - 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}();") @@ -299,7 +237,7 @@ class SeparateErasureCompiler 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} \{") @@ -321,8 +259,28 @@ class SeparateErasureCompiler v.add("{res}->length = length;") v.add("return (val*){res};") v.add("\}") - return - else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then + return true + else if mclass.name == "RoutineRef" then + self.header.add_decl("struct instance_{c_name} \{") + 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);") + v.add_decl("/* allocate {mtype} */") + v.add_decl("{mtype.ctype} NEW_{c_name}(val* recv, nitmethod_t method, const struct class* class)\{") + 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}->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 var pointer_type = mainmodule.pointer_type self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}();") @@ -341,8 +299,84 @@ class SeparateErasureCompiler v.add("return {res};") end v.add("\}") - return + return true end + return false + end + + redef fun compile_class_vft(ccinfo, v) + do + var mclass = ccinfo.mclass + var mtype = ccinfo.mtype + var c_name = mclass.c_name + var is_dead = ccinfo.is_dead + var rta = runtime_type_analysis + + # Build class vft + self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};") + + v.add_decl("const struct class class_{c_name} = \{") + v.add_decl("{class_ids[mclass]},") + v.add_decl("\"{mclass.name}\", /* class_name_string */") + v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */") + v.add_decl("{class_colors[mclass]},") + if not is_dead then + if build_class_vts_table(mclass) then + v.require_declaration("vts_table_{c_name}") + v.add_decl("&vts_table_{c_name},") + else + v.add_decl("NULL,") + end + v.add_decl("&type_table_{c_name},") + v.add_decl("\{") + var vft = self.method_tables.get_or_null(mclass) + if vft != null then for i in [0 .. vft.length[ do + var mpropdef = vft[i] + if mpropdef == null then + v.add_decl("NULL, /* empty */") + else + assert mpropdef isa MMethodDef + if rta != null and not rta.live_methoddefs.has(mpropdef) then + v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */") + continue + end + var rf = mpropdef.virtual_runtime_function + v.require_declaration(rf.c_name) + v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mpropdef.full_name} */") + end + end + v.add_decl("\}") + end + v.add_decl("\};") + end + + protected fun compile_class_type_table(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor) + do + var mclass = ccinfo.mclass + var c_name = mclass.c_name + var class_table = self.class_tables[mclass] + + # Build class type table + v.add_decl("const struct type_table type_table_{c_name} = \{") + v.add_decl("{class_table.length},") + v.add_decl("\{") + for msuper in class_table do + if msuper == null then + v.add_decl("-1, /* empty */") + else + v.add_decl("{self.class_ids[msuper]}, /* {msuper} */") + end + end + v.add_decl("\}") + v.add_decl("\};") + end + + redef fun compile_default_new(ccinfo, v) + do + var mclass = ccinfo.mclass + var mtype = ccinfo.mtype + var c_name = mclass.c_name + var is_dead = ccinfo.is_dead #Build NEW self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(void);") @@ -371,6 +405,33 @@ class SeparateErasureCompiler v.add("\}") end + redef fun build_class_compilation_info(mclass) + do + var ccinfo = super + var mtype = ccinfo.mtype + var rta = runtime_type_analysis + var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind + if not is_dead and rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" then + is_dead = true + end + ccinfo.is_dead = is_dead + return ccinfo + end + + redef fun compile_class_to_c(mclass: MClass) + do + var ccinfo = build_class_compilation_info(mclass) + var v = new_visitor + v.add_decl("/* runtime class {mclass.c_name} */") + self.provide_declaration("class_{mclass.c_name}", "extern const struct class class_{mclass.c_name};") + v.add_decl("extern const struct type_table type_table_{mclass.c_name};") + self.compile_class_vft(ccinfo, v) + self.compile_class_type_table(ccinfo, v) + if not self.compile_class_if_universal(ccinfo, v) then + self.compile_default_new(ccinfo, v) + end + end + private fun build_class_vts_table(mclass: MClass): Bool do if self.vt_tables[mclass].is_empty then return false @@ -603,7 +664,7 @@ class SeparateErasureCompilerVisitor 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 pointer_type = compiler.mainmodule.pointer_type var res = self.new_var_extern(mtype) self.add "{res} = ((struct instance_{pointer_type.c_name}*){value})->value; /* unboxing {value.mtype} */" @@ -616,7 +677,7 @@ class SeparateErasureCompilerVisitor redef fun box_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 valtype = compiler.mainmodule.pointer_type var res = self.new_var(mtype) if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then @@ -654,7 +715,59 @@ class SeparateErasureCompilerVisitor var res = self.new_var(mtype) res.is_exact = true self.require_declaration("NEW_{nclass.c_name}") + length = autobox(length, compiler.mainmodule.int_type) self.add("{res} = NEW_{nclass.c_name}({length});") return res end + + redef fun routine_ref_instance(routine_type, recv, callsite) + do + var mmethoddef = callsite.mpropdef + #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(mmethoddef.c_name) + + var thunk_function = mmethoddef.callref_thunk(my_recv_mclass_type) + 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 + compiler.thunk_todo(thunk_function) + + # 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})", routine_type) + #debug "LEAVING ref_instance" + return res + + end end