loader: `MModule::load` cause build_module_importation
[nit.git] / src / compiler / separate_compiler.nit
index c73bf58..d3390af 100644 (file)
@@ -252,7 +252,8 @@ class SeparateCompiler
        do
                # Collect all bas box class
                # FIXME: this is not completely fine with a separate compilation scheme
        do
                # Collect all bas box class
                # FIXME: this is not completely fine with a separate compilation scheme
-               for classname in ["Int", "Bool", "Byte", "Char", "Float", "NativeString", "Pointer"] do
+               for classname in ["Int", "Bool", "Byte", "Char", "Float", "NativeString",
+                                "Pointer", "Int8", "Int16", "UInt16", "Int32", "UInt32"] do
                        var classes = self.mainmodule.model.get_mclasses_by_name(classname)
                        if classes == null then continue
                        assert classes.length == 1 else print classes.join(", ")
                        var classes = self.mainmodule.model.get_mclasses_by_name(classname)
                        if classes == null then continue
                        assert classes.length == 1 else print classes.join(", ")
@@ -625,7 +626,7 @@ class SeparateCompiler
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
-                               if pd.msignature == null then continue # Skip broken method
+                               if pd.mproperty.is_broken or pd.is_broken or pd.msignature == null then continue # Skip broken method
                                var rta = runtime_type_analysis
                                if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
                                #print "compile {pd} @ {cd} @ {mmodule}"
                                var rta = runtime_type_analysis
                                if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
                                #print "compile {pd} @ {cd} @ {mmodule}"
@@ -813,6 +814,8 @@ class SeparateCompiler
        # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
        fun compile_class_to_c(mclass: MClass)
        do
        # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
        fun compile_class_to_c(mclass: MClass)
        do
+               if mclass.is_broken then return
+
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
@@ -842,6 +845,9 @@ class SeparateCompiler
                                        if rta != null and not rta.live_methoddefs.has(mpropdef) then
                                                v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
                                                continue
                                        if rta != null and not rta.live_methoddefs.has(mpropdef) then
                                                v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
                                                continue
+                                       else if mpropdef.is_broken or mpropdef.msignature == null or mpropdef.mproperty.is_broken then
+                                               v.add_decl("NULL, /* DEAD (BROKEN) {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
+                                               continue
                                        end
                                        var rf = mpropdef.virtual_runtime_function
                                        v.require_declaration(rf.c_name)
                                        end
                                        var rf = mpropdef.virtual_runtime_function
                                        v.require_declaration(rf.c_name)
@@ -997,10 +1003,13 @@ class SeparateCompiler
                        # use some Huffman coding.
                        if t.name == "Int" then
                                class_info[1] = t
                        # use some Huffman coding.
                        if t.name == "Int" then
                                class_info[1] = t
+                               t.mclass_type.tag_value = 1
                        else if t.name == "Char" then
                                class_info[2] = t
                        else if t.name == "Char" then
                                class_info[2] = t
+                               t.mclass_type.tag_value = 2
                        else if t.name == "Bool" then
                                class_info[3] = t
                        else if t.name == "Bool" then
                                class_info[3] = t
+                               t.mclass_type.tag_value = 3
                        else
                                continue
                        end
                        else
                                continue
                        end
@@ -1857,7 +1866,7 @@ class SeparateCompilerVisitor
                        else
                                var mtype1 = value1.mtype.as(MClassType)
                                self.require_declaration("class_{mtype1.c_name}")
                        else
                                var mtype1 = value1.mtype.as(MClassType)
                                self.require_declaration("class_{mtype1.c_name}")
-                               self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name}); /* is_same_type_test */")
+                               self.add("{res} = ({value2} != NULL) && ({class_info(value2)} == &class_{mtype1.c_name}); /* is_same_type_test */")
                        end
                else
                        self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {class_info(value1)} == {class_info(value2)}); /* is_same_type_test */")
                        end
                else
                        self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {class_info(value1)} == {class_info(value2)}); /* is_same_type_test */")
@@ -1890,20 +1899,58 @@ class SeparateCompilerVisitor
                        value2 = tmp
                end
                if value1.mtype.is_c_primitive then
                        value2 = tmp
                end
                if value1.mtype.is_c_primitive then
