X-Git-Url: http://nitlanguage.org diff --git a/src/separate_compiler.nit b/src/separate_compiler.nit index d671df3..4122fdd 100644 --- a/src/separate_compiler.nit +++ b/src/separate_compiler.nit @@ -95,6 +95,11 @@ redef class ModelBuilder for t in mtypes do compiler.compile_type_to_c(t) end + # compile remaining types structures (useless but needed for the symbol resolution at link-time) + for t in compiler.undead_types do + if mtypes.has(t) then continue + compiler.compile_type_to_c(t) + end compiler.display_stats @@ -114,7 +119,6 @@ class SeparateCompiler var runtime_type_analysis: nullable RapidTypeAnalysis private var undead_types: Set[MType] = new HashSet[MType] - private var partial_types: Set[MType] = new HashSet[MType] private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]] private var type_layout: nullable Layout[MType] @@ -443,16 +447,10 @@ class SeparateCompiler var mtypes = new HashSet[MType] mtypes.add_all(self.runtime_type_analysis.live_types) mtypes.add_all(self.runtime_type_analysis.live_cast_types) - mtypes.add_all(self.undead_types) for c in self.box_kinds.keys do mtypes.add(c.mclass_type) end - for mtype in mtypes do - retrieve_partial_types(mtype) - end - mtypes.add_all(self.partial_types) - # Typing Layout var layout_builder: TypingLayoutBuilder[MType] if modelbuilder.toolcontext.opt_bm_typing.value then @@ -581,34 +579,6 @@ class SeparateCompiler return tables end - fun retrieve_partial_types(mtype: MType) do - # add formal types arguments to mtypes - if mtype isa MGenericType then - for ft in mtype.arguments do - if ft.need_anchor then - print("Why do we need anchor here ?") - abort - end - self.partial_types.add(ft) - retrieve_partial_types(ft) - end - end - var mclass_type: MClassType - if mtype isa MNullableType then - mclass_type = mtype.mtype.as(MClassType) - else - mclass_type = mtype.as(MClassType) - end - - # add virtual types to mtypes - for vt in self.mainmodule.properties(mclass_type.mclass) do - if vt isa MVirtualTypeProp then - var anchored = vt.mvirtualtype.lookup_bound(self.mainmodule, mclass_type).anchor_to(self.mainmodule, mclass_type) - self.partial_types.add(anchored) - end - end - end - # Separately compile all the method definitions of the module fun compile_module_to_c(mmodule: MModule) do @@ -630,6 +600,10 @@ class SeparateCompiler # Globaly compile the type structure of a live type fun compile_type_to_c(mtype: MType) do + assert not mtype.need_anchor + var layout = self.type_layout + var is_live = mtype isa MClassType and runtime_type_analysis.live_types.has(mtype) + var is_cast_live = runtime_type_analysis.live_cast_types.has(mtype) var c_name = mtype.c_name var v = new SeparateCompilerVisitor(self) v.add_decl("/* runtime type {mtype} */") @@ -639,39 +613,70 @@ class SeparateCompiler # const struct type_X v.add_decl("const struct type type_{c_name} = \{") - v.add_decl("{self.type_layout.ids[mtype]},") + + # type id (for cast target) + if is_cast_live then + v.add_decl("{layout.ids[mtype]},") + else + v.add_decl("-1, /*CAST DEAD*/") + end + + # type name v.add_decl("\"{mtype}\", /* class_name_string */") - var layout = self.type_layout - if layout isa PHLayout[MType, MType] then - v.add_decl("{layout.masks[mtype]},") + + # type color (for cast target) + if is_cast_live then + if layout isa PHLayout[MType, MType] then + v.add_decl("{layout.masks[mtype]},") + else + v.add_decl("{layout.pos[mtype]},") + end else - v.add_decl("{layout.pos[mtype]},") + v.add_decl("-1, /*CAST DEAD*/") end + + # is_nullable bit if mtype isa MNullableType then v.add_decl("1,") else v.add_decl("0,") end - if compile_type_resolution_table(mtype) then - v.require_declaration("resolution_table_{c_name}") - v.add_decl("&resolution_table_{c_name},") + + # resolution table (for receiver) + if is_live then + var mclass_type = mtype + if mclass_type isa MNullableType then mclass_type = mclass_type.mtype + assert mclass_type isa MClassType + if resolution_tables[mclass_type].is_empty then + v.add_decl("NULL, /*NO RESOLUTIONS*/") + else + compile_type_resolution_table(mtype) + v.require_declaration("resolution_table_{c_name}") + v.add_decl("&resolution_table_{c_name},") + end else - v.add_decl("NULL,") + v.add_decl("NULL, /*DEAD*/") end - v.add_decl("{self.type_tables[mtype].length},") - v.add_decl("\{") - for stype in self.type_tables[mtype] do - if stype == null then - v.add_decl("-1, /* empty */") - else - v.add_decl("{self.type_layout.ids[stype]}, /* {stype} */") + + # cast table (for receiver) + if is_live then + v.add_decl("{self.type_tables[mtype].length},") + v.add_decl("\{") + for stype in self.type_tables[mtype] do + if stype == null then + v.add_decl("-1, /* empty */") + else + v.add_decl("{layout.ids[stype]}, /* {stype} */") + end end + v.add_decl("\},") + else + v.add_decl("0, \{\}, /*DEAD TYPE*/") end - v.add_decl("\},") v.add_decl("\};") end - fun compile_type_resolution_table(mtype: MType): Bool do + fun compile_type_resolution_table(mtype: MType) do var mclass_type: MClassType if mtype isa MNullableType then @@ -679,7 +684,6 @@ class SeparateCompiler else mclass_type = mtype.as(MClassType) end - if not self.resolution_tables.has_key(mclass_type) then return false var layout = self.resolution_layout @@ -714,7 +718,6 @@ class SeparateCompiler end v.add_decl("\}") v.add_decl("\};") - return true end # Globally compile the table of the class mclass @@ -724,6 +727,7 @@ class SeparateCompiler do var mtype = mclass.intro.bound_mtype var c_name = mclass.c_name + var c_instance_name = mclass.c_instance_name var vft = self.method_tables[mclass] var attrs = self.attr_tables[mclass] @@ -755,20 +759,22 @@ class SeparateCompiler end if mtype.ctype != "val*" then - #Build instance struct - 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("{mtype.ctype} value;") - self.header.add_decl("\};") + if mtype.mclass.name == "Pointer" or mtype.mclass.kind != extern_kind then + #Build instance struct + self.header.add_decl("struct instance_{c_instance_name} \{") + self.header.add_decl("const struct type *type;") + self.header.add_decl("const struct class *class;") + self.header.add_decl("{mtype.ctype} value;") + self.header.add_decl("\};") + end if not self.runtime_type_analysis.live_types.has(mtype) then return #Build BOX - self.header.add_decl("val* BOX_{c_name}({mtype.ctype});") + self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});") v.add_decl("/* allocate {mtype} */") v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{") - v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));") + v.add("struct instance_{c_instance_name}*res = nit_alloc(sizeof(struct instance_{c_instance_name}));") v.require_declaration("type_{c_name}") v.add("res->type = &type_{c_name};") v.require_declaration("class_{c_name}") @@ -779,7 +785,7 @@ class SeparateCompiler return else if mclass.name == "NativeArray" then #Build instance struct - self.header.add_decl("struct instance_{c_name} \{") + self.header.add_decl("struct instance_{c_instance_name} \{") self.header.add_decl("const struct type *type;") self.header.add_decl("const struct class *class;") # NativeArrays are just a instance header followed by an array of values @@ -793,7 +799,7 @@ class SeparateCompiler var res = v.new_named_var(mtype, "self") res.is_exact = true var mtype_elt = mtype.arguments.first - v.add("{res} = nit_alloc(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));") + v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));") v.add("{res}->type = type;") hardening_live_type(v, "type") v.require_declaration("class_{c_name}") @@ -830,7 +836,7 @@ class SeparateCompiler v.add("if({t} == NULL) \{") v.add_abort("type null") v.add("\}") - v.add("if({t}->resolution_table == NULL) \{") + v.add("if({t}->table_size == 0) \{") v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", {t}->name);") v.add_abort("type dead") v.add("\}") @@ -939,7 +945,7 @@ class SeparateCompilerVisitor else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then return value else if value.mtype.ctype == "val*" then - return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) + return self.new_expr("((struct instance_{mtype.c_instance_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) else if mtype.ctype == "val*" then var valtype = value.mtype.as(MClassType) var res = self.new_var(mtype) @@ -948,6 +954,7 @@ class SeparateCompilerVisitor self.add("printf(\"Dead code executed!\\n\"); show_backtrace(1);") return res end + self.require_declaration("BOX_{valtype.c_name}") self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */") return res else if value.mtype.cname_blind == "void*" and mtype.cname_blind == "void*" then @@ -1259,7 +1266,7 @@ class SeparateCompilerVisitor # The attribute is primitive, thus we store it in a box # The trick is to create the box the first time then resuse the box self.add("if ({attr} != NULL) \{") - self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */") + self.add("((struct instance_{mtype.c_instance_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */") self.add("\} else \{") value = self.autobox(value, self.object_type.as_nullable) self.add("{attr} = {value}; /* {a} on {recv.inspect} */") @@ -1273,11 +1280,37 @@ class SeparateCompilerVisitor end end + # Check that mtype is a live open type + fun hardening_live_open_type(mtype: MType) + do + if not compiler.modelbuilder.toolcontext.opt_hardening.value then return + self.require_declaration(mtype.const_color) + var col = mtype.const_color + self.add("if({col} == -1) \{") + self.add("fprintf(stderr, \"Resolution of a dead open type: %s\\n\", \"{mtype.to_s.escape_to_c}\");") + self.add_abort("open type dead") + self.add("\}") + end + + # Check that mtype it a pointer to a live cast type + fun hardening_cast_type(t: String) + do + if not compiler.modelbuilder.toolcontext.opt_hardening.value then return + add("if({t} == NULL) \{") + add_abort("cast type null") + add("\}") + add("if({t}->id == -1 || {t}->color == -1) \{") + add("fprintf(stderr, \"Try to cast on a dead cast type: %s\\n\", {t}->name);") + add_abort("cast type dead") + add("\}") + end + redef fun init_instance(mtype) do self.require_declaration("NEW_{mtype.mclass.c_name}") var compiler = self.compiler if mtype isa MGenericType and mtype.need_anchor then + hardening_live_open_type(mtype) link_unresolved_type(self.frame.mpropdef.mclassdef, mtype) var recv = self.frame.arguments.first var recv_type_info = self.type_info(recv) @@ -1330,17 +1363,19 @@ class SeparateCompilerVisitor self.add_decl("const struct type* {type_struct};") # Either with resolution_table with a direct resolution - link_unresolved_type(self.frame.mpropdef.mclassdef, ntype) - self.require_declaration(ntype.const_color) + hardening_live_open_type(mtype) + link_unresolved_type(self.frame.mpropdef.mclassdef, mtype) + self.require_declaration(mtype.const_color) if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then - self.add("{type_struct} = {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {ntype.const_color})];") + self.add("{type_struct} = {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})];") else - self.add("{type_struct} = {recv_type_info}->resolution_table->types[{ntype.const_color}];") + self.add("{type_struct} = {recv_type_info}->resolution_table->types[{mtype.const_color}];") end if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then self.compiler.count_type_test_unresolved[tag] += 1 self.add("count_type_test_unresolved_{tag}++;") end + hardening_cast_type(type_struct) self.add("{cltype} = {type_struct}->color;") self.add("{idtype} = {type_struct}->id;") if maybe_null and accept_null == "0" then @@ -1352,6 +1387,7 @@ class SeparateCompilerVisitor else if ntype isa MClassType then compiler.undead_types.add(mtype) self.require_declaration("type_{mtype.c_name}") + hardening_cast_type("(&type_{mtype.c_name})") self.add("{cltype} = type_{mtype.c_name}.color;") self.add("{idtype} = type_{mtype.c_name}.id;") if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then @@ -1498,12 +1534,12 @@ class SeparateCompilerVisitor end end if primitive != null then - test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value") + test.add("((struct instance_{primitive.c_instance_name}*){value1})->value == ((struct instance_{primitive.c_instance_name}*){value2})->value") else if can_be_primitive(value1) and can_be_primitive(value2) then test.add("{value1}->class == {value2}->class") var s = new Array[String] for t, v in self.compiler.box_kinds do - s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)" + s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_instance_name}*){value1})->value == ((struct instance_{t.c_instance_name}*){value2})->value)" end test.add("({s.join(" || ")})") else @@ -1554,6 +1590,7 @@ class SeparateCompilerVisitor assert mtype isa MGenericType var compiler = self.compiler if mtype.need_anchor then + hardening_live_open_type(mtype) link_unresolved_type(self.frame.mpropdef.mclassdef, mtype) var recv = self.frame.arguments.first var recv_type_info = self.type_info(recv) @@ -1573,7 +1610,7 @@ class SeparateCompilerVisitor do var elttype = arguments.first.mtype var nclass = self.get_class("NativeArray") - var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values" + var recv = "((struct instance_{nclass.c_instance_name}*){arguments[0]})->values" if pname == "[]" then self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null))) return @@ -1581,7 +1618,7 @@ class SeparateCompilerVisitor self.add("{recv}[{arguments[1]}]={arguments[2]};") return else if pname == "copy_to" then - var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values" + var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values" self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));") return end @@ -1786,6 +1823,23 @@ end redef class MType fun const_color: String do return "COLOR_{c_name}" + + # C name of the instance type to use + fun c_instance_name: String do return c_name +end + +redef class MClassType + redef fun c_instance_name do return mclass.c_instance_name +end + +redef class MClass + # Extern classes use the C instance of kernel::Pointer + fun c_instance_name: String + do + if kind == extern_kind then + return "kernel__Pointer" + else return c_name + end end redef class MProperty