X-Git-Url: http://nitlanguage.org diff --git a/src/separate_compiler.nit b/src/separate_compiler.nit index bc63f80..c70be37 100644 --- a/src/separate_compiler.nit +++ b/src/separate_compiler.nit @@ -58,8 +58,8 @@ redef class ModelBuilder # Class abstract representation v.add_decl("struct class \{ nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */") # Type abstract representation - v.add_decl("struct fts_table \{ int fts[1]; \}; /* fts list of a C type representation. */") - v.add_decl("struct type \{ int tid; int color; struct fts_table *fts_table; int type_table[1]; \}; /* general C type representing a Nit type. */") + v.add_decl("struct type \{ int id; int color; struct fts_table *fts_table; int type_table[1]; \}; /* general C type representing a Nit type. */") + v.add_decl("struct fts_table \{ struct type *fts[1]; \}; /* fts list of a C type representation. */") # 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. */") @@ -93,19 +93,29 @@ 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 type structures - for t in runtime_type_analysis.live_types do + # 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 + write_and_make(compiler) end end @@ -114,10 +124,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] @@ -131,25 +144,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) - - print "types colors: " - for k, v in type_colors do - print "{k}:{v}" - end - # classes coloration var class_coloring = new ClassColoring(mainmodule) self.class_colors = class_coloring.colorize(mmbuilder.model.mclasses) @@ -170,6 +164,146 @@ class SeparateCompiler self.ft_tables = ft_coloring.build_ft_tables 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 @@ -197,8 +331,8 @@ class SeparateCompiler # 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 tid;") - self.header.add_decl("int tcolor;") + self.header.add_decl("int id;") + self.header.add_decl("int color;") self.header.add_decl("const struct fts_table_{c_name} *fts_table;") self.header.add_decl("int type_table[{self.type_tables[mtype].length}];") self.header.add_decl("\};") @@ -206,7 +340,7 @@ class SeparateCompiler # extern const struct fst_table_X fst_table_X self.header.add_decl("extern const struct fts_table_{c_name} fts_table_{c_name};") self.header.add_decl("struct fts_table_{c_name} \{") - self.header.add_decl("int fts[{self.ft_tables[mtype.mclass].length}];") + self.header.add_decl("struct type *fts[{self.ft_tables[mtype.mclass].length}];") self.header.add_decl("\};") # const struct type_X @@ -230,24 +364,24 @@ class SeparateCompiler v.add_decl("\{") if mtype isa MGenericType then - print "-- for type {mtype}" for ft in self.ft_tables[mtype.mclass] do if ft == null then - print "-- ft:null" - v.add_decl("-1, /* empty */") + v.add_decl("NULL, /* empty */") else - print "-- ft:{ft}" var id = -1 - var ftype: MClassType + var ntype: MType if ft.mclass == mtype.mclass then - ftype = mtype.arguments[ft.rank].as(MClassType) + ntype = mtype.arguments[ft.rank] else - ftype = ft.anchor_to(self.mainmodule, mtype).as(MClassType) + 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 - id = self.typeids[ftype] + v.add_decl("(struct type*)&type_{ftype.c_name}, /* {ft} ({ftype}) */") + else + v.add_decl("NULL, /* empty ({ft} not a live type) */") end - v.add_decl("{id}, /* {ft} ({ftype}) */") end end end @@ -261,19 +395,18 @@ class SeparateCompiler # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally fun compile_class_to_c(mclass: MClass) do - var mtype = mclass.mclassdefs.first.bound_mtype - var c_name = mclass.mclass_type.c_name + var mtype = mclass.intro.bound_mtype + 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}];") @@ -319,41 +452,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};") @@ -406,8 +555,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 @@ -472,9 +621,12 @@ class VirtualRuntimeFunction var sig = new Buffer var comment = new Buffer - var ret = mmethoddef.msignature.return_mtype + + # 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 +635,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..mmethoddef.msignature.arity[ do - var mtype = mmethoddef.msignature.mparameters[i].mtype - if i == mmethoddef.msignature.vararg_rank then + 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 +717,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! @@ -585,7 +738,8 @@ class SeparateCompilerVisitor end var res: nullable RuntimeVariable - var ret = mmethod.intro.msignature.return_mtype + var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true) + var ret = msignature.return_mtype if mmethod.is_new then ret = arguments.first.mtype res = self.new_var(ret) @@ -598,22 +752,51 @@ class SeparateCompilerVisitor var s = new Buffer var ss = new Buffer - var first = true - for a in arguments do - if not first then - s.append(", ") - ss.append(", ") + + var recv = arguments.first + s.append("val*") + ss.append("{recv}") + for i in [0..msignature.arity[ do + var a = arguments[i+1] + var t = msignature.mparameters[i].mtype + s.append(", {t.ctype}") + a = self.autobox(a, t) + ss.append(", {a}") + end + + var maybenull = recv.mcasttype isa MNullableType + if maybenull then + self.add("if ({recv} == NULL) \{") + if mmethod.name == "==" then + assert res != null + var arg = arguments[1] + if arg.mcasttype isa MNullableType then + self.add("{res} = ({arg} == NULL);") + else if arg.mcasttype isa MNullType then + self.add("{res} = 1; /* is null */") + else + self.add("{res} = 0; /* {arg.inspect} cannot be null */") + end + else if mmethod.name == "!=" then + assert res != null + var arg = arguments[1] + if arg.mcasttype isa MNullableType then + self.add("{res} = ({arg} != NULL);") + else if arg.mcasttype isa MNullType then + self.add("{res} = 0; /* is null */") + else + self.add("{res} = 1; /* {arg.inspect} cannot be null */") + end else - first = false + self.add_abort("Reciever is null") end - s.append("{a.mtype.ctype}") - ss.append("{a}") + self.add("\} else \{") end 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};") @@ -621,6 +804,10 @@ class SeparateCompilerVisitor self.add("{call};") end + if maybenull then + self.add("\}") + end + return res end @@ -651,6 +838,14 @@ class SeparateCompilerVisitor return res end + redef fun isset_attribute(a, recv) + 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; /* {a} on {recv.inspect}*/") + return res + end + redef fun read_attribute(a, recv) do # FIXME: Here we inconditionally return boxed primitive attributes @@ -659,7 +854,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}") @@ -673,29 +868,52 @@ 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 + 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 + 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 MClassType then - var color = compiler.type_colors[mtype] - var id = compiler.typeids[mtype] - self.add("{res} = {value}->type->type_table[{color}] == {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] - #TODO - self.add("{res} = {value}->type->type_table[{ftcolor}] == self->type->fts_table->fts[{ftcolor}];") + 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 @@ -704,7 +922,24 @@ class SeparateCompilerVisitor redef fun is_same_type_test(value1, value2) do var res = self.new_var(bool_type) - # TODO + # 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 @@ -713,14 +948,105 @@ class SeparateCompilerVisitor 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);") return res end redef fun equal_test(value1, value2) do var res = self.new_var(bool_type) - # TODO + 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} = {value1} == {value2};") + else if value2.mtype.ctype != "val*" then + 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.add("if ({res}) \{") + self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});") + self.add("\}") + end + else + 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