Merge: compiler: introduce and use `MType::is_c_primitive`
authorJean Privat <jean@pryen.org>
Mon, 23 Mar 2015 15:16:18 +0000 (22:16 +0700)
committerJean Privat <jean@pryen.org>
Mon, 23 Mar 2015 15:16:18 +0000 (22:16 +0700)
Thus remove all comparaison to "val*" in the code, this is cleaner.

Pull-Request: #1214
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

1  2 
src/compiler/abstract_compiler.nit
src/compiler/global_compiler.nit
src/compiler/separate_compiler.nit
src/compiler/separate_erasure_compiler.nit

@@@ -603,9 -603,9 +603,9 @@@ abstract class AbstractCompile
                var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value
                if gccd_disable.has("noreturn") or gccd_disable.has("all") then
                        # Signal handler function prototype
 -                      self.header.add_decl("void show_backtrace(int);")
 +                      self.header.add_decl("void fatal_exit(int);")
                else
 -                      self.header.add_decl("void show_backtrace(int) __attribute__ ((noreturn));")
 +                      self.header.add_decl("void fatal_exit(int) __attribute__ ((noreturn));")
                end
  
                if gccd_disable.has("likely") or gccd_disable.has("all") then
@@@ -741,7 -741,12 +741,7 @@@ extern void nitni_global_ref_decr( stru
                        v.compiler.header.add_decl("extern long count_isset_checks;")
                end
  
 -              v.add_decl("void sig_handler(int signo)\{")
 -              v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
 -              v.add_decl("show_backtrace(signo);")
 -              v.add_decl("\}")
 -
 -              v.add_decl("void show_backtrace (int signo) \{")
 +              v.add_decl("static void show_backtrace(void) \{")
                if ost == "nitstack" or ost == "libunwind" then
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
                end
 -              v.add_decl("exit(signo);")
 +              v.add_decl("\}")
 +
 +              v.add_decl("void sig_handler(int signo)\{")
 +              v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
 +              v.add_decl("show_backtrace();")
 +              # rethrows
 +              v.add_decl("signal(signo, SIG_DFL);")
 +              v.add_decl("kill(getpid(), signo);")
 +              v.add_decl("\}")
 +
 +              v.add_decl("void fatal_exit(int status) \{")
 +              v.add_decl("show_backtrace();")
 +              v.add_decl("exit(status);")
                v.add_decl("\}")
  
                if no_main then
@@@ -1085,6 -1078,9 +1085,6 @@@ abstract class AbstractCompilerVisito
                self.writer = new CodeWriter(compiler.files.last)
        end
  
 -      # Force to get the primitive class named `name` or abort
 -      fun get_class(name: String): MClass do return self.compiler.mainmodule.get_primitive_class(name)
 -
        # Force to get the primitive property named `name` in the instance `recv` or abort
        fun get_property(name: String, recv: MType): MMethod
        do
                var recv
                var ctype = mtype.ctype
                assert mtype.mclass.name != "NativeArray"
-               if ctype == "val*" then
+               if not mtype.is_c_primitive then
                        recv = init_instance(mtype)
                else if ctype == "char*" then
                        recv = new_expr("NULL/*special!*/", mtype)
                end
        end
  
 +      # The currently processed module
 +      #
 +      # alias for `compiler.mainmodule`
 +      fun mmodule: MModule do return compiler.mainmodule
 +
        # Generate an integer value
        fun int_instance(value: Int): RuntimeVariable
        do
 -              var res = self.new_var(self.get_class("Int").mclass_type)
 -              self.add("{res} = {value};")
 +              var t = mmodule.int_type
 +              var res = new RuntimeVariable("{value.to_s}l", t, t)
 +              return res
 +      end
 +
 +      # Generate a char value
 +      fun char_instance(value: Char): RuntimeVariable
 +      do
 +              var t = mmodule.char_type
 +              var res = new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
 +              return res
 +      end
 +
 +      # Generate a float value
 +      #
 +      # FIXME pass a Float, not a string
 +      fun float_instance(value: String): RuntimeVariable
 +      do
 +              var t = mmodule.float_type
 +              var res = new RuntimeVariable("{value}", t, t)
                return res
        end
  
        # Generate an integer value
        fun bool_instance(value: Bool): RuntimeVariable
        do
 -              var res = self.new_var(self.get_class("Bool").mclass_type)
 -              if value then
 -                      self.add("{res} = 1;")
 -              else
 -                      self.add("{res} = 0;")
 -              end
 +              var s = if value then "1" else "0"
 +              var res = new RuntimeVariable(s, bool_type, bool_type)
 +              return res
 +      end
 +
 +      # Generate the `null` value
 +      fun null_instance: RuntimeVariable
 +      do
 +              var t = compiler.mainmodule.model.null_type
 +              var res = new RuntimeVariable("((val*)NULL)", t, t)
                return res
        end
  
        # Generate a string value
        fun string_instance(string: String): RuntimeVariable
        do
 -              var mtype = self.get_class("String").mclass_type
 +              var mtype = mmodule.string_type
                var name = self.get_name("varonce")
                self.add_decl("static {mtype.ctype} {name};")
                var res = self.new_var(mtype)
                self.add("if (likely({name}!=NULL)) \{")
                self.add("{res} = {name};")
                self.add("\} else \{")
 -              var native_mtype = self.get_class("NativeString").mclass_type
 +              var native_mtype = mmodule.native_string_type
                var nat = self.new_var(native_mtype)
                self.add("{nat} = \"{string.escape_to_c}\";")
                var length = self.int_instance(string.length)
                else
                        self.add("PRINT_ERROR(\"\\n\");")
                end
 -              self.add("show_backtrace(1);")
 +              self.add("fatal_exit(1);")
        end
  
        # Add a dynamic cast
@@@ -1785,12 -1754,16 +1785,16 @@@ redef class MTyp
  
        # Short name of the `ctype` to use in unions
        fun ctypename: String do return "val"
+       # Is the associated C type a primitive one?
+       #
+       # ENSURE `result == (ctype != "val*")`
+       fun is_c_primitive: Bool do return false
  end
  
  redef class MClassType
  
-       redef fun ctype: String
-       do
+       redef var ctype is lazy do
                if mclass.name == "Int" then
                        return "long"
                else if mclass.name == "Bool" then
                end
        end
  
+       redef var is_c_primitive is lazy do return ctype != "val*"
        redef fun ctype_extern: String
        do
                if mclass.kind == extern_kind then
@@@ -2297,7 -2272,7 +2303,7 @@@ redef class AAttrPropde
                        if is_lazy then
                                var set
                                var ret = self.mpropdef.static_mtype
-                               var useiset = ret.ctype == "val*" and not ret isa MNullableType
+                               var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                var guard = self.mlazypropdef.mproperty
                                if useiset then
                                        set = v.isset_attribute(self.mpropdef.mproperty, recv)
  
                                v.assign(res, value)
                                if not useiset then
 -                                      var true_v = v.new_expr("1", v.bool_type)
 +                                      var true_v = v.bool_instance(true)
                                        v.write_attribute(guard, arguments.first, true_v)
                                end
                                v.add("\}")
                        v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
                        if is_lazy then
                                var ret = self.mpropdef.static_mtype
-                               var useiset = ret.ctype == "val*" and not ret isa MNullableType
+                               var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                if not useiset then
 -                                      v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.new_expr("1", v.bool_type))
 +                                      v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true))
                                end
                        end
                else
