X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/separate_erasure_compiler.nit b/src/compiler/separate_erasure_compiler.nit index af3a43c..813e7fb 100644 --- a/src/compiler/separate_erasure_compiler.nit +++ b/src/compiler/separate_erasure_compiler.nit @@ -20,11 +20,11 @@ intrude import separate_compiler # Add separate erased compiler specific options redef class ToolContext # --erasure - var opt_erasure: OptionBool = new OptionBool("Erase generic types", "--erasure") + var opt_erasure = new OptionBool("Erase generic types", "--erasure") # --rta var opt_rta = new OptionBool("Activate RTA (implicit with --global and --separate)", "--rta") # --no-check-erasure-cast - var opt_no_check_erasure_cast: OptionBool = new OptionBool("Disable implicit casts on unsafe return with erasure-typing policy (dangerous)", "--no-check-erasure-cast") + var opt_no_check_erasure_cast = new OptionBool("Disable implicit casts on unsafe return with erasure-typing policy (dangerous)", "--no-check-erasure-cast") redef init do @@ -39,9 +39,14 @@ redef class ToolContext if opt_no_check_all.value then opt_no_check_erasure_cast.value = true end + + # Temporary disabled. TODO: implement tagging in the erasure compiler. + if opt_erasure.value then + opt_no_tag_primitives.value = true + end end - var erasure_compiler_phase = new ErasureCompilerPhase(self, null) + var erasure_compiler_phase = new ErasureCompilerPhase(self, [contracts_phase]) end class ErasureCompilerPhase @@ -65,33 +70,8 @@ redef class ModelBuilder self.toolcontext.info("*** GENERATING C ***", 1) var compiler = new SeparateErasureCompiler(mainmodule, self, runtime_type_analysis) - compiler.compile_header - - # compile class structures - self.toolcontext.info("Property coloring", 2) - compiler.new_file("{mainmodule.name}.tables") - compiler.do_property_coloring - for m in mainmodule.in_importation.greaters do - for mclass in m.intro_mclasses do - compiler.compile_class_to_c(mclass) - end - end - compiler.compile_color_consts(compiler.vt_colors) - - # The main function of the C - compiler.new_file("{mainmodule.name}.main") - compiler.compile_nitni_global_ref_functions - compiler.compile_main_function - - # compile methods - for m in mainmodule.in_importation.greaters do - self.toolcontext.info("Generate C for module {m}", 2) - compiler.new_file("{m.name}.sep") - compiler.compile_module_to_c(m) - end - + compiler.do_compilation compiler.display_stats - var time1 = get_time self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2) write_and_make(compiler) @@ -101,12 +81,11 @@ end class SeparateErasureCompiler super SeparateCompiler - private var class_ids: Map[MClass, Int] - private var class_colors: Map[MClass, Int] - protected var vt_colors: Map[MVirtualTypeProp, Int] + private var class_ids: Map[MClass, Int] is noinit + private var class_colors: Map[MClass, Int] is noinit + protected var vt_colors: Map[MVirtualTypeProp, Int] is noinit - init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do - super + init do # Class coloring var poset = mainmodule.flatten_mclass_hierarchy @@ -215,81 +194,14 @@ 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 is_dead = ccinfo.is_dead - var vft = self.method_tables[mclass] - var attrs = self.attr_tables[mclass] - var class_table = self.class_tables[mclass] - var v = self.new_visitor - - var rta = runtime_type_analysis - var is_dead = mclass.kind == abstract_kind or mclass.kind == interface_kind - if not is_dead and rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" 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("\{") - 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 - if true or mpropdef.mclassdef.bound_mtype.ctype != "val*" then - v.require_declaration("VIRTUAL_{mpropdef.c_name}") - v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */") - else - v.require_declaration("{mpropdef.c_name}") - v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */") - end - 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("\};") - - if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then + if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then #Build instance struct self.header.add_decl("struct instance_{c_name} \{") self.header.add_decl("const struct class *class;") @@ -297,9 +209,9 @@ class SeparateErasureCompiler self.header.add_decl("\};") #Build BOX - self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});") + self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});") v.add_decl("/* allocate {mtype} */") - v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{") + v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype_extern} value) \{") v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));") v.require_declaration("class_{c_name}") v.add("res->class = &class_{c_name};") @@ -307,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}();") @@ -325,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} \{") @@ -347,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}();") @@ -367,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);") @@ -380,16 +388,50 @@ class SeparateErasureCompiler var res = v.new_named_var(mtype, "self") res.is_exact = true - v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));") + var attrs = self.attr_tables.get_or_null(mclass) + if attrs == null then + v.add("{res} = nit_alloc(sizeof(struct instance));") + else + v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));") + end v.require_declaration("class_{c_name}") v.add("{res}->class = &class_{c_name};") - self.generate_init_attr(v, res, mtype) - v.set_finalizer res + if attrs != null then + self.generate_init_attr(v, res, mtype) + v.set_finalizer res + end v.add("return {res};") end 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 @@ -434,12 +476,17 @@ class SeparateErasureCompiler end end + redef fun compile_types + do + compile_color_consts(vt_colors) + end + redef fun new_visitor do return new SeparateErasureCompilerVisitor(self) # Stats - private var class_tables: Map[MClass, Array[nullable MClass]] - private var vt_tables: Map[MClass, Array[nullable MPropDef]] + private var class_tables: Map[MClass, Array[nullable MClass]] is noinit + private var vt_tables: Map[MClass, Array[nullable MPropDef]] is noinit redef fun display_sizes do @@ -549,8 +596,7 @@ class SeparateErasureCompilerVisitor end var class_ptr - var type_table - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then class_ptr = "{value}->class->" else var mclass = value.mtype.as(MClassType).mclass @@ -569,7 +615,7 @@ class SeparateErasureCompilerVisitor else if mtype isa MVirtualType then var recv = self.frame.arguments.first var recv_ptr - if recv.mtype.ctype == "val*" then + if not recv.mtype.is_c_primitive then recv_ptr = "{recv}->class->" else var mclass = recv.mtype.as(MClassType).mclass @@ -618,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} */" @@ -631,12 +677,12 @@ 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 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.require_declaration("BOX_{valtype.c_name}") @@ -653,7 +699,7 @@ class SeparateErasureCompilerVisitor 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} = {value} == NULL ? \"null\" : {value}->class->name;" else self.require_declaration("class_{value.mtype.c_name}") @@ -664,19 +710,64 @@ class SeparateErasureCompilerVisitor redef fun native_array_instance(elttype, length) do - var nclass = self.get_class("NativeArray") + var nclass = mmodule.native_array_class var mtype = nclass.get_mtype([elttype]) 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 calloc_array(ret_type, arguments) - do - var ret = ret_type.as(MClassType) - self.require_declaration("NEW_{ret.mclass.c_name}") - self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]})", ret_type)) - 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