X-Git-Url: http://nitlanguage.org diff --git a/src/separate_compiler.nit b/src/separate_compiler.nit index 0d85e05..6346d60 100644 --- a/src/separate_compiler.nit +++ b/src/separate_compiler.nit @@ -63,13 +63,6 @@ redef class ModelBuilder # Instance abstract representation v.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */") - # Class names (for the class_name and output_class_name methods) - v.add_decl("extern const char const * class_names[];") - v.add("const char const * class_names[] = \{") - for t in runtime_type_analysis.live_types do - v.add("\"{t}\",") - end - v.add("\};") # The main function of the C @@ -93,23 +86,32 @@ redef class ModelBuilder end v.add("\}") - + # compile class structures for m in mainmodule.in_importation.greaters do - compiler.compile_module_to_c(m) for mclass in m.intro_mclasses do compiler.compile_class_to_c(mclass) end end - # compile live & cast type structures - var mtypes = new HashSet[MClassType] - mtypes.add_all(runtime_type_analysis.live_types) - mtypes.add_all(runtime_type_analysis.live_cast_types) + # compile methods + for m in mainmodule.in_importation.greaters do + compiler.compile_module_to_c(m) + end + # compile live & cast type structures + var mtypes = compiler.do_global_type_coloring for t in mtypes do compiler.compile_type_to_c(t) end + # compile live generic types selection structures + for mclass in model.mclasses do + compiler.compile_live_gentype_to_c(mclass) + end + + # for the class_name and output_class_name methods + compiler.compile_class_names + write_and_make(compiler) end end @@ -118,10 +120,13 @@ end class SeparateCompiler super GlobalCompiler # TODO better separation of concerns + private var undead_types: Set[MClassType] = new HashSet[MClassType] protected var typeids: HashMap[MClassType, Int] = new HashMap[MClassType, Int] - private var type_colors: Map[MClassType, Int] - private var type_tables: Map[MClassType, Array[nullable MClassType]] + private var type_colors: Map[MClassType, Int] = typeids + private var type_tables: nullable Map[MClassType, Array[nullable MClassType]] = null + private var livetypes_tables: nullable Map[MClass, Array[nullable Object]] + private var livetypes_tables_sizes: nullable Map[MClass, Array[Int]] private var class_colors: Map[MClass, Int] @@ -135,20 +140,6 @@ class SeparateCompiler private var ft_tables: Map[MClass, Array[nullable MParameterType]] init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do - - # types coloration - var mtypes = new HashSet[MClassType] - mtypes.add_all(runtime_type_analysis.live_types) - mtypes.add_all(runtime_type_analysis.live_cast_types) - - for mtype in mtypes do - self.typeids[mtype] = self.typeids.length - end - - var type_coloring = new TypeColoring(mainmodule, runtime_type_analysis) - self.type_colors = type_coloring.colorize(mtypes) - self.type_tables = type_coloring.build_type_tables(mtypes, type_colors) - # classes coloration var class_coloring = new ClassColoring(mainmodule) self.class_colors = class_coloring.colorize(mmbuilder.model.mclasses) @@ -169,6 +160,170 @@ class SeparateCompiler self.ft_tables = ft_coloring.build_ft_tables end + private fun compile_class_names do + + # Build type names table + var type_array = new Array[nullable MClassType] + for t, i in typeids do + if i >= type_array.length then + type_array[i] = null + end + type_array[i] = t + end + + var v = new SeparateCompilerVisitor(self) + self.header.add_decl("extern const char const * class_names[];") + v.add("const char const * class_names[] = \{") + for t in type_array do + if t == null then + v.add("NULL,") + else + v.add("\"{t}\",") + end + end + v.add("\};") + end + + # colorize live types of the program + private fun do_global_type_coloring: Set[MClassType] do + var mtypes = new HashSet[MClassType] + #print "undead types:" + #for t in self.undead_types do + # print t + #end + #print "live types:" + #for t in runtime_type_analysis.live_types do + # print t + #end + #print "cast types:" + #for t in runtime_type_analysis.live_cast_types do + # print t + #end + #print "--" + 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) + + # add formal types arguments to mtypes + for mtype in mtypes do + if mtype isa MGenericType then + #TODO do it recursive + for ft in mtype.arguments do + if ft isa MNullableType then ft = ft.mtype + mtypes.add(ft.as(MClassType)) + end + end + end + + # set type unique id + for mtype in mtypes do + self.typeids[mtype] = self.typeids.length + end + + # build livetypes tables + self.livetypes_tables = new HashMap[MClass, Array[nullable Object]] + self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]] + for mtype in mtypes do + if mtype isa MGenericType then + var table: Array[nullable Object] + var sizes: Array[Int] + if livetypes_tables.has_key(mtype.mclass) then + table = livetypes_tables[mtype.mclass] + else + table = new Array[nullable Object] + self.livetypes_tables[mtype.mclass] = table + end + if livetypes_tables_sizes.has_key(mtype.mclass) then + sizes = livetypes_tables_sizes[mtype.mclass] + else + sizes = new Array[Int] + self.livetypes_tables_sizes[mtype.mclass] = sizes + end + build_livetype_table(mtype, 0, table, sizes) + end + end + + # colorize + var type_coloring = new TypeColoring(self.mainmodule, self.runtime_type_analysis) + self.type_colors = type_coloring.colorize(mtypes) + self.type_tables = type_coloring.build_type_tables(mtypes, type_colors) + + return mtypes + end + + # build live gentype table recursively + private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do + var ft = mtype.arguments[current_rank] + if ft isa MNullableType then ft = ft.mtype + var id = self.typeids[ft.as(MClassType)] + + if current_rank >= sizes.length then + sizes[current_rank] = id + 1 + else if id >= sizes[current_rank] then + sizes[current_rank] = id + 1 + end + + if id > table.length then + for i in [table.length .. id[ do table[i] = null + end + + if current_rank == mtype.arguments.length - 1 then + table[id] = mtype + else + var ft_table = new Array[nullable Object] + table[id] = ft_table + build_livetype_table(mtype, current_rank + 1, ft_table, sizes) + end + end + + private fun add_to_livetypes_table(table: Array[nullable Object], ft: MClassType) do + var id = self.typeids[ft] + for i in [table.length .. id[ do + table[i] = null + end + table[id] = ft + end + + private fun compile_livetype_table(table: Array[nullable Object], buffer: Buffer, depth: Int, max: Int) do + for obj in table do + if obj == null then + if depth == max then + buffer.append("NULL,\n") + else + buffer.append("\{\},\n") + end + else if obj isa MClassType then + buffer.append("(struct type*) &type_{obj.c_name}, /* {obj} */\n") + else if obj isa Array[nullable Object] then + buffer.append("\{\n") + compile_livetype_table(obj, buffer, depth + 1, max) + buffer.append("\},\n") + end + end + end + + # declare live generic types tables selection + private fun compile_live_gentype_to_c(mclass: MClass) do + if mclass.arity > 0 then + if self.livetypes_tables.has_key(mclass) then + var table = self.livetypes_tables[mclass] + var sign = self.livetypes_tables_sizes[mclass] + var table_buffer = new Buffer.from("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}] = \{\n") + compile_livetype_table(table, table_buffer, 1, mclass.arity) + table_buffer.append("\};") + + var v = new SeparateCompilerVisitor(self) + self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];") + v.add_decl(table_buffer.to_s) + else + var sign = new Array[Int].filled_with(0, mclass.arity) + var v = new SeparateCompilerVisitor(self) + self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];") + v.add_decl("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];") + end + end + end + # Separately compile all the method definitions of the module fun compile_module_to_c(mmodule: MModule) do @@ -178,7 +333,7 @@ class SeparateCompiler #print "compile {pd} @ {cd} @ {mmodule}" var r = new SeparateRuntimeFunction(pd) r.compile_to_c(self) - if cd.bound_mtype.ctype != "val*" then + if true or cd.bound_mtype.ctype != "val*" then var r2 = new VirtualRuntimeFunction(pd) r2.compile_to_c(self) end @@ -228,25 +383,23 @@ class SeparateCompiler v.add_decl("const struct fts_table_{c_name} fts_table_{c_name} = \{") v.add_decl("\{") - if mtype isa MGenericType then - for ft in self.ft_tables[mtype.mclass] do - if ft == null then - v.add_decl("NULL, /* empty */") + for ft in self.ft_tables[mtype.mclass] do + if ft == null then + v.add_decl("NULL, /* empty */") + else + var id = -1 + var ntype: MType + if ft.mclass == mtype.mclass then + ntype = mtype.arguments[ft.rank] else - var id = -1 - var ftype: MClassType - if ft.mclass == mtype.mclass then - var ntype = mtype.arguments[ft.rank] - if ntype isa MNullableType then ntype = ntype.mtype - ftype = ntype.as(MClassType) - else - ftype = ft.anchor_to(self.mainmodule, mtype).as(MClassType) - end - if self.typeids.has_key(ftype) then - v.add_decl("(struct type*)&type_{ftype.c_name}, /* {ft} ({ftype}) */") - else - v.add_decl("NULL, /* empty ({ft} not a live type) */") - end + ntype = ft.anchor_to(self.mainmodule, mtype) + end + if ntype isa MNullableType then ntype = ntype.mtype + var ftype = ntype.as(MClassType) + if self.typeids.has_key(ftype) then + v.add_decl("(struct type*)&type_{ftype.c_name}, /* {ft} ({ftype}) */") + else + v.add_decl("NULL, /* empty ({ft} not a live type) */") end end end @@ -261,18 +414,17 @@ class SeparateCompiler fun compile_class_to_c(mclass: MClass) do var mtype = mclass.intro.bound_mtype - var c_name = mclass.mclass_type.c_name + var c_name = mclass.c_name var vft = self.method_tables[mclass] var attrs = self.attr_tables[mclass] - var v = new SeparateCompilerVisitor(self) - v.add_decl("/* runtime class {mtype} */") + v.add_decl("/* runtime class {c_name} */") var idnum = classids.length var idname = "ID_" + c_name self.classids[mtype] = idname - self.header.add_decl("#define {idname} {idnum} /* {mtype} */") + #self.header.add_decl("#define {idname} {idnum} /* {c_name} */") self.header.add_decl("struct class_{c_name} \{") self.header.add_decl("nitmethod_t vft[{vft.length}];") @@ -305,7 +457,7 @@ class SeparateCompiler if mpropdef == null then v.add_decl("NULL, /* empty */") else - if mpropdef.mclassdef.bound_mtype.ctype != "val*" then + 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} */") else v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */") @@ -318,41 +470,57 @@ class SeparateCompiler if mtype.ctype != "val*" then #Build instance struct self.header.add_decl("struct instance_{c_name} \{") - self.header.add_decl("const struct type_{c_name} *type;") - self.header.add_decl("const struct class_{c_name} *class;") + 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("\};") - self.header.add_decl("val* BOX_{c_name}({mtype.ctype});") + self.header.add_decl("val* BOX_{c_name}({mtype.ctype}, struct type*);") 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} value, struct type* type) \{") v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));") - if self.typeids.has_key(mtype) then - v.add("res->type = &type_{c_name};") - else - v.add("res->type = NULL;") - end - v.add("res->class = &class_{c_name};") + v.add("res->type = type;") + v.add("res->class = (struct 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 - v.add_decl("struct instance_{c_name} \{") - v.add_decl("const struct type_{c_name} *type;") - v.add_decl("const struct class_{c_name} *class;") - v.add_decl("nitattribute_t attrs[{attrs.length}];") - v.add_decl("\};") + #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 + # 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("{mtype.ctype} NEW_{c_name}(struct type *type);") + self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});") v.add_decl("/* allocate {mtype} */") - v.add_decl("{mtype.ctype} NEW_{c_name}(struct type *type) \{") - var res = v.new_var(mtype) + v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{") + var res = v.new_named_var(mtype, "self") res.is_exact = true - v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);") + if is_native_array then + 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} = calloc(sizeof(struct instance_{c_name}), 1);") v.add("{res}->type = type;") v.add("{res}->class = (struct class*) &class_{c_name};") @@ -405,8 +573,8 @@ class SeparateRuntimeFunction sig.append("void ") end sig.append(self.c_name) - sig.append("({selfvar.mtype.ctype} self") - comment.append("(self: {recv}") + sig.append("({selfvar.mtype.ctype} {selfvar}") + comment.append("(self: {selfvar}") arguments.add(selfvar) for i in [0..mmethoddef.msignature.arity[ do var mtype = mmethoddef.msignature.mparameters[i].mtype @@ -471,10 +639,12 @@ class VirtualRuntimeFunction var sig = new Buffer var comment = new Buffer - var msignature = mmethoddef.mproperty.intro.msignature + + # Because the function is virtual, the signature must match the one of the original class + var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef + var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true) var ret = msignature.return_mtype if ret != null then - ret = v.resolve_for(ret, selfvar) sig.append("{ret.ctype} ") else if mmethoddef.mproperty.is_new then ret = recv @@ -483,15 +653,14 @@ class VirtualRuntimeFunction sig.append("void ") end sig.append(self.c_name) - sig.append("({selfvar.mtype.ctype} self") - comment.append("(self: {recv}") + sig.append("({selfvar.mtype.ctype} {selfvar}") + comment.append("(self: {selfvar}") arguments.add(selfvar) for i in [0..msignature.arity[ do var mtype = msignature.mparameters[i].mtype if i == msignature.vararg_rank then mtype = v.get_class("Array").get_mtype([mtype]) end - mtype = v.resolve_for(mtype, selfvar) comment.append(", {mtype}") sig.append(", {mtype.ctype} p{i}") var argvar = new RuntimeVariable("p{i}", mtype, mtype) @@ -566,7 +735,9 @@ class SeparateCompilerVisitor self.add("printf(\"Dead code executed!\\n\"); exit(1);") return res end - self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */") + var totype = value.mtype + if totype isa MNullableType then totype = totype.mtype + self.add("{res} = BOX_{valtype.c_name}({value}, (struct type*) &type_{totype.c_name}); /* autobox from {value.mtype} to {mtype} */") return res else # Bad things will appen! @@ -643,7 +814,7 @@ class SeparateCompilerVisitor var color = self.compiler.as(SeparateCompiler).method_colors[mmethod] var r if ret == null then r = "void" else r = ret.ctype - var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss})" + var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/" if res != null then self.add("{res} = {call};") @@ -689,7 +860,7 @@ class SeparateCompilerVisitor do # FIXME: Here we inconditionally return boxed primitive attributes var res = self.new_var(bool_type) - self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL;") + self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL; /* {a} on {recv.inspect}*/") return res end @@ -701,7 +872,7 @@ class SeparateCompilerVisitor var cret = self.object_type.as_nullable var res = self.new_var(cret) res.mcasttype = ret - self.add("{res} = (val*) {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}];") + self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */") if not ret isa MNullableType then self.add("if ({res} == NULL) \{") self.add_abort("Uninitialized attribute {a.name}") @@ -715,27 +886,63 @@ class SeparateCompilerVisitor do # FIXME: Here we inconditionally box primitive attributes value = self.autobox(value, self.object_type.as_nullable) - self.add("{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] = {value};") + self.add("{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] = {value}; /* {a} on {recv.inspect} */") end redef fun init_instance(mtype) do - mtype = self.anchor(mtype).as(MClassType) - var res = self.new_expr("NEW_{mtype.mclass.mclass_type.c_name}((struct type*) &type_{mtype.c_name})", mtype) - return res + var compiler = self.compiler.as(SeparateCompiler) + if mtype isa MGenericType and mtype.need_anchor then + var buff = new Buffer + var rank = 0 + for ft in mtype.arguments do + if ft isa MParameterType then + var ftcolor = compiler.ft_colors[ft] + buff.append("[self->type->fts_table->fts[{ftcolor}]->id]") + else if ft isa MGenericType and ft.need_anchor then + var ft_decl = mtype.mclass.mclass_type.arguments[rank] + var ftcolor = compiler.ft_colors[ft_decl.as(MParameterType)] + buff.append("[self->type->fts_table->fts[{ftcolor}]->id]") + else + var typecolor = compiler.type_colors[ft.as(MClassType)] + buff.append("[{typecolor}]") + end + rank += 1 + end + mtype = self.anchor(mtype).as(MClassType) + return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype) + end + compiler.undead_types.add(mtype) + return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype) end redef fun type_test(value, mtype) do var compiler = self.compiler.as(SeparateCompiler) var res = self.new_var(bool_type) + var buff = new Buffer - if mtype isa MNullableType then mtype = mtype.mtype - if mtype isa MClassType then - self.add("{res} = {value}->type->type_table[type_{mtype.c_name}.color] == type_{mtype.c_name}.id;") + var s: String + if mtype isa MNullableType then + mtype = mtype.mtype + s = "{value} == NULL ||" + else + s = "{value} != NULL &&" + end + if mtype isa MGenericType and mtype.need_anchor then + for ft in mtype.mclass.mclass_type.arguments do + var ftcolor = compiler.ft_colors[ft.as(MParameterType)] + buff.append("[self->type->fts_table->fts[{ftcolor}]->id]") + end + self.add("{res} = {s} {value}->type->type_table[livetypes_{mtype.mclass.c_name}{buff.to_s}->color] == livetypes_{mtype.mclass.c_name}{buff.to_s}->id;") + else if mtype isa MClassType then + compiler.undead_types.add(mtype) + self.add("{res} = {s} {value}->type->type_table[type_{mtype.c_name}.color] == type_{mtype.c_name}.id;") else if mtype isa MParameterType then var ftcolor = compiler.ft_colors[mtype] - self.add("{res} = {value}->type->type_table[self->type->fts_table->fts[{ftcolor}]->color] == self->type->fts_table->fts[{ftcolor}]->id;") + self.add("{res} = {s} {value}->type->type_table[self->type->fts_table->fts[{ftcolor}]->color] == self->type->fts_table->fts[{ftcolor}]->id;") + else + add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); exit(1);") end return res @@ -744,17 +951,31 @@ class SeparateCompilerVisitor redef fun is_same_type_test(value1, value2) do var res = self.new_var(bool_type) - # TODO - add("printf(\"NOT YET IMPLEMENTED: is_same_type(%s,%s).\\n\", \"{value1.inspect}\", \"{value2.inspect}\"); exit(1);") + # Swap values to be symetric + if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then + var tmp = value1 + value1 = value2 + value2 = tmp + end + if value1.mtype.ctype != "val*" then + if value2.mtype.ctype == value1.mtype.ctype then + self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */") + else if value2.mtype.ctype != "val*" then + 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 */") + end + else + self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */") + end return res end redef fun class_name_string(value1) do var res = self.get_name("var_class_name") - self.add_decl("const char* {res};") - # TODO - add("printf(\"NOT YET IMPLEMENTED: class_name_string(%s).\\n\", \"{value1.inspect}\"); exit(1);") + self.add_decl("const char* {res} = class_names[self->type->id];") return res end @@ -779,9 +1000,80 @@ class SeparateCompilerVisitor self.add("\}") end else - self.add("{res} = {value1} == {value2};") + var s = new Array[String] + # This is just ugly on so many level. this works but must be rewriten + for t in self.compiler.live_primitive_types do + if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue + if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue + s.add "({value1}->class == (struct class*)&class_{t.c_name} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)" + end + if s.is_empty then + self.add("{res} = {value1} == {value2};") + else + self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class && ({s.join(" || ")}));") + end end return res end + + redef fun array_instance(array, elttype) + do + var compiler = self.compiler.as(SeparateCompiler) + var nclass = self.get_class("NativeArray") + elttype = self.anchor(elttype) + var arraytype = self.get_class("Array").get_mtype([elttype]) + var res = self.init_instance(arraytype) + self.add("\{ /* {res} = array_instance Array[{elttype}] */") + var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype])) + nat.is_exact = true + compiler.undead_types.add(nat.mtype.as(MClassType)) + self.add("{nat} = NEW_{nclass.c_name}({array.length}, (struct type *) &type_{nat.mtype.c_name});") + for i in [0..array.length[ do + var r = self.autobox(array[i], self.object_type) + self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};") + end + var length = self.int_instance(array.length) + self.send(self.get_property("with_native", arraytype), [res, nat, length]) + self.check_init_instance(res) + self.add("\}") + return res + end + + redef fun native_array_def(pname, ret_type, arguments) + do + var elttype = arguments.first.mtype + var nclass = self.get_class("NativeArray") + 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 + else if pname == "[]=" then + self.add("{recv}[{arguments[1]}]={arguments[2]};") + return + else if pname == "copy_to" then + var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values" + self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));") + return + end + end + + redef fun calloc_array(ret_type, arguments) + do + var ret = ret_type.as(MClassType) + var compiler = self.compiler.as(SeparateCompiler) + compiler.undead_types.add(ret) + self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]}, (struct type*) &type_{ret_type.c_name})", ret_type)) + end end +redef class MClass + # Return the name of the C structure associated to a Nit class + fun c_name: String do + var res = self.c_name_cache + if res != null then return res + res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}" + self.c_name_cache = res + return res + end + private var c_name_cache: nullable String +end