-                       if value2.mtype == value1.mtype then
+                       var t1 = value1.mtype
+                       assert t1 == value1.mcasttype
+
+                       # Fast case: same C type.
+                       if value2.mtype == t1 then
+                               # Same exact C primitive representation.
                                self.add("{res} = {value1} == {value2};")
                                self.add("{res} = {value1} == {value2};")
-                       else if value2.mtype.is_c_primitive then
-                               self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
-                       else if value1.mtype.is_tagged then
-                               self.add("{res} = ({value2} != NULL) && ({self.autobox(value2, value1.mtype)} == {value1});")
+                               return res
+                       end
+
+                       # Complex case: value2 has a different representation
+                       # Thus, it should be checked if `value2` is type-compatible with `value1`
+                       # This compatibility is done statically if possible and dynamically else
+
+                       # Conjunction (ands) of dynamic tests according to the static knowledge
+                       var tests = new Array[String]
+
+                       var t2 = value2.mcasttype
+                       if t2 isa MNullableType then
+                               # The destination type cannot be null
+                               tests.add("({value2} != NULL)")
+                               t2 = t2.mtype
+                       else if t2 isa MNullType then
+                               # `value2` is known to be null, thus incompatible with a primitive
+                               self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
+                               return res
+                       end
+
+                       if t2 == t1 then
+                               # Same type but different representation.
+                       else if t2.is_c_primitive then
+                               # Type of `value2` is a different primitive type, thus incompatible
+                               self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
+                               return res
+                       else if t1.is_tagged then
+                               # To be equal, `value2` should also be correctly tagged
+                               tests.add("({extract_tag(value2)} == {t1.tag_value})")
                        else
                        else
-                               var mtype1 = value1.mtype.as(MClassType)
-                               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("\}")
+                               # To be equal, `value2` should also be boxed with the same class
+                               self.require_declaration("class_{t1.c_name}")
+                               tests.add "({class_info(value2)} == &class_{t1.c_name})"
+                       end
+
+                       # Compare the unboxed `value2` with `value1`
+                       if tests.not_empty then
+                               self.add "if ({tests.join(" && ")}) \{"
                        end
                        end
+                       self.add "{res} = {self.autobox(value2, t1)} == {value1};"
+                       if tests.not_empty then
+                               self.add "\} else {res} = 0;"
+                       end
+
                        return res
                end
                var maybe_null = true
                        return res
                end
                var maybe_null = true
@@ -2217,12 +2264,9 @@ class SeparateRuntimeFunction
                var mmethoddef = self.mmethoddef
 
                var sig = "{c_ret} {c_name}{c_sig}"
                var mmethoddef = self.mmethoddef
 
                var sig = "{c_ret} {c_name}{c_sig}"
-               compiler.provide_declaration(self.c_name, "{sig} __attribute__((weak));")
+               compiler.provide_declaration(self.c_name, "{sig};")
 
                var rta = compiler.as(SeparateCompiler).runtime_type_analysis
 
                var rta = compiler.as(SeparateCompiler).runtime_type_analysis
-               if rta != null and not rta.live_mmodules.has(mmethoddef.mclassdef.mmodule) then
-                       return
-               end
 
                var recv = self.mmethoddef.mclassdef.bound_mtype
                var v = compiler.new_visitor
 
                var recv = self.mmethoddef.mclassdef.bound_mtype
                var v = compiler.new_visitor
@@ -2264,6 +2308,8 @@ class SeparateRuntimeFunction
                                assert subret != null
                                v.assign(frame.returnvar.as(not null), subret)
                        end
                                assert subret != null
                                v.assign(frame.returnvar.as(not null), subret)
                        end
+               else if rta != null and not rta.live_mmodules.has(mmethoddef.mclassdef.mmodule) then
+                       v.add_abort("FATAL: Dead method executed.")
                else
                        mmethoddef.compile_inside_to_c(v, arguments)
                end
                else
                        mmethoddef.compile_inside_to_c(v, arguments)
                end
@@ -2327,6 +2373,12 @@ redef class MType
        # Are values of `self` tagged?
        # If false, it means that the type is not primitive, or is boxed.
        var is_tagged = false
        # Are values of `self` tagged?
        # If false, it means that the type is not primitive, or is boxed.
        var is_tagged = false
+
+       # The tag value of the type
+       #
+       # ENSURE `is_tagged == (tag_value > 0)`
+       # ENSURE `not is_tagged == (tag_value == 0)`
+       var tag_value = 0
 end
 
 redef class MEntity
 end
 
 redef class MEntity