X-Git-Url: http://nitlanguage.org diff --git a/src/separate_compiler.nit b/src/separate_compiler.nit index 1e606b3..43d06c2 100644 --- a/src/separate_compiler.nit +++ b/src/separate_compiler.nit @@ -16,7 +16,7 @@ module separate_compiler import abstract_compiler -import layout_builders +import coloring import rapid_type_analysis # Add separate compiler specific options @@ -40,7 +40,7 @@ redef class ToolContext # --semi-global var opt_semi_global = new OptionBool("Enable all semi-global optimizations", "--semi-global") # --no-colo-dead-methods - var opt_no_colo_dead_methods = new OptionBool("Do not colorize dead methods", "--no-colo-dead-methods") + var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods") # --tables-metrics var opt_tables_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics") @@ -52,7 +52,7 @@ redef class ToolContext self.option_context.add_option(self.opt_no_union_attribute) self.option_context.add_option(self.opt_no_shortcut_equate) self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global) - self.option_context.add_option(self.opt_no_colo_dead_methods) + self.option_context.add_option(self.opt_colo_dead_methods) self.option_context.add_option(self.opt_tables_metrics) end @@ -105,7 +105,9 @@ redef class ModelBuilder # The main function of the C compiler.new_file("{mainmodule.name}.main") + compiler.compile_nitni_global_ref_functions compiler.compile_main_function + compiler.compile_finalizer_function # compile methods for m in mainmodule.in_importation.greaters do @@ -154,10 +156,11 @@ class SeparateCompiler private var undead_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] - private var resolution_layout: nullable Layout[MType] - protected var method_layout: nullable Layout[PropertyLayoutElement] - protected var attr_layout: nullable Layout[MAttribute] + private var type_ids: Map[MType, Int] + private var type_colors: Map[MType, Int] + private var opentype_colors: Map[MType, Int] + protected var method_colors: Map[PropertyLayoutElement, Int] + protected var attr_colors: Map[MAttribute, Int] init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do super(mainmodule, mmbuilder) @@ -188,7 +191,11 @@ class SeparateCompiler self.header.add_decl("void* val;") for c, v in self.box_kinds do var t = c.mclass_type - self.header.add_decl("{t.ctype} {t.ctypename};") + + # `Pointer` reuse the `val` field + if t.mclass.name == "Pointer" then continue + + self.header.add_decl("{t.ctype_extern} {t.ctypename};") end self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */") end @@ -210,9 +217,11 @@ class SeparateCompiler fun box_kind_of(mclass: MClass): Int do - if mclass.mclass_type.ctype == "val*" then + #var pointer_type = self.mainmodule.pointer_type + #if mclass.mclass_type.ctype == "val*" or mclass.mclass_type.is_subtype(self.mainmodule, mclass.mclass_type pointer_type) then + if mclass.mclass_type.ctype_extern == "val*" then return 0 - else if mclass.kind == extern_kind then + else if mclass.kind == extern_kind and mclass.name != "NativeString" then return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")] else return self.box_kinds[mclass] @@ -258,30 +267,14 @@ class SeparateCompiler # colorize classe properties fun do_property_coloring do - var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses) var rta = runtime_type_analysis # Layouts - var method_layout_builder: PropertyLayoutBuilder[PropertyLayoutElement] - var attribute_layout_builder: PropertyLayoutBuilder[MAttribute] - #FIXME PH and BM layouts too slow for large programs - #if modelbuilder.toolcontext.opt_bm_typing.value then - # method_layout_builder = new MMethodBMizer(self.mainmodule) - # attribute_layout_builder = new MAttributeBMizer(self.mainmodule) - #else if modelbuilder.toolcontext.opt_phmod_typing.value then - # method_layout_builder = new MMethodHasher(new PHModOperator, self.mainmodule) - # attribute_layout_builder = new MAttributeHasher(new PHModOperator, self.mainmodule) - #else if modelbuilder.toolcontext.opt_phand_typing.value then - # method_layout_builder = new MMethodHasher(new PHAndOperator, self.mainmodule) - # attribute_layout_builder = new MAttributeHasher(new PHAndOperator, self.mainmodule) - #else - - var class_layout_builder = new MClassColorer(self.mainmodule) - class_layout_builder.build_layout(mclasses) - method_layout_builder = new MPropertyColorer[PropertyLayoutElement](self.mainmodule, class_layout_builder) - attribute_layout_builder = new MPropertyColorer[MAttribute](self.mainmodule, class_layout_builder) - #end + var poset = mainmodule.flatten_mclass_hierarchy + var mclasses = new HashSet[MClass].from(poset) + var colorer = new POSetColorer[MClass] + colorer.colorize(poset) # The dead methods, still need to provide a dead color symbol var dead_methods = new Array[MMethod] @@ -294,7 +287,7 @@ class SeparateCompiler mattributes[mclass] = new HashSet[MAttribute] for mprop in self.mainmodule.properties(mclass) do if mprop isa MMethod then - if modelbuilder.toolcontext.opt_no_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then + if not modelbuilder.toolcontext.opt_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then dead_methods.add(mprop) continue end @@ -335,9 +328,10 @@ class SeparateCompiler end # methods coloration - self.method_layout = method_layout_builder.build_layout(mmethods) - self.method_tables = build_method_tables(mclasses, super_calls) - self.compile_color_consts(method_layout.pos) + var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts) + method_colors = meth_colorer.colorize(mmethods) + method_tables = build_method_tables(mclasses, super_calls) + compile_color_consts(method_colors) # attribute null color to dead methods and supercalls for mproperty in dead_methods do @@ -349,158 +343,93 @@ class SeparateCompiler end # attributes coloration - self.attr_layout = attribute_layout_builder.build_layout(mattributes) - self.attr_tables = build_attr_tables(mclasses) - self.compile_color_consts(attr_layout.pos) + var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts) + attr_colors = attr_colorer.colorize(mattributes) + attr_tables = build_attr_tables(mclasses) + compile_color_consts(attr_colors) end fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do - var layout = self.method_layout var tables = new HashMap[MClass, Array[nullable MPropDef]] for mclass in mclasses do var table = new Array[nullable MPropDef] - var supercalls = new List[MMethodDef] - - # first, fill table from parents by reverse linearization order - var parents = new Array[MClass] - if mainmodule.flatten_mclass_hierarchy.has(mclass) then - parents = mclass.in_hierarchy(mainmodule).greaters.to_a - self.mainmodule.linearize_mclasses(parents) - end - - for parent in parents do - if parent == mclass then continue - for mproperty in self.mainmodule.properties(parent) do - if not mproperty isa MMethod then continue - if not layout.pos.has_key(mproperty) then continue - var color = layout.pos[mproperty] - if table.length <= color then - for i in [table.length .. color[ do - table[i] = null - end - end - for mpropdef in mproperty.mpropdefs do - if mpropdef.mclassdef.mclass == parent then - table[color] = mpropdef - end - end - end + tables[mclass] = table - # lookup for super calls in super classes - for mmethoddef in super_calls do - for mclassdef in parent.mclassdefs do - if mclassdef.mpropdefs.has(mmethoddef) then - supercalls.add(mmethoddef) - end - end - end - end + var mproperties = self.mainmodule.properties(mclass) + var mtype = mclass.intro.bound_mtype - # then override with local properties - for mproperty in self.mainmodule.properties(mclass) do + for mproperty in mproperties do if not mproperty isa MMethod then continue - if not layout.pos.has_key(mproperty) then continue - var color = layout.pos[mproperty] + if not method_colors.has_key(mproperty) then continue + var color = method_colors[mproperty] if table.length <= color then for i in [table.length .. color[ do table[i] = null end end - for mpropdef in mproperty.mpropdefs do - if mpropdef.mclassdef.mclass == mclass then - table[color] = mpropdef - end - end + table[color] = mproperty.lookup_first_definition(mainmodule, mtype) end - # lookup for super calls in local class - for mmethoddef in super_calls do - for mclassdef in mclass.mclassdefs do - if mclassdef.mpropdefs.has(mmethoddef) then - supercalls.add(mmethoddef) - end - end - end - # insert super calls in table according to receiver - for supercall in supercalls do - var color = layout.pos[supercall] + for supercall in super_calls do + if not mtype.collect_mclassdefs(mainmodule).has(supercall.mclassdef) then continue + + var color = method_colors[supercall] if table.length <= color then for i in [table.length .. color[ do table[i] = null end end - var mmethoddef = supercall.lookup_next_definition(self.mainmodule, mclass.intro.bound_mtype) + var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype) table[color] = mmethoddef end - tables[mclass] = table + end return tables end fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do - var layout = self.attr_layout var tables = new HashMap[MClass, Array[nullable MPropDef]] for mclass in mclasses do var table = new Array[nullable MPropDef] - # first, fill table from parents by reverse linearization order - var parents = new Array[MClass] - if mainmodule.flatten_mclass_hierarchy.has(mclass) then - parents = mclass.in_hierarchy(mainmodule).greaters.to_a - self.mainmodule.linearize_mclasses(parents) - end - for parent in parents do - if parent == mclass then continue - for mproperty in self.mainmodule.properties(parent) do - if not mproperty isa MAttribute then continue - var color = layout.pos[mproperty] - if table.length <= color then - for i in [table.length .. color[ do - table[i] = null - end - end - for mpropdef in mproperty.mpropdefs do - if mpropdef.mclassdef.mclass == parent then - table[color] = mpropdef - end - end - end - end + tables[mclass] = table + + var mproperties = self.mainmodule.properties(mclass) + var mtype = mclass.intro.bound_mtype - # then override with local properties - for mproperty in self.mainmodule.properties(mclass) do + for mproperty in mproperties do if not mproperty isa MAttribute then continue - var color = layout.pos[mproperty] + if not attr_colors.has_key(mproperty) then continue + var color = attr_colors[mproperty] if table.length <= color then for i in [table.length .. color[ do table[i] = null end end - for mpropdef in mproperty.mpropdefs do - if mpropdef.mclassdef.mclass == mclass then - table[color] = mpropdef - end - end + table[color] = mproperty.lookup_first_definition(mainmodule, mtype) end - tables[mclass] = table end return tables end # colorize live types of the program private fun do_type_coloring: POSet[MType] do + # Collect types to colorize + var live_types = runtime_type_analysis.live_types + var live_cast_types = runtime_type_analysis.live_cast_types 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(live_types) + mtypes.add_all(live_cast_types) for c in self.box_kinds.keys do mtypes.add(c.mclass_type) end - # Typing Layout - var layout_builder = new MTypeColorer(self.mainmodule) - # colorize types - self.type_layout = layout_builder.build_layout(mtypes) - var poset = layout_builder.poset.as(not null) - self.type_tables = self.build_type_tables(poset) + # Compute colors + var poset = poset_from_mtypes(mtypes) + var colorer = new POSetColorer[MType] + colorer.colorize(poset) + type_ids = colorer.ids + type_colors = colorer.colors + type_tables = build_type_tables(poset) # VT and FT are stored with other unresolved types in the big resolution_tables self.compile_resolution_tables(mtypes) @@ -508,19 +437,27 @@ class SeparateCompiler return poset end + private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do + var poset = new POSet[MType] + for e in mtypes do + poset.add_node(e) + for o in mtypes do + if e == o then continue + if e.is_subtype(mainmodule, null, o) then + poset.add_edge(e, o) + end + end + end + return poset + end + # Build type tables fun build_type_tables(mtypes: POSet[MType]): Map[MType, Array[nullable MType]] do var tables = new HashMap[MType, Array[nullable MType]] - var layout = self.type_layout for mtype in mtypes do var table = new Array[nullable MType] for sup in mtypes[mtype].greaters do - var color: Int - if layout isa PHLayout[MType, MType] then - color = layout.hashes[mtype][sup] - else - color = layout.pos[sup] - end + var color = type_colors[sup] if table.length <= color then for i in [table.length .. color[ do table[i] = null @@ -553,9 +490,9 @@ class SeparateCompiler end # Compute the table layout with the prefered method - var resolution_builder = new ResolutionColorer - self.resolution_layout = resolution_builder.build_layout(mtype2unresolved) - self.resolution_tables = self.build_resolution_tables(mtype2unresolved) + var colorer = new BucketsColorer[MType, MType] + opentype_colors = colorer.colorize(mtype2unresolved) + resolution_tables = self.build_resolution_tables(mtype2unresolved) # Compile a C constant for each collected unresolved type. # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it) @@ -565,8 +502,8 @@ class SeparateCompiler end var all_unresolved_types_colors = new HashMap[MType, Int] for t in all_unresolved do - if self.resolution_layout.pos.has_key(t) then - all_unresolved_types_colors[t] = self.resolution_layout.pos[t] + if opentype_colors.has_key(t) then + all_unresolved_types_colors[t] = opentype_colors[t] else all_unresolved_types_colors[t] = -1 end @@ -582,16 +519,10 @@ class SeparateCompiler fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do var tables = new HashMap[MClassType, Array[nullable MType]] - var layout = self.resolution_layout for mclasstype, mtypes in elements do var table = new Array[nullable MType] for mtype in mtypes do - var color: Int - if layout isa PHLayout[MClassType, MType] then - color = layout.hashes[mclasstype][mtype] - else - color = layout.pos[mtype] - end + var color = opentype_colors[mtype] if table.length <= color then for i in [table.length .. color[ do table[i] = null @@ -628,7 +559,6 @@ class SeparateCompiler 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 @@ -643,7 +573,7 @@ class SeparateCompiler # type id (for cast target) if is_cast_live then - v.add_decl("{layout.ids[mtype]},") + v.add_decl("{type_ids[mtype]},") else v.add_decl("-1, /*CAST DEAD*/") end @@ -653,11 +583,7 @@ class SeparateCompiler # 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 + v.add_decl("{type_colors[mtype]},") else v.add_decl("-1, /*CAST DEAD*/") end @@ -671,8 +597,7 @@ class SeparateCompiler # resolution table (for receiver) if is_live then - var mclass_type = mtype - if mclass_type isa MNullableType then mclass_type = mclass_type.mtype + var mclass_type = mtype.as_notnullable assert mclass_type isa MClassType if resolution_tables[mclass_type].is_empty then v.add_decl("NULL, /*NO RESOLUTIONS*/") @@ -693,7 +618,7 @@ class SeparateCompiler if stype == null then v.add_decl("-1, /* empty */") else - v.add_decl("{layout.ids[stype]}, /* {stype} */") + v.add_decl("{type_ids[stype]}, /* {stype} */") end end v.add_decl("\},") @@ -705,14 +630,7 @@ class SeparateCompiler fun compile_type_resolution_table(mtype: MType) do - var mclass_type: MClassType - if mtype isa MNullableType then - mclass_type = mtype.mtype.as(MClassType) - else - mclass_type = mtype.as(MClassType) - end - - var layout = self.resolution_layout + var mclass_type = mtype.as_notnullable.as(MClassType) # extern const struct resolution_table_X resolution_table_X self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};") @@ -720,11 +638,7 @@ class SeparateCompiler # const struct fts_table_X fts_table_X var v = new_visitor v.add_decl("const struct types resolution_table_{mtype.c_name} = \{") - if layout isa PHLayout[MClassType, MType] then - v.add_decl("{layout.masks[mclass_type]},") - else - v.add_decl("0, /* dummy */") - end + v.add_decl("0, /* dummy */") v.add_decl("\{") for t in self.resolution_tables[mclass_type] do if t == null then @@ -735,7 +649,7 @@ class SeparateCompiler # the value stored is tv. var tv = t.resolve_for(mclass_type, mclass_type, self.mainmodule, true) # FIXME: What typeids means here? How can a tv not be live? - if self.type_layout.ids.has_key(tv) then + if type_ids.has_key(tv) then v.require_declaration("type_{tv.c_name}") v.add_decl("&type_{tv.c_name}, /* {t}: {tv} */") else @@ -754,14 +668,13 @@ 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] var v = new_visitor var rta = runtime_type_analysis - var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" + var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" and mclass.name != "Pointer" v.add_decl("/* runtime class {c_name} */") @@ -790,23 +703,24 @@ class SeparateCompiler v.add_decl("\};") end - if mtype.ctype != "val*" then - 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 mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then + # Is a primitive type or the Pointer class, not any other extern class - if not rta.live_types.has(mtype) then return + #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_extern} value;") + self.header.add_decl("\};") + + if not rta.live_types.has(mtype) and mtype.mclass.name != "Pointer" then return #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("struct instance_{c_instance_name}*res = nit_alloc(sizeof(struct instance_{c_instance_name}));") + 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.compiler.undead_types.add(mtype) v.require_declaration("type_{c_name}") v.add("res->type = &type_{c_name};") v.require_declaration("class_{c_name}") @@ -814,10 +728,31 @@ class SeparateCompiler v.add("res->value = value;") v.add("return (val*)res;") v.add("\}") + + if mtype.mclass.name != "Pointer" then return + + v = new_visitor + self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);") + v.add_decl("/* allocate {mtype} */") + v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{") + if is_dead then + v.add_abort("{mclass} is DEAD") + else + var res = v.new_named_var(mtype, "self") + res.is_exact = true + v.add("{res} = nit_alloc(sizeof(struct instance_{mtype.c_name}));") + v.add("{res}->type = type;") + hardening_live_type(v, "type") + v.require_declaration("class_{c_name}") + v.add("{res}->class = &class_{c_name};") + v.add("((struct instance_{mtype.c_name}*){res})->value = NULL;") + v.add("return {res};") + end + v.add("\}") return else if mclass.name == "NativeArray" then #Build instance struct - self.header.add_decl("struct instance_{c_instance_name} \{") + self.header.add_decl("struct instance_{c_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 a length and an array of values @@ -830,9 +765,9 @@ class SeparateCompiler v.add_decl("/* allocate {mtype} */") v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{") var res = v.get_name("self") - v.add_decl("struct instance_{c_instance_name} *{res};") + v.add_decl("struct instance_{c_name} *{res};") var mtype_elt = mtype.arguments.first - v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));") + v.add("{res} = nit_alloc(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));") v.add("{res}->type = type;") hardening_live_type(v, "type") v.require_declaration("class_{c_name}") @@ -841,6 +776,30 @@ class SeparateCompiler v.add("return (val*){res};") v.add("\}") return + else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then + # Is an extern class (other than Pointer and NativeString) + # Pointer is caught in a previous `if`, and NativeString is internal + + var pointer_type = mainmodule.pointer_type + + self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);") + v.add_decl("/* allocate {mtype} */") + v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{") + if is_dead then + v.add_abort("{mclass} is DEAD") + else + var res = v.new_named_var(mtype, "self") + res.is_exact = true + v.add("{res} = nit_alloc(sizeof(struct instance_{pointer_type.c_name}));") + v.add("{res}->type = type;") + hardening_live_type(v, "type") + v.require_declaration("class_{c_name}") + v.add("{res}->class = &class_{c_name};") + v.add("((struct instance_{pointer_type.c_name}*){res})->value = NULL;") + v.add("return {res};") + end + v.add("\}") + return end #Build NEW @@ -858,6 +817,7 @@ class SeparateCompiler v.require_declaration("class_{c_name}") v.add("{res}->class = &class_{c_name};") self.generate_init_attr(v, res, mtype) + v.set_finalizer res v.add("return {res};") end v.add("\}") @@ -871,7 +831,7 @@ class SeparateCompiler v.add_abort("type null") v.add("\}") v.add("if({t}->table_size == 0) \{") - v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", {t}->name);") + v.add("PRINT_ERROR(\"Insantiation of a dead type: %s\\n\", {t}->name);") v.add_abort("type dead") v.add("\}") end @@ -958,9 +918,17 @@ class SeparateCompiler redef fun compile_nitni_structs do - self.header.add_decl("struct nitni_instance \{struct instance *value;\};") + self.header.add_decl """ +struct nitni_instance \{ + struct nitni_instance *next, + *prev; /* adjacent global references in global list */ + int count; /* number of time this global reference has been marked */ + struct instance *value; +\}; +""" + super end - + redef fun finalize_ffi_for_module(mmodule) do var old_module = self.mainmodule @@ -992,6 +960,22 @@ class SeparateCompilerVisitor end end + redef fun unbox_signature_extern(m, args) + do + var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true) + var recv = args.first + if not m.mproperty.is_init and m.is_extern then + args.first = self.unbox_extern(args.first, m.mclassdef.mclass.mclass_type) + end + for i in [0..msignature.arity[ do + var t = msignature.mparameters[i].mtype + if i == msignature.vararg_rank then + t = args[i+1].mtype + end + if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t) + end + end + redef fun autobox(value, mtype) do if value.mtype == mtype then @@ -999,29 +983,70 @@ 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_instance_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) + return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) else if mtype.ctype == "val*" then var valtype = value.mtype.as(MClassType) + if mtype isa MClassType and mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then + valtype = compiler.mainmodule.pointer_type + end var res = self.new_var(mtype) if compiler.runtime_type_analysis != null and 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("printf(\"Dead code executed!\\n\"); show_backtrace(1);") + self.add("PRINT_ERROR(\"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.ctype == "void*" and mtype.ctype == "void*" then + else if (value.mtype.ctype == "void*" and mtype.ctype == "void*") or + (value.mtype.ctype == "char*" and mtype.ctype == "void*") or + (value.mtype.ctype == "void*" and mtype.ctype == "char*") then return value else # Bad things will appen! var res = self.new_var(mtype) self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */") - self.add("printf(\"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}\"); show_backtrace(1);") return res end end + redef fun unbox_extern(value, mtype) + do + if mtype isa MClassType and mtype.mclass.kind == extern_kind and + mtype.mclass.name != "NativeString" 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} */" + return res + else + return value + end + end + + redef fun box_extern(value, mtype) + do + if mtype isa MClassType and mtype.mclass.kind == extern_kind and + mtype.mclass.name != "NativeString" 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);") + return res + end + self.require_declaration("BOX_{valtype.c_name}") + self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */") + self.require_declaration("type_{mtype.c_name}") + self.add("{res}->type = &type_{mtype.c_name};") + self.require_declaration("class_{mtype.c_name}") + self.add("{res}->class = &class_{mtype.c_name};") + return res + else + return value + end + end + # Return a C expression returning the runtime type structure of the value # The point of the method is to works also with primitives types. fun type_info(value: RuntimeVariable): String @@ -1039,11 +1064,12 @@ class SeparateCompilerVisitor do var rta = compiler.runtime_type_analysis var recv = args.first.mtype - if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null then + var mmethod = callsite.mproperty + # TODO: Inlining of new-style constructors + if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then var tgs = rta.live_targets(callsite) if tgs.length == 1 then # DIRECT CALL - var mmethod = callsite.mproperty self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args) var res0 = before_send(mmethod, args) var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args) @@ -1090,7 +1116,7 @@ class SeparateCompilerVisitor do var res: nullable RuntimeVariable = null var recv = arguments.first - var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!=" + var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or mmethod.name == "==" or mmethod.name == "!=" var maybenull = recv.mcasttype isa MNullableType and consider_null if maybenull then self.add("if ({recv} == NULL) \{") @@ -1387,7 +1413,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_instance_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */") + self.add("((struct instance_{mtype.c_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} */") @@ -1408,7 +1434,7 @@ class SeparateCompilerVisitor 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("PRINT_ERROR(\"Resolution of a dead open type: %s\\n\", \"{mtype.to_s.escape_to_c}\");") self.add_abort("open type dead") self.add("\}") end @@ -1421,7 +1447,7 @@ class SeparateCompilerVisitor 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("PRINT_ERROR(\"Try to cast on a dead cast type: %s\\n\", {t}->name);") add_abort("cast type dead") add("\}") end @@ -1508,7 +1534,7 @@ class SeparateCompilerVisitor self.add("count_type_test_resolved_{tag}++;") end else - self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);") + self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);") end # check color is in table @@ -1561,7 +1587,8 @@ class SeparateCompilerVisitor self.add_decl("const char* {res};") if value.mtype.ctype == "val*" then self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;" - else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind then + else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind and + value.mtype.as(MClassType).name != "NativeString" then self.add "{res} = \"{value.mtype.as(MClassType).mclass}\";" else self.require_declaration("type_{value.mtype.c_name}") @@ -1644,12 +1671,12 @@ class SeparateCompilerVisitor end end if primitive != null then - test.add("((struct instance_{primitive.c_instance_name}*){value1})->value == ((struct instance_{primitive.c_instance_name}*){value2})->value") + test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_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_instance_name}*){value1})->value == ((struct instance_{t.c_instance_name}*){value2})->value)" + s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)" end test.add("({s.join(" || ")})") else @@ -1662,8 +1689,7 @@ class SeparateCompilerVisitor fun can_be_primitive(value: RuntimeVariable): Bool do - var t = value.mcasttype - if t isa MNullableType then t = t.mtype + var t = value.mcasttype.as_notnullable if not t isa MClassType then return false var k = t.mclass.kind return k == interface_kind or t.ctype != "val*" @@ -1693,7 +1719,7 @@ class SeparateCompilerVisitor return res end - fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable + redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable do var mtype = self.get_class("NativeArray").get_mtype([elttype]) self.require_declaration("NEW_{mtype.mclass.c_name}") @@ -1716,7 +1742,7 @@ class SeparateCompilerVisitor do var elttype = arguments.first.mtype var nclass = self.get_class("NativeArray") - var recv = "((struct instance_{nclass.c_instance_name}*){arguments[0]})->values" + var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values" if pname == "[]" then self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null))) return @@ -1724,11 +1750,11 @@ class SeparateCompilerVisitor self.add("{recv}[{arguments[1]}]={arguments[2]};") return else if pname == "length" then - self.ret(self.new_expr("((struct instance_{nclass.c_instance_name}*){arguments[0]})->length", ret_type.as(not null))) + self.ret(self.new_expr("((struct instance_{nclass.c_name}*){arguments[0]})->length", ret_type.as(not null))) return else if pname == "copy_to" then - var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values" - self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));") + var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values" + self.add("memmove({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));") return end end @@ -1932,29 +1958,21 @@ 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 +interface PropertyLayoutElement end redef class MProperty + super PropertyLayoutElement fun const_color: String do return "COLOR_{c_name}" end redef class MPropDef + super PropertyLayoutElement fun const_color: String do return "COLOR_{c_name}" end + +redef class AExternInitPropdef + # The semi-global compilation does not support inlining calls to extern news + redef fun can_inline do return false +end