model: rewrite of MType::is_subtype
[nit.git] / src / separate_erasure_compiler.nit
index d2522a5..2e85a75 100644 (file)
@@ -31,15 +31,6 @@ redef class ToolContext
 end
 
 redef class ModelBuilder
-       redef fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
-       do
-               if self.toolcontext.opt_erasure.value then
-                       run_separate_erasure_compiler(mainmodule, runtime_type_analysis)
-               else
-                       super
-               end
-       end
-
        fun run_separate_erasure_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
        do
                var time0 = get_time
@@ -54,7 +45,7 @@ redef class ModelBuilder
                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. */")
-               v.add_decl("struct class \{ int id; int color; struct type_table *type_table; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
+               v.add_decl("struct class \{ int id; int box_kind; int color; struct type_table *type_table; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
                v.add_decl("struct type_table \{ int size; int table[1]; \}; /* colorized type table. */")
                v.add_decl("typedef struct \{ struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
                v.add_decl("extern const char const * class_names[];")
@@ -112,6 +103,7 @@ class SeparateErasureCompiler
 
                # for the class_name and output_class_name methods
                self.compile_class_names
+               self.compile_box_kinds
        end
 
        redef fun compile_class_names do
@@ -155,32 +147,16 @@ class SeparateErasureCompiler
                self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
                self.header.add_decl("struct class_{c_name} \{")
                self.header.add_decl("int id;")
+               self.header.add_decl("int box_kind;")
                self.header.add_decl("int color;")
                self.header.add_decl("struct type_table *type_table;")
                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:
-                       # * the `vft` to be polymorph
-                       # * the `value` that contains the native value.
-                       self.header.add_decl("{mtype.ctype} value;")
-               end
-
-               # Collect all attributes and associate them a field in the structure.
-               # Note: we do not try to optimize the order and helps CC to optimize the client code.
-               for cd in mtype.collect_mclassdefs(self.mainmodule) do
-                       for p in cd.intro_mproperties do
-                               if not p isa MAttribute then continue
-                               var t = p.intro.static_mtype.as(not null)
-                               t = t.anchor_to(self.mainmodule, mtype)
-                               self.header.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
-                       end
-               end
                self.header.add_decl("\};")
 
                # Build class vft
                v.add_decl("const struct class_{c_name} class_{c_name} = \{")
                v.add_decl("{self.class_ids[mclass]},")
+               v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
                v.add_decl("{self.class_colors[mclass]},")
                v.add_decl("(struct type_table*) &type_table_{c_name},")
                v.add_decl("\{")
@@ -211,7 +187,7 @@ class SeparateErasureCompiler
                v.add_decl("\{")
                for msuper in class_table do
                        if msuper == null then
-                               v.add_decl("0, /* empty */")
+                               v.add_decl("-1, /* empty */")
                        else
                                v.add_decl("{self.class_ids[msuper]}, /* {msuper} */")
                        end
@@ -271,17 +247,11 @@ class SeparateErasureCompiler
                end
                v.add("{res}->class = (struct class*) &class_{c_name};")
 
-               for cd in mtype.collect_mclassdefs(self.mainmodule)
-               do
-                       var n = self.modelbuilder.mclassdef2nclassdef[cd]
-                       for npropdef in n.n_propdefs do
-                               if npropdef isa AAttrPropdef then
-                                       npropdef.init_expr(v, res)
-                               end
-                       end
-               end
+               self.generate_init_attr(v, res, mtype)
                v.add("return {res};")
                v.add("\}")
+
+               generate_check_init_instance(mtype)
        end
 
        redef fun new_visitor do return new SeparateErasureCompilerVisitor(self)
@@ -290,35 +260,6 @@ end
 class SeparateErasureCompilerVisitor
        super SeparateCompilerVisitor
 
-       # Box or unbox a value to another type iff a C type conversion is needed
-       # ENSURE: result.mtype.ctype == mtype.ctype
-       redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
-       do
-               if value.mtype.ctype == mtype.ctype then
-                       return value
-               else if value.mtype.ctype == "val*" then
-                       return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
-               else if mtype.ctype == "val*" then
-                       var valtype = value.mtype.as(MClassType)
-                       var res = self.new_var(mtype)
-                       if not compiler.runtime_type_analysis.live_types.has(valtype) then
-                               self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
-                               self.add("printf(\"Dead code executed!\\n\"); exit(1);")
-                               return res
-                       end
-                       var totype = value.mtype
-                       if totype isa MNullableType then totype = totype.mtype
-                       self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
-                       return res
-               else
-                       # Bad things will appen!
-                       var res = self.new_var(mtype)
-                       self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
-                       self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
-                       return res
-               end
-       end
-
        redef fun init_instance(mtype)
        do
                return self.new_expr("NEW_{mtype.mclass.c_name}()", mtype)
@@ -327,7 +268,6 @@ class SeparateErasureCompilerVisitor
        redef fun type_test(value, mtype)
        do
                var res = self.new_var(bool_type)
-               var boxed = self.autobox(value, self.object_type)
 
                var cltype = self.get_name("cltype")
                self.add_decl("int {cltype};")
@@ -355,6 +295,20 @@ class SeparateErasureCompilerVisitor
                                maybe_null = true
                        end
                end
+
+               if value.mcasttype.is_subtype(self.frame.mpropdef.mclassdef.mmodule, self.frame.mpropdef.mclassdef.bound_mtype, mtype) then
+                       self.add("{res} = 1; /* easy {value.inspect} isa {mtype}*/")
+                       return res
+               end
+
+               var type_table
+               if value.mtype.ctype == "val*" then
+                       type_table = "{value}->class->type_table"
+               else
+                       var mclass = value.mtype.as(MClassType).mclass
+                       type_table = "type_table_{mclass.c_name}"
+               end
+
                if mtype isa MClassType then
                        self.add("{cltype} = class_{mtype.mclass.c_name}.color;")
                        self.add("{idtype} = class_{mtype.mclass.c_name}.id;")
@@ -365,24 +319,25 @@ class SeparateErasureCompilerVisitor
 
                var s: String
                if maybe_null then
-                       s = "{boxed} == NULL ||"
+                       s = "{value} == NULL ||"
                else
-                       s = "{boxed} != NULL &&"
+                       s = "{value} != NULL &&"
                end
                # check color is in table
-               self.add("if({boxed} != NULL && {cltype} >= {boxed}->class->type_table->size) \{")
+               self.add("if({value} != NULL && {cltype} >= {type_table}->size) \{")
                self.add("{res} = 0;")
                self.add("\} else \{")
-               self.add("{res} = {s} {boxed}->class->type_table->table[{cltype}] == {idtype};")
+               self.add("{res} = {s} {type_table}->table[{cltype}] == {idtype};")
                self.add("\}")
 
                return res
        end
 
-       redef fun class_name_string(value1)
+       redef fun class_name_string(value)
        do
                var res = self.get_name("var_class_name")
-               self.add_decl("const char* {res} = class_names[self->class->id];")
+               self.add_decl("const char *{res};")
+               self.add("{res} = class_names[{value}->class->id];")
                return res
        end
 
@@ -402,7 +357,7 @@ class SeparateErasureCompilerVisitor
                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.check_init_instance(res, arraytype)
                self.add("\}")
                return res
        end