import global_compiler # TODO better separation of concerns
-intrude import vft_computation
+intrude import coloring
redef class ToolContext
# --separate
var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
do
# Hijack the run_global_compiler to run the separate one if requested.
if self.toolcontext.opt_separate.value then
- build_vft(mainmodule)
run_separate_compiler(mainmodule, runtime_type_analysis)
else
super
v.add_decl("#include <gc/gc.h>")
v.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
v.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
+
+ # Class abstract representation
v.add_decl("struct class \{ nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
- v.add_decl("typedef struct \{ struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
+ # Type abstract representation
+ 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. */")
# 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
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 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
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] = 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]
+
+ private var method_colors: Map[MMethod, Int]
+ private var method_tables: Map[MClass, Array[nullable MMethodDef]]
+
+ private var attr_colors: Map[MAttribute, Int]
+ private var attr_tables: Map[MClass, Array[nullable MAttributeDef]]
+
+ private var ft_colors: Map[MParameterType, Int]
+ private var ft_tables: Map[MClass, Array[nullable MParameterType]]
+
+ init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
+ # classes coloration
+ var class_coloring = new ClassColoring(mainmodule)
+ self.class_colors = class_coloring.colorize(mmbuilder.model.mclasses)
+
+ # methods coloration
+ var method_coloring = new MethodColoring(class_coloring)
+ self.method_colors = method_coloring.colorize
+ self.method_tables = method_coloring.build_property_tables
+
+ # attributes coloration
+ var attribute_coloring = new AttributeColoring(class_coloring)
+ self.attr_colors = attribute_coloring.colorize
+ self.attr_tables = attribute_coloring.build_property_tables
+
+ # fts coloration
+ var ft_coloring = new FTColoring(class_coloring)
+ self.ft_colors = ft_coloring.colorize
+ 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
end
end
+ # Globaly compile the type structure of a live type
+ fun compile_type_to_c(mtype: MClassType)
+ do
+ var c_name = mtype.c_name
+ var v = new SeparateCompilerVisitor(self)
+ 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("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("\};")
+
+ # 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("struct type *fts[{self.ft_tables[mtype.mclass].length}];")
+ self.header.add_decl("\};")
+
+ # const struct type_X
+ v.add_decl("const struct type_{c_name} type_{c_name} = \{")
+ v.add_decl("{self.typeids[mtype]},")
+ v.add_decl("{self.type_colors[mtype]},")
+ v.add_decl("&fts_table_{c_name},")
+ v.add_decl("\{")
+ for stype in self.type_tables[mtype] do
+ if stype == null then
+ v.add_decl("-1, /* empty */")
+ else
+ v.add_decl("{self.typeids[stype]}, /* {stype} */")
+ end
+ end
+ v.add_decl("\},")
+ v.add_decl("\};")
+
+ # const struct fst_table_X fst_table_X
+ v.add_decl("const struct fts_table_{c_name} fts_table_{c_name} = \{")
+ v.add_decl("\{")
+
+ 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
+ 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
+
+ v.add_decl("\},")
+ v.add_decl("\};")
+ end
+
# Globally compile the table of the class mclass
# In a link-time optimisation compiler, tables are globally computed
# 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[{mclass.vft.length}];")
+ self.header.add_decl("nitmethod_t vft[{vft.length}];")
if mtype.ctype != "val*" then
# Is the Nit type is native then the struct is a box with two fields:
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("\{")
- for i in [0 .. mclass.vft.length[ do
- var mpropdef = mclass.vft[i]
+ for i in [0 .. vft.length[ do
+ var mpropdef = vft[i]
if mpropdef == null then
v.add_decl("NULL, /* empty */")
else
if mtype.ctype != "val*" then
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
- 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}));")
- 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 class_{c_name} *class;")
- v.add_decl("nitattribute_t attrs[{mclass.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}(void);")
+ self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
v.add_decl("/* allocate {mtype} */")
- v.add_decl("{mtype.ctype} NEW_{c_name}(void) \{")
- 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};")
for cd in mtype.collect_mclassdefs(self.mainmodule)
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
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
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)
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!
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)
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 = mmethod.color.as(not null)
+ 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};")
self.add("{call};")
end
+ if maybenull then
+ self.add("\}")
+ end
+
return res
end
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
var cret = self.object_type.as_nullable
var res = self.new_var(cret)
res.mcasttype = ret
- self.add("{res} = (val*) {recv}->attrs[{a.color.as(not null)}];")
+ 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}")
do
# FIXME: Here we inconditionally box primitive attributes
value = self.autobox(value, self.object_type.as_nullable)
- self.add("{recv}->attrs[{a.color.as(not null)}] = {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.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)
- # TODO
- add("printf(\"NOT YET IMPLEMENTED: type_test(%s,%s).\\n\", \"{value.inspect}\", \"{mtype}\"); exit(1);")
+ var buff = new Buffer
+
+ 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} = {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
end
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 equal_test(value1, value2)
do
var res = self.new_var(bool_type)
- # TODO
- add("printf(\"NOT YET IMPLEMENTED: equal_test(%s,%s).\\n\", \"{value1.inspect}\", \"{value2.inspect}\"); exit(1);")
+ 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