@@@ -2725,15 -2700,15 +2731,15 @@@ redef class AOrElseExp
  end
  
  redef class AIntExpr
 -      redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null))
 +      redef fun expr(v) do return v.int_instance(self.value.as(not null))
  end
  
  redef class AFloatExpr
 -      redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float
 +      redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
  end
  
  redef class ACharExpr
 -      redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null))
 +      redef fun expr(v) do return v.char_instance(self.value.as(not null))
  end
  
  redef class AArrayExpr
@@@ -2798,15 -2773,15 +2804,15 @@@ redef class AOrangeExp
  end
  
  redef class ATrueExpr
 -      redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null))
 +      redef fun expr(v) do return v.bool_instance(true)
  end
  
  redef class AFalseExpr
 -      redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null))
 +      redef fun expr(v) do return v.bool_instance(false)
  end
  
  redef class ANullExpr
 -      redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null))
 +      redef fun expr(v) do return v.null_instance
  end
  
  redef class AIsaExpr
@@@ -2834,7 -2809,7 +2840,7 @@@ redef class AAsNotnullExp
                var i = v.expr(self.n_expr, null)
                if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
  
-               if i.mtype.ctype != "val*" then return i
+               if i.mtype.is_c_primitive then return i
  
                v.add("if (unlikely({i} == NULL)) \{")
                v.add_abort("Cast failed")
