Merge: Simplify management of primitive types
authorJean Privat <jean@pryen.org>
Mon, 23 Mar 2015 15:16:10 +0000 (22:16 +0700)
committerJean Privat <jean@pryen.org>
Mon, 23 Mar 2015 15:16:10 +0000 (22:16 +0700)
Add direct methods to access primitive types

Simplify and improve the generation of primitive values in the compiler.

More (and improved) `*_instance` methods are now available in AbstractCompilerVisitor.
One of the point is the simplification of the generated C so that less local variables are generated, maybe this will also help the C compiler to work faster.

Pull-Request: #1213
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,9 -1078,6 +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
                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
@@@ -2288,7 -2305,7 +2312,7 @@@ redef class AAttrPropde
  
                                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("\}")
                                var ret = self.mpropdef.static_mtype
                                var useiset = ret.ctype == "val*" 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
@@@ -2701,15 -2718,15 +2725,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
@@@ -2774,15 -2791,15 +2798,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
@@@ -312,7 -312,7 +312,7 @@@ class GlobalCompilerVisito
                        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
        do
                if recv.mtype.ctype != "val*" 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)
        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)
 +              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)
 -                      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
 +
 +              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)
                                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
@@@ -1187,7 -1170,7 +1187,7 @@@ class SeparateCompilerVisito
                        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}")
                                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
  
        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
@@@ -2161,7 -2136,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)
@@@ -615,7 -615,7 +615,7 @@@ class SeparateErasureCompilerVisito
                        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}")
  
        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