X-Git-Url: http://nitlanguage.org diff --git a/src/separate_compiler.nit b/src/separate_compiler.nit index a260c4a..dcd7cc7 100644 --- a/src/separate_compiler.nit +++ b/src/separate_compiler.nit @@ -59,30 +59,36 @@ redef class ModelBuilder fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis) do var time0 = get_time - self.toolcontext.info("*** COMPILING TO C ***", 1) + self.toolcontext.info("*** GENERATING C ***", 1) var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis) compiler.compile_header # compile class structures + self.toolcontext.info("Property coloring", 2) + compiler.new_file("{mainmodule.name}.classes") + compiler.do_property_coloring for m in mainmodule.in_importation.greaters do for mclass in m.intro_mclasses do + if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue compiler.compile_class_to_c(mclass) end end # The main function of the C - compiler.new_file + compiler.new_file("{mainmodule.name}.main") compiler.compile_main_function # compile methods for m in mainmodule.in_importation.greaters do - compiler.new_file + self.toolcontext.info("Generate C for module {m}", 2) + compiler.new_file("{m.name}.sep") compiler.compile_module_to_c(m) end # compile live & cast type structures - compiler.new_file + self.toolcontext.info("Type coloring", 2) + compiler.new_file("{mainmodule.name}.types") var mtypes = compiler.do_type_coloring for t in mtypes do compiler.compile_type_to_c(t) @@ -90,6 +96,8 @@ redef class ModelBuilder compiler.display_stats + var time1 = get_time + self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2) write_and_make(compiler) end end @@ -112,24 +120,25 @@ class SeparateCompiler init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis) do super(mainmodule, mmbuilder) - self.header = new_visitor + var file = new_file("nit.common") + self.header = new CodeWriter(file) self.runtime_type_analysis = runtime_type_analysis - self.do_property_coloring self.compile_box_kinds end redef fun compile_header_structs do self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */") self.compile_header_attribute_structs - self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */") + self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[]; \}; /* general C type representing a Nit class. */") # With resolution_table_table, all live type resolution are stored in a big table: resolution_table - self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; struct types *resolution_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */") + self.header.add_decl("struct type \{ int id; const char *name; int color; short int is_nullable; const struct types *resolution_table; int table_size; int type_table[]; \}; /* general C type representing a Nit type. */") + self.header.add_decl("struct instance \{ const struct type *type; const struct class *class; nitattribute_t attrs[]; \}; /* general C type representing a Nit instance. */") if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then - self.header.add_decl("struct types \{ int mask; struct type *types[1]; \}; /* a list types (used for vts, fts and unresolved lists). */") + self.header.add_decl("struct types \{ int mask; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */") else - self.header.add_decl("struct types \{ struct type *types[1]; \}; /* a list types (used for vts, fts and unresolved lists). */") + self.header.add_decl("struct types \{ int dummy; const struct type *types[]; \}; /* a list types (used for vts, fts and unresolved lists). */") end if modelbuilder.toolcontext.opt_phmod_typing.value then @@ -138,7 +147,7 @@ class SeparateCompiler self.header.add_decl("#define HASH(mask, id) ((mask)&(id))") end - self.header.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */") + self.header.add_decl("typedef struct instance val; /* general C type representing a Nit instance. */") end fun compile_header_attribute_structs @@ -183,21 +192,22 @@ class SeparateCompiler end fun compile_color_consts(colors: Map[Object, Int]) do + var v = new_visitor for m, c in colors do if color_consts_done.has(m) then continue if m isa MProperty then if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then - self.header.add_decl("#define {m.const_color} {c}") + self.provide_declaration(m.const_color, "#define {m.const_color} {c}") else - self.header.add_decl("extern const int {m.const_color};") - self.header.add("const int {m.const_color} = {c};") + self.provide_declaration(m.const_color, "extern const int {m.const_color};") + v.add("const int {m.const_color} = {c};") end else if m isa MType then if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then - self.header.add_decl("#define {m.const_color} {c}") + self.provide_declaration(m.const_color, "#define {m.const_color} {c}") else - self.header.add_decl("extern const int {m.const_color};") - self.header.add("const int {m.const_color} = {c};") + self.provide_declaration(m.const_color, "extern const int {m.const_color};") + v.add("const int {m.const_color} = {c};") end end color_consts_done.add(m) @@ -213,13 +223,23 @@ class SeparateCompiler # Layouts var method_layout_builder: PropertyLayoutBuilder[MMethod] var attribute_layout_builder: PropertyLayoutBuilder[MAttribute] - if modelbuilder.toolcontext.opt_bm_typing.value then - method_layout_builder = new MMethodBMizer(self.mainmodule) - attribute_layout_builder = new MAttributeBMizer(self.mainmodule) - else - method_layout_builder = new MMethodColorer(self.mainmodule) - attribute_layout_builder = new MAttributeColorer(self.mainmodule) - end + #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 MMethodColorer(self.mainmodule, class_layout_builder) + attribute_layout_builder = new MAttributeColorer(self.mainmodule, class_layout_builder) + #end # methods coloration var method_layout = method_layout_builder.build_layout(mclasses) @@ -239,9 +259,13 @@ class SeparateCompiler for mclass in mclasses do var table = new Array[nullable MPropDef] # first, fill table from parents by reverse linearization order - var parents = self.mainmodule.super_mclasses(mclass) - var lin = self.mainmodule.reverse_linearize_mclasses(parents) - for parent in lin do + 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 var color = layout.pos[mproperty] @@ -283,9 +307,13 @@ class SeparateCompiler for mclass in mclasses do var table = new Array[nullable MPropDef] # first, fill table from parents by reverse linearization order - var parents = self.mainmodule.super_mclasses(mclass) - var lin = self.mainmodule.reverse_linearize_mclasses(parents) - for parent in lin do + 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] @@ -323,7 +351,7 @@ class SeparateCompiler end # colorize live types of the program - private fun do_type_coloring: Set[MType] do + private fun do_type_coloring: POSet[MType] do var mtypes = new HashSet[MType] mtypes.add_all(self.runtime_type_analysis.live_types) mtypes.add_all(self.runtime_type_analysis.live_cast_types) @@ -333,7 +361,7 @@ class SeparateCompiler end for mtype in mtypes do - retieve_live_partial_types(mtype) + retrieve_partial_types(mtype) end mtypes.add_all(self.partial_types) @@ -351,24 +379,22 @@ class SeparateCompiler # colorize types self.type_layout = layout_builder.build_layout(mtypes) - self.type_tables = self.build_type_tables(mtypes) + var poset = layout_builder.poset.as(not null) + self.type_tables = self.build_type_tables(poset) # VT and FT are stored with other unresolved types in the big resolution_tables self.compile_resolution_tables(mtypes) - return mtypes + return poset end # Build type tables - fun build_type_tables(mtypes: Set[MType]): Map[MType, Array[nullable MType]] do + 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] - var supers = new HashSet[MType] - supers.add_all(self.mainmodule.super_mtypes(mtype, mtypes)) - supers.add(mtype) - for sup in supers do + for sup in mtypes[mtype].greaters do var color: Int if layout isa PHLayout[MType, MType] then color = layout.hashes[mtype][sup] @@ -467,7 +493,7 @@ class SeparateCompiler return tables end - fun retieve_live_partial_types(mtype: MType) do + fun retrieve_partial_types(mtype: MType) do # add formal types arguments to mtypes if mtype isa MGenericType then for ft in mtype.arguments do @@ -476,7 +502,7 @@ class SeparateCompiler abort end self.partial_types.add(ft) - retieve_live_partial_types(ft) + retrieve_partial_types(ft) end end var mclass_type: MClassType @@ -504,12 +530,10 @@ class SeparateCompiler for pd in cd.mpropdefs do if not pd isa MMethodDef then continue #print "compile {pd} @ {cd} @ {mmodule}" - var r = new SeparateRuntimeFunction(pd) + var r = pd.separate_runtime_function r.compile_to_c(self) - if true or cd.bound_mtype.ctype != "val*" then - var r2 = new VirtualRuntimeFunction(pd) - r2.compile_to_c(self) - end + var r2 = pd.virtual_runtime_function + r2.compile_to_c(self) end end self.mainmodule = old_module @@ -523,19 +547,10 @@ class SeparateCompiler v.add_decl("/* runtime type {mtype} */") # extern const struct type_X - self.header.add_decl("extern const struct type_{c_name} type_{c_name};") - self.header.add_decl("struct type_{c_name} \{") - self.header.add_decl("int id;") - self.header.add_decl("const char *name;") - self.header.add_decl("int color;") - self.header.add_decl("short int is_nullable;") - self.header.add_decl("const struct types *resolution_table;") - self.header.add_decl("int table_size;") - self.header.add_decl("int type_table[{self.type_tables[mtype].length}];") - self.header.add_decl("\};") + self.provide_declaration("type_{c_name}", "extern const struct type type_{c_name};") # const struct type_X - v.add_decl("const struct type_{c_name} type_{c_name} = \{") + v.add_decl("const struct type type_{c_name} = \{") v.add_decl("{self.type_layout.ids[mtype]},") v.add_decl("\"{mtype}\", /* class_name_string */") var layout = self.type_layout @@ -550,7 +565,8 @@ class SeparateCompiler v.add_decl("0,") end if compile_type_resolution_table(mtype) then - v.add_decl("(struct types*) &resolution_table_{c_name},") + v.require_declaration("resolution_table_{c_name}") + v.add_decl("&resolution_table_{c_name},") else v.add_decl("NULL,") end @@ -580,19 +596,15 @@ class SeparateCompiler var layout = self.resolution_layout # extern const struct resolution_table_X resolution_table_X - self.header.add_decl("extern const struct resolution_table_{mtype.c_name} resolution_table_{mtype.c_name};") - self.header.add_decl("struct resolution_table_{mtype.c_name} \{") - if layout isa PHLayout[MClassType, MType] then - self.header.add_decl("int mask;") - end - self.header.add_decl("struct type *types[{self.resolution_tables[mclass_type].length}];") - self.header.add_decl("\};") + self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};") # const struct fts_table_X fts_table_X var v = new_visitor - v.add_decl("const struct resolution_table_{mtype.c_name} resolution_table_{mtype.c_name} = \{") + 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("\{") for t in self.resolution_tables[mclass_type] do @@ -605,13 +617,14 @@ class SeparateCompiler 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 - v.add_decl("(struct type*)&type_{tv.c_name}, /* {t}: {tv} */") + v.require_declaration("type_{tv.c_name}") + v.add_decl("&type_{tv.c_name}, /* {t}: {tv} */") else v.add_decl("NULL, /* empty ({t}: {tv} not a live type) */") end end end - v.add_decl("\},") + v.add_decl("\}") v.add_decl("\};") return true end @@ -628,32 +641,30 @@ class SeparateCompiler var attrs = self.attr_tables[mclass] var v = new_visitor - v.add_decl("/* runtime class {c_name} */") + var is_dead = not runtime_type_analysis.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" - self.header.add_decl("struct class_{c_name} \{") - self.header.add_decl("int box_kind;") - self.header.add_decl("nitmethod_t vft[{vft.length}];") - self.header.add_decl("\};") + v.add_decl("/* runtime class {c_name} */") # Build class vft - self.header.add_decl("extern const struct class_{c_name} class_{c_name};") - v.add_decl("const struct class_{c_name} class_{c_name} = \{") - v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */") - v.add_decl("\{") - for i in [0 .. vft.length[ do - var mpropdef = vft[i] - if mpropdef == null then - v.add_decl("NULL, /* empty */") - else - if true or mpropdef.mclassdef.bound_mtype.ctype != "val*" then - v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */") + if not is_dead then + 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("{self.box_kind_of(mclass)}, /* box_kind */") + v.add_decl("\{") + for i in [0 .. vft.length[ do + var mpropdef = vft[i] + if mpropdef == null then + v.add_decl("NULL, /* empty */") else - v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */") + assert mpropdef isa MMethodDef + var rf = mpropdef.virtual_runtime_function + v.require_declaration(rf.c_name) + v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */") end end + v.add_decl("\}") + v.add_decl("\};") end - v.add_decl("\}") - v.add_decl("\};") if mtype.ctype != "val*" then #Build instance struct @@ -665,70 +676,80 @@ class SeparateCompiler if not self.runtime_type_analysis.live_types.has(mtype) then return + #Build BOX self.header.add_decl("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 = GC_MALLOC(sizeof(struct instance_{c_name}));") - v.add("res->type = (struct type*) &type_{c_name};") - v.add("res->class = (struct class*) &class_{c_name};") + v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));") + v.require_declaration("type_{c_name}") + v.add("res->type = &type_{c_name};") + v.require_declaration("class_{c_name}") + v.add("res->class = &class_{c_name};") v.add("res->value = value;") v.add("return (val*)res;") v.add("\}") return - end - - var is_native_array = mclass.name == "NativeArray" - - var sig - if is_native_array then - sig = "int length, struct type* type" - else - sig = "struct type* type" - end - - #Build instance struct - #extern const struct instance_array__NativeArray instance_array__NativeArray; - 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("nitattribute_t attrs[{attrs.length}];") - if is_native_array then + else if mclass.name == "NativeArray" 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;") # NativeArrays are just a instance header followed by an array of values self.header.add_decl("val* values[0];") - end - self.header.add_decl("\};") - + self.header.add_decl("\};") - self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});") - v.add_decl("/* allocate {mtype} */") - v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{") - var res = v.new_named_var(mtype, "self") - res.is_exact = true - if is_native_array then + #Build NEW + self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(int length, const struct type* type);") + v.add_decl("/* allocate {mtype} */") + v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{") + var res = v.new_named_var(mtype, "self") + res.is_exact = true var mtype_elt = mtype.arguments.first - v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));") - else - v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));") - end - v.add("{res}->type = type;") - if v.compiler.modelbuilder.toolcontext.opt_hardening.value then - v.add("if(type == NULL) \{") - v.add_abort("type null") - v.add("\}") - v.add("if(type->resolution_table == NULL) \{") - v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", type->name);") - v.add_abort("type dead") + 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}") + v.add("{res}->class = &class_{c_name};") + v.add("return {res};") v.add("\}") + return end - v.add("{res}->class = (struct class*) &class_{c_name};") - self.generate_init_attr(v, res, mtype) - v.add("return {res};") + #Build NEW + 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) + {attrs.length}*sizeof(nitattribute_t));") + v.add("{res}->type = type;") + hardening_live_type(v, "type") + v.require_declaration("class_{c_name}") + v.add("{res}->class = &class_{c_name};") + self.generate_init_attr(v, res, mtype) + v.add("return {res};") + end v.add("\}") generate_check_init_instance(mtype) end + # Add a dynamic test to ensure that the type referenced by `t` is a live type + fun hardening_live_type(v: VISITOR, t: String) + do + if not v.compiler.modelbuilder.toolcontext.opt_hardening.value then return + v.add("if({t} == NULL) \{") + v.add_abort("type null") + v.add("\}") + v.add("if({t}->resolution_table == NULL) \{") + v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", {t}->name);") + v.add_abort("type dead") + v.add("\}") + end + redef fun generate_check_init_instance(mtype) do if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return @@ -736,10 +757,14 @@ class SeparateCompiler var v = self.new_visitor var c_name = mtype.mclass.c_name var res = new RuntimeVariable("self", mtype, mtype) - self.header.add_decl("void CHECK_NEW_{c_name}({mtype.ctype});") + self.provide_declaration("CHECK_NEW_{c_name}", "void CHECK_NEW_{c_name}({mtype.ctype});") v.add_decl("/* allocate {mtype} */") v.add_decl("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{") - self.generate_check_attr(v, res, mtype) + if runtime_type_analysis.live_classes.has(mtype.mclass) then + self.generate_check_attr(v, res, mtype) + else + v.add_abort("{mtype.mclass} is DEAD") + end v.add("\}") end @@ -860,6 +885,7 @@ class SeparateCompilerVisitor if value.mtype.ctype == "val*" then return "{value}->type" else + self.require_declaration("type_{value.mtype.c_name}") return "(&type_{value.mtype.c_name})" end end @@ -867,7 +893,13 @@ class SeparateCompilerVisitor redef fun send(mmethod, arguments) do if arguments.first.mcasttype.ctype != "val*" then - return self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments) + # In order to shortcut the primitive, we need to find the most specific method + # Howverr, because of performance (no flattening), we always work on the realmainmodule + var m = self.compiler.mainmodule + self.compiler.mainmodule = self.compiler.realmainmodule + var res = self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments) + self.compiler.mainmodule = m + return res end var res: nullable RuntimeVariable @@ -948,6 +980,7 @@ class SeparateCompilerVisitor var r if ret == null then r = "void" else r = ret.ctype + self.require_declaration(mmethod.const_color) var call = "(({r} (*)({s}))({arguments.first}->class->vft[{mmethod.const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/" if res != null then @@ -996,6 +1029,7 @@ class SeparateCompilerVisitor # Autobox arguments self.adapt_signature(mmethoddef, arguments) + self.require_declaration(mmethoddef.c_name) if res == null then self.add("{mmethoddef.c_name}({arguments.join(", ")});") return null @@ -1006,6 +1040,13 @@ class SeparateCompilerVisitor return res end + redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable + do + # FIXME implements a polymorphic access in tables + m = m.lookup_next_definition(m.mclassdef.mmodule, m.mclassdef.bound_mtype) + return self.call(m, recvtype, args) + end + redef fun vararg_instance(mpropdef, recv, varargs, elttype) do # A vararg must be stored into an new array @@ -1040,6 +1081,7 @@ class SeparateCompilerVisitor return res end + self.require_declaration(a.const_color) if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/") else @@ -1062,6 +1104,7 @@ class SeparateCompilerVisitor var intromclassdef = a.intro.mclassdef ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true) + self.require_declaration(a.const_color) if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then # Get the attribute or a box (ie. always a val*) var cret = self.object_type.as_nullable @@ -1107,6 +1150,7 @@ class SeparateCompilerVisitor # Adapt the value to the declared type value = self.autobox(value, mtype) + self.require_declaration(a.const_color) if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then var attr = "{recv}->attrs[{a.const_color}]" if mtype.ctype != "val*" then @@ -1130,24 +1174,28 @@ class SeparateCompilerVisitor 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 link_unresolved_type(self.frame.mpropdef.mclassdef, mtype) var recv = self.frame.arguments.first var recv_type_info = self.type_info(recv) + self.require_declaration(mtype.const_color) if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then - return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype) + return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype) else - return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype) + return self.new_expr("NEW_{mtype.mclass.c_name}({recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype) end end compiler.undead_types.add(mtype) - return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype) + self.require_declaration("type_{mtype.c_name}") + return self.new_expr("NEW_{mtype.mclass.c_name}(&type_{mtype.c_name})", mtype) end redef fun check_init_instance(value, mtype) do if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return + self.require_declaration("CHECK_NEW_{mtype.mclass.c_name}") self.add("CHECK_NEW_{mtype.mclass.c_name}({value});") end @@ -1185,10 +1233,11 @@ class SeparateCompilerVisitor if ntype.need_anchor then var type_struct = self.get_name("type_struct") - self.add_decl("struct type* {type_struct};") + 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) 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})];") else @@ -1208,6 +1257,7 @@ class SeparateCompilerVisitor end else if ntype isa MClassType then compiler.undead_types.add(mtype) + self.require_declaration("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 @@ -1256,7 +1306,8 @@ class SeparateCompilerVisitor self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/") else var mtype1 = value1.mtype.as(MClassType) - self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */") + self.require_declaration("class_{mtype1.c_name}") + self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name}); /* is_same_type_test */") end else self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */") @@ -1271,6 +1322,7 @@ class SeparateCompilerVisitor if value.mtype.ctype == "val*" then self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;" else + self.require_declaration("type_{value.mtype.c_name}") self.add "{res} = type_{value.mtype.c_name}.name;" end return res @@ -1291,7 +1343,8 @@ class SeparateCompilerVisitor self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/") else var mtype1 = value1.mtype.as(MClassType) - self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name});") + self.require_declaration("class_{mtype1.c_name}") + self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name});") self.add("if ({res}) \{") self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});") self.add("\}") @@ -1402,20 +1455,23 @@ class SeparateCompilerVisitor 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}") assert mtype isa MGenericType var compiler = self.compiler if mtype.need_anchor then link_unresolved_type(self.frame.mpropdef.mclassdef, mtype) var recv = self.frame.arguments.first var recv_type_info = self.type_info(recv) + self.require_declaration(mtype.const_color) if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then - return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype) + return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[HASH({recv_type_info}->resolution_table->mask, {mtype.const_color})])", mtype) else - return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype) + return self.new_expr("NEW_{mtype.mclass.c_name}({length}, {recv_type_info}->resolution_table->types[{mtype.const_color}])", mtype) end end compiler.undead_types.add(mtype) - return self.new_expr("NEW_{mtype.mclass.c_name}({length}, (struct type *) &type_{mtype.c_name})", mtype) + self.require_declaration("type_{mtype.c_name}") + return self.new_expr("NEW_{mtype.mclass.c_name}({length}, &type_{mtype.c_name})", mtype) end redef fun native_array_def(pname, ret_type, arguments) @@ -1454,6 +1510,30 @@ class SeparateCompilerVisitor end end +redef class MMethodDef + fun separate_runtime_function: AbstractRuntimeFunction + do + var res = self.separate_runtime_function_cache + if res == null then + res = new SeparateRuntimeFunction(self) + self.separate_runtime_function_cache = res + end + return res + end + private var separate_runtime_function_cache: nullable SeparateRuntimeFunction + + fun virtual_runtime_function: AbstractRuntimeFunction + do + var res = self.virtual_runtime_function_cache + if res == null then + res = new VirtualRuntimeFunction(self) + self.virtual_runtime_function_cache = res + end + return res + end + private var virtual_runtime_function_cache: nullable VirtualRuntimeFunction +end + # The C function associated to a methoddef separately compiled class SeparateRuntimeFunction super AbstractRuntimeFunction @@ -1488,7 +1568,7 @@ class SeparateRuntimeFunction end sig.append(self.c_name) sig.append("({selfvar.mtype.ctype} {selfvar}") - comment.append("(self: {selfvar}") + comment.append("({selfvar}: {selfvar.mtype}") arguments.add(selfvar) for i in [0..msignature.arity[ do var mtype = msignature.mparameters[i].mtype @@ -1505,7 +1585,7 @@ class SeparateRuntimeFunction if ret != null then comment.append(": {ret}") end - compiler.header.add_decl("{sig};") + compiler.provide_declaration(self.c_name, "{sig};") v.add_decl("/* method {self} for {comment} */") v.add_decl("{sig} \{") @@ -1564,7 +1644,7 @@ class VirtualRuntimeFunction end sig.append(self.c_name) sig.append("({selfvar.mtype.ctype} {selfvar}") - comment.append("(self: {selfvar}") + comment.append("({selfvar}: {selfvar.mtype}") arguments.add(selfvar) for i in [0..msignature.arity[ do var mtype = msignature.mparameters[i].mtype @@ -1581,7 +1661,7 @@ class VirtualRuntimeFunction if ret != null then comment.append(": {ret}") end - compiler.header.add_decl("{sig};") + compiler.provide_declaration(self.c_name, "{sig};") v.add_decl("/* method {self} for {comment} */") v.add_decl("{sig} \{") @@ -1590,10 +1670,11 @@ class VirtualRuntimeFunction end frame.returnlabel = v.get_name("RET_LABEL") - if recv != arguments.first.mtype then - #print "{self} {recv} {arguments.first}" + var subret = v.call(mmethoddef, recv, arguments) + if ret != null then + assert subret != null + v.assign(frame.returnvar.as(not null), subret) end - mmethoddef.compile_inside_to_c(v, arguments) v.add("{frame.returnlabel.as(not null)}:;") if ret != null then