@@@ -86,7 -86,7 +86,7 @@@ class GlobalCompile
                self.header = new CodeWriter(file)
                self.live_primitive_types = new Array[MClassType]
                for t in runtime_type_analysis.live_types do
-                       if t.ctype != "val*" or t.mclass.name == "Pointer" then
+                       if t.is_c_primitive or t.mclass.name == "Pointer" then
                                self.live_primitive_types.add(t)
                        end
                end
  
                # Init instance code (allocate and init-arguments)
                for t in runtime_type_analysis.live_types do
-                       if t.ctype == "val*" then
+                       if not t.is_c_primitive then
                                compiler.generate_init_instance(t)
                                if t.mclass.kind == extern_kind then
                                        compiler.generate_box_instance(t)
        fun generate_init_instance(mtype: MClassType)
        do
                assert self.runtime_type_analysis.live_types.has(mtype)
-               assert mtype.ctype == "val*"
+               assert not mtype.is_c_primitive
                var v = self.new_visitor
  
                var is_native_array = mtype.mclass.name == "NativeArray"
@@@ -303,16 -303,16 +303,16 @@@ class GlobalCompilerVisito
        do
                if value.mtype == mtype then
                        return value
-               else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
+               else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then
                        return value
-               else if value.mtype.ctype == "val*" then
+               else if not value.mtype.is_c_primitive then
                        return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
-               else if mtype.ctype == "val*" then
+               else if not mtype.is_c_primitive 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("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
                        # Bad things will appen!
                        var res = self.new_var(mtype)
                        self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
 -                      self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
 +                      self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); fatal_exit(1);")
                        return res
                end
        end
                var res = self.new_var(mtype)
                if not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
                        self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
 -                      self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                      self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                        return res
                end
                self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
  
        redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
        do
 -              var ret_type = self.get_class("NativeArray").get_mtype([elttype])
 +              var ret_type = mmodule.native_array_type(elttype)
                ret_type = anchor(ret_type).as(MClassType)
                return self.new_expr("NEW_{ret_type.c_name}({length})", ret_type)
        end
                end
  
                self.add("/* send {m} on {args.first.inspect} */")
-               if args.first.mtype.ctype != "val*" then
+               if args.first.mtype.is_c_primitive then
                        var mclasstype = args.first.mtype.as(MClassType)
                        if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
                                self.add("/* skip, no method {m} */")
                var defaultpropdef: nullable MMethodDef = null
                for t in types do
                        var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
-                       if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
+                       if propdef.mclassdef.mclass.name == "Object" and not t.is_c_primitive then
                                defaultpropdef = propdef
                                continue
                        end
                end
  
                self.add("/* super {m} on {args.first.inspect} */")
-               if args.first.mtype.ctype != "val*" then
+               if args.first.mtype.is_c_primitive then
                        var mclasstype = args.first.mtype.as(MClassType)
                        if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
                                self.add("/* skip, no method {m} */")
  
        fun bugtype(recv: RuntimeVariable)
        do
-               if recv.mtype.ctype != "val*" then return
+               if recv.mtype.is_c_primitive then return
                self.add("PRINT_ERROR(\"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
 -              self.add("show_backtrace(1);")
 +              self.add("fatal_exit(1);")
        end
  
        redef fun isset_attribute(a, recv)
                        ta = self.resolve_for(ta, recv2)
                        var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
                        if not ta isa MNullableType then
-                               if ta.ctype == "val*" then
+                               if not ta.is_c_primitive then
                                        self.add("{res} = ({attr} != NULL);")
                                else
                                        self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
                        ta = self.resolve_for(ta, recv2)
                        var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
                        if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
-                               if ta.ctype == "val*" then
+                               if not ta.is_c_primitive then
                                        self.add("if ({res2} == NULL) \{")
                                        self.add_abort("Uninitialized attribute {a.name}")
                                        self.add("\}")
                var res = self.new_var(bool_type)
  
                self.add("/* isa {mtype} on {value.inspect} */")
-               if value.mtype.ctype != "val*" then
+               if value.mtype.is_c_primitive then
                        if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
                                self.add("{res} = 1;")
                        else
        redef fun is_same_type_test(value1, value2)
        do
                var res = self.new_var(bool_type)
-               if value2.mtype.ctype == "val*" then
-                       if value1.mtype.ctype == "val*" then
+               if not value2.mtype.is_c_primitive then
+                       if not value1.mtype.is_c_primitive then
                                self.add "{res} = {value1}->classid == {value2}->classid;"
                        else
                                self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
                        end
                else
-                       if value1.mtype.ctype == "val*" then
+                       if not value1.mtype.is_c_primitive then
                                self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
                        else if value1.mcasttype == value2.mcasttype then
                                self.add "{res} = 1;"
        do
                var res = self.get_name("var_class_name")
                self.add_decl("const char* {res};")
-               if value.mtype.ctype == "val*" then
+               if not value.mtype.is_c_primitive then
                        self.add "{res} = class_names[{value}->classid];"
                else
                        self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
        redef fun equal_test(value1, value2)
        do
                var res = self.new_var(bool_type)
-               if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
+               if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
                        var tmp = value1
                        value1 = value2
                        value2 = tmp
                end
-               if value1.mtype.ctype != "val*" then
+               if value1.mtype.is_c_primitive then
                        if value2.mtype == value1.mtype then
                                self.add("{res} = {value1} == {value2};")
-                       else if value2.mtype.ctype != "val*" then
+                       else if value2.mtype.is_c_primitive then
                                self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
                        else
                                var mtype1 = value1.mtype.as(MClassType)
        redef fun array_instance(array, elttype)
        do
                elttype = self.anchor(elttype)
 -              var arraytype = self.get_class("Array").get_mtype([elttype])
 +              var arraytype = mmodule.array_type(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]))
 +              var nat = self.new_var(mmodule.native_array_type(elttype))
                nat.is_exact = true
                self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
                for i in [0..array.length[ do
@@@ -991,7 -991,7 +991,7 @@@ private class CustomizedRuntimeFunctio
                for i in [0..mmethoddef.msignature.arity[ do
                        var mtype = mmethoddef.msignature.mparameters[i].mtype
                        if i == mmethoddef.msignature.vararg_rank then
 -                              mtype = v.get_class("Array").get_mtype([mtype])
 +                              mtype = v.mmodule.array_type(mtype)
                        end
                        mtype = v.resolve_for(mtype, selfvar)
                        comment.append(", {mtype}")
@@@ -268,7 -268,7 +268,7 @@@ class SeparateCompile
                if mclass.mclass_type.ctype_extern == "val*" then
                        return 0
                else if mclass.kind == extern_kind and mclass.name != "NativeString" then
 -                      return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
 +                      return self.box_kinds[self.mainmodule.pointer_type.mclass]
                else
                        return self.box_kinds[mclass]
                end
                # Collect types to colorize
                var live_types = runtime_type_analysis.live_types
                var live_cast_types = runtime_type_analysis.live_cast_types
 -              var mtypes = new HashSet[MType]
 -              mtypes.add_all(live_types)
 -              for c in self.box_kinds.keys do
 -                      mtypes.add(c.mclass_type)
 -              end
  
                # Compute colors
 -              var poset = poset_from_mtypes(mtypes, live_cast_types)
 +              var poset = poset_from_mtypes(live_types, live_cast_types)
                var colorer = new POSetColorer[MType]
                colorer.colorize(poset)
                type_ids = colorer.ids
                type_tables = build_type_tables(poset)
  
                # VT and FT are stored with other unresolved types in the big resolution_tables
 -              self.compile_resolution_tables(mtypes)
 +              self.compute_resolution_tables(live_types)
  
                return poset
        end
  
        private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
                var poset = new POSet[MType]
 +
 +              # Instead of doing the full matrix mtypes X cast_types,
 +              # a grouping is done by the base classes of the type so
 +              # that we compare only types whose base classes are in inheritance.
 +
 +              var mtypes_by_class = new MultiHashMap[MClass, MType]
                for e in mtypes do
 +                      var c = e.as_notnullable.as(MClassType).mclass
 +                      mtypes_by_class[c].add(e)
                        poset.add_node(e)
 -                      for o in cast_types do
 -                              if e == o then continue
 -                              poset.add_node(o)
 -                              if e.is_subtype(mainmodule, null, o) then
 -                                      poset.add_edge(e, o)
 +              end
 +
 +              var casttypes_by_class = new MultiHashMap[MClass, MType]
 +              for e in cast_types do
 +                      var c = e.as_notnullable.as(MClassType).mclass
 +                      casttypes_by_class[c].add(e)
 +                      poset.add_node(e)
 +              end
 +
 +              for c1, ts1 in mtypes_by_class do
 +                      for c2 in c1.in_hierarchy(mainmodule).greaters do
 +                              var ts2 = casttypes_by_class[c2]
 +                              for e in ts1 do
 +                                      for o in ts2 do
 +                                              if e == o then continue
 +                                              if e.is_subtype(mainmodule, null, o) then
 +                                                      poset.add_edge(e, o)
 +                                              end
 +                                      end
                                end
                        end
                end
                return tables
        end
  
 -      protected fun compile_resolution_tables(mtypes: Set[MType]) do
 -              # resolution_tables is used to perform a type resolution at runtime in O(1)
 -
 +      # resolution_tables is used to perform a type resolution at runtime in O(1)
 +      private fun compute_resolution_tables(mtypes: Set[MType]) do
                # During the visit of the body of classes, live_unresolved_types are collected
                # and associated to
                # Collect all live_unresolved_types (visited in the body of classes)
                var v = new_visitor
  
                var rta = runtime_type_analysis
-               var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" and mclass.name != "Pointer"
+               var is_dead = rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" and mclass.name != "Pointer"
  
                v.add_decl("/* runtime class {c_name} */")
  
                        v.add_decl("\};")
                end
  
-               if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then
+               if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then
                        # Is a primitive type or the Pointer class, not any other extern class
  
                        if mtype.is_tagged then return
                                v.add_decl("NULL,")
                        else
                                var s = "type_{t.c_name}"
 +                              undead_types.add(t.mclass_type)
                                v.require_declaration(s)
                                v.add_decl("&{s},")
                        end
@@@ -1153,9 -1136,9 +1153,9 @@@ class SeparateCompilerVisito
        do
                if value.mtype == mtype then
                        return value
-               else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
+               else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then
                        return value
-               else if value.mtype.ctype == "val*" then
+               else if not value.mtype.is_c_primitive then
                        if mtype.is_tagged then
                                if mtype.name == "Int" then
                                        return self.new_expr("(long)({value})>>2", mtype)
                                end
                        end
                        return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
-               else if mtype.ctype == "val*" then
+               else if not mtype.is_c_primitive then
                        if value.mtype.is_tagged then
                                if value.mtype.name == "Int" then
                                        return self.new_expr("(val*)({value}<<2|1)", mtype)
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and 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("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")
                        # Bad things will appen!
                        var res = self.new_var(mtype)
                        self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
 -                      self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
 +                      self.add("PRINT_ERROR(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); fatal_exit(1);")
                        return res
                end
        end
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
                                self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
 -                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")
        # Thus the expression can be used as a condition.
        fun extract_tag(value: RuntimeVariable): String
        do
-               assert value.mtype.ctype == "val*"
+               assert not value.mtype.is_c_primitive
                return "((long){value}&3)" # Get the two low bits
        end
  
        # The point of the method is to work also with primitive types.
        fun class_info(value: RuntimeVariable): String
        do
-               if value.mtype.ctype == "val*" then
+               if not value.mtype.is_c_primitive then
                        if can_be_primitive(value) and not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
                                var tag = extract_tag(value)
                                return "({tag}?class_info[{tag}]:{value}->class)"
        # The point of the method is to work also with primitive types.
        fun type_info(value: RuntimeVariable): String
        do
-               if value.mtype.ctype == "val*" then
+               if not value.mtype.is_c_primitive then
                        if can_be_primitive(value) and not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
                                var tag = extract_tag(value)
                                return "({tag}?type_info[{tag}]:{value}->type)"
        end
        redef fun send(mmethod, arguments)
        do
-               if arguments.first.mcasttype.ctype != "val*" then
+               if arguments.first.mcasttype.is_c_primitive then
                        # In order to shortcut the primitive, we need to find the most specific method
                        # Howverr, because of performance (no flattening), we always work on the realmainmodule
                        var m = self.compiler.mainmodule
  
        redef fun supercall(m: MMethodDef, recvtype: MClassType, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
-               if arguments.first.mcasttype.ctype != "val*" then
+               if arguments.first.mcasttype.is_c_primitive then
                        # In order to shortcut the primitive, we need to find the most specific method
                        # However, because of performance (no flattening), we always work on the realmainmodule
                        var main = self.compiler.mainmodule
                        self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
                else
  
-                       if mtype.ctype == "val*" then
+                       if not mtype.is_c_primitive then
                                self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
                        else
                                self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
                        self.add("{res} = {recv}->attrs[{a.const_color}].{ret.ctypename}; /* {a} on {recv.inspect} */")
  
                        # Check for Uninitialized attribute
-                       if ret.ctype == "val*" and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
+                       if not ret.is_c_primitive and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then
                                self.add("if (unlikely({res} == NULL)) \{")
                                self.add_abort("Uninitialized attribute {a.name}")
                                self.add("\}")
                self.require_declaration(a.const_color)
                if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
                        var attr = "{recv}->attrs[{a.const_color}]"
-                       if mtype.ctype != "val*" then
+                       if mtype.is_c_primitive then
                                assert mtype isa MClassType
                                # The attribute is primitive, thus we store it in a box
                                # The trick is to create the box the first time then resuse the box
                                self.add("count_type_test_resolved_{tag}++;")
                        end
                else
 -                      self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
 +                      self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); fatal_exit(1);")
                end
  
                # check color is in table
        do
                var res = self.new_var(bool_type)
                # Swap values to be symetric
-               if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
+               if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
                        var tmp = value1
                        value1 = value2
                        value2 = tmp
                end
-               if value1.mtype.ctype != "val*" then
+               if value1.mtype.is_c_primitive then
                        if value2.mtype == value1.mtype then
                                self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
-                       else if value2.mtype.ctype != "val*" then
+                       else if value2.mtype.is_c_primitive then
                                self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
                        else
                                var mtype1 = value1.mtype.as(MClassType)
        do
                var res = self.get_name("var_class_name")
                self.add_decl("const char* {res};")
-               if value.mtype.ctype == "val*" then
+               if not value.mtype.is_c_primitive then
                        self.add "{res} = {value} == NULL ? \"null\" : {type_info(value)}->name;"
                else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind and
                        value.mtype.as(MClassType).name != "NativeString" then
        redef fun equal_test(value1, value2)
        do
                var res = self.new_var(bool_type)
-               if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
+               if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then
                        var tmp = value1
                        value1 = value2
                        value2 = tmp
                end
-               if value1.mtype.ctype != "val*" then
+               if value1.mtype.is_c_primitive then
                        if value2.mtype == value1.mtype then
                                self.add("{res} = {value1} == {value2};")
-                       else if value2.mtype.ctype != "val*" then
+                       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});")
  
                var incompatible = false
                var primitive
-               if t1.ctype != "val*" then
+               if t1.is_c_primitive then
                        primitive = t1
                        if t1 == t2 then
                                # No need to compare class
-                       else if t2.ctype != "val*" then
+                       else if t2.is_c_primitive then
                                incompatible = true
                        else if can_be_primitive(value2) then
                                if t1.is_tagged then
                        else
                                incompatible = true
                        end
-               else if t2.ctype != "val*" then
+               else if t2.is_c_primitive then
                        primitive = t2
                        if can_be_primitive(value1) then
                                if t2.is_tagged then
                var t = value.mcasttype.as_notnullable
                if not t isa MClassType then return false
                var k = t.mclass.kind
-               return k == interface_kind or t.ctype != "val*"
+               return k == interface_kind or t.is_c_primitive
        end
  
        fun maybe_null(value: RuntimeVariable): Bool
  
        redef fun array_instance(array, elttype)
        do
 -              var nclass = self.get_class("NativeArray")
 -              var arrayclass = self.get_class("Array")
 +              var nclass = mmodule.native_array_class
 +              var arrayclass = mmodule.array_class
                var arraytype = arrayclass.get_mtype([elttype])
                var res = self.init_instance(arraytype)
                self.add("\{ /* {res} = array_instance Array[{elttype}] */")
  
        redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
        do
 -              var mtype = self.get_class("NativeArray").get_mtype([elttype])
 +              var mtype = mmodule.native_array_type(elttype)
                self.require_declaration("NEW_{mtype.mclass.c_name}")
                assert mtype isa MGenericType
                var compiler = self.compiler
        redef fun native_array_def(pname, ret_type, arguments)
        do
                var elttype = arguments.first.mtype
 -              var nclass = self.get_class("NativeArray")
 +              var nclass = mmodule.native_array_class
                var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
                if pname == "[]" then
                        # Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing
                end
        end
  
 -      redef fun calloc_array(ret_type, arguments)
 -      do
 -              var mclass = self.get_class("ArrayCapable")
 -              var ft = mclass.mparameters.first
 -              var res = self.native_array_instance(ft, arguments[1])
 -              self.ret(res)
 -      end
 -
        fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do
                assert mtype.need_anchor
                var compiler = self.compiler
@@@ -2153,7 -2144,7 +2153,7 @@@ class SeparateRuntimeFunctio
                for i in [0..called_signature.arity[ do
                        var mtype = called_signature.mparameters[i].mtype
                        if i == called_signature.vararg_rank then
 -                              mtype = mmethoddef.mclassdef.mmodule.get_primitive_class("Array").get_mtype([mtype])
 +                              mtype = mmethoddef.mclassdef.mmodule.array_type(mtype)
                        end
                        sig.append(", {mtype.ctype} p{i}")
                end
                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])
 +                              mtype = v.mmodule.array_type(mtype)
                        end
                        comment.append(", {mtype}")
                        var argvar = new RuntimeVariable("p{i}", mtype, mtype)
                var selfvar = arguments.first
                var ret = called_signature.return_mtype
  
-               if mmethoddef.is_intro and recv.ctype == "val*" then
+               if mmethoddef.is_intro and not recv.is_c_primitive then
                        var m = mmethoddef.mproperty
                        var n2 = "CALL_" + m.const_color
                        compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};")
                        v2.add "\}"
  
                end
-               if mmethoddef.has_supercall and recv.ctype == "val*" then
+               if mmethoddef.has_supercall and not recv.is_c_primitive then
                        var m = mmethoddef
                        var n2 = "CALL_" + m.const_color
                        compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};")
@@@ -206,7 -206,7 +206,7 @@@ class SeparateErasureCompile
  
                var rta = runtime_type_analysis
                var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind
-               if not is_dead and rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" then
+               if not is_dead and rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" then
                        is_dead = true
                end
  
                v.add_decl("\}")
                v.add_decl("\};")
  
-               if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then
+               if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then
                        #Build instance struct
                        self.header.add_decl("struct instance_{c_name} \{")
                        self.header.add_decl("const struct class *class;")
@@@ -529,7 -529,7 +529,7 @@@ class SeparateErasureCompilerVisito
                end
  
                var class_ptr
-               if value.mtype.ctype == "val*" then
+               if not value.mtype.is_c_primitive then
                        class_ptr = "{value}->class->"
                else
                        var mclass = value.mtype.as(MClassType).mclass
                else if mtype isa MVirtualType then
                        var recv = self.frame.arguments.first
                        var recv_ptr
-                       if recv.mtype.ctype == "val*" then
+                       if not recv.mtype.is_c_primitive then
                                recv_ptr = "{recv}->class->"
                        else
                                var mclass = recv.mtype.as(MClassType).mclass
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
                                self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
 -                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
                                return res
                        end
                        self.require_declaration("BOX_{valtype.c_name}")
        do
                var res = self.get_name("var_class_name")
                self.add_decl("const char* {res};")
-               if value.mtype.ctype == "val*" then
+               if not value.mtype.is_c_primitive then
                        self.add "{res} = {value} == NULL ? \"null\" : {value}->class->name;"
                else
                        self.require_declaration("class_{value.mtype.c_name}")
  
        redef fun native_array_instance(elttype, length)
        do
 -              var nclass = self.get_class("NativeArray")
 +              var nclass = mmodule.native_array_class
                var mtype = nclass.get_mtype([elttype])
                var res = self.new_var(mtype)
                res.is_exact = true