rta: use callsites to do the analysis
[nit.git] / src / separate_compiler.nit
index dcd7cc7..e553259 100644 (file)
@@ -18,6 +18,7 @@ module separate_compiler
 import abstract_compiler
 import layout_builders
 import rapid_type_analysis
+import collect_super_sends
 
 # Add separate compiler specific options
 redef class ToolContext
@@ -56,7 +57,7 @@ redef class ToolContext
 end
 
 redef class ModelBuilder
-       fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
+       fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: nullable RapidTypeAnalysis)
        do
                var time0 = get_time
                self.toolcontext.info("*** GENERATING C ***", 1)
@@ -106,8 +107,10 @@ end
 class SeparateCompiler
        super AbstractCompiler
 
+       redef type VISITOR: SeparateCompilerVisitor
+
        # The result of the RTA (used to know live types and methods)
-       var runtime_type_analysis: RapidTypeAnalysis
+       var runtime_type_analysis: nullable RapidTypeAnalysis
 
        private var undead_types: Set[MType] = new HashSet[MType]
        private var partial_types: Set[MType] = new HashSet[MType]
@@ -115,10 +118,10 @@ class SeparateCompiler
 
        private var type_layout: nullable Layout[MType]
        private var resolution_layout: nullable Layout[MType]
-       protected var method_layout: nullable Layout[MMethod]
+       protected var method_layout: nullable Layout[PropertyLayoutElement]
        protected var attr_layout: nullable Layout[MAttribute]
 
-       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis) do
+       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
                super(mainmodule, mmbuilder)
                var file = new_file("nit.common")
                self.header = new CodeWriter(file)
@@ -194,24 +197,35 @@ class SeparateCompiler
        fun compile_color_consts(colors: Map[Object, Int]) do
                var v = new_visitor
                for m, c in colors do
-                       if color_consts_done.has(m) then continue
-                       if m isa MProperty then
-                               if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
-                                       self.provide_declaration(m.const_color, "#define {m.const_color} {c}")
-                               else
-                                       self.provide_declaration(m.const_color, "extern const int {m.const_color};")
-                                       v.add("const int {m.const_color} = {c};")
-                               end
-                       else if m isa MType then
-                               if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
-                                       self.provide_declaration(m.const_color, "#define {m.const_color} {c}")
-                               else
-                                       self.provide_declaration(m.const_color, "extern const int {m.const_color};")
-                                       v.add("const int {m.const_color} = {c};")
-                               end
+                       compile_color_const(v, m, c)
+               end
+       end
+
+       fun compile_color_const(v: SeparateCompilerVisitor, m: Object, color: Int) do
+               if color_consts_done.has(m) then return
+               if m isa MProperty then
+                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
+                       else
+                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
+                               v.add("const int {m.const_color} = {color};")
+                       end
+               else if m isa MPropDef then
+                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
+                       else
+                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
+                               v.add("const int {m.const_color} = {color};")
+                       end
+               else if m isa MType then
+                       if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
+                               self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
+                       else
+                               self.provide_declaration(m.const_color, "extern const int {m.const_color};")
+                               v.add("const int {m.const_color} = {color};")
                        end
-                       color_consts_done.add(m)
                end
+               color_consts_done.add(m)
        end
 
        private var color_consts_done = new HashSet[Object]
@@ -221,7 +235,7 @@ class SeparateCompiler
                var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
 
                # Layouts
-               var method_layout_builder: PropertyLayoutBuilder[MMethod]
+               var method_layout_builder: PropertyLayoutBuilder[PropertyLayoutElement]
                var attribute_layout_builder: PropertyLayoutBuilder[MAttribute]
                #FIXME PH and BM layouts too slow for large programs
                #if modelbuilder.toolcontext.opt_bm_typing.value then
@@ -237,33 +251,76 @@ class SeparateCompiler
 
                var class_layout_builder = new MClassColorer(self.mainmodule)
                class_layout_builder.build_layout(mclasses)
-               method_layout_builder = new MMethodColorer(self.mainmodule, class_layout_builder)
-               attribute_layout_builder = new MAttributeColorer(self.mainmodule, class_layout_builder)
+               method_layout_builder = new MPropertyColorer[PropertyLayoutElement](self.mainmodule, class_layout_builder)
+               attribute_layout_builder = new MPropertyColorer[MAttribute](self.mainmodule, class_layout_builder)
                #end
 
+               # lookup properties to build layout with
+               var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
+               var mattributes = new HashMap[MClass, Set[MAttribute]]
+               for mclass in mclasses do
+                       mmethods[mclass] = new HashSet[PropertyLayoutElement]
+                       mattributes[mclass] = new HashSet[MAttribute]
+                       for mprop in self.mainmodule.properties(mclass) do
+                               if mprop isa MMethod then
+                                       mmethods[mclass].add(mprop)
+                               else if mprop isa MAttribute then
+                                       mattributes[mclass].add(mprop)
+                               end
+                       end
+               end
+
+               # lookup super calls and add it to the list of mmethods to build layout with
+               var super_calls
+               if runtime_type_analysis != null then
+                       super_calls = runtime_type_analysis.live_super_sends
+               else
+                       super_calls = modelbuilder.collect_super_sends
+               end
+               for mmethoddef in super_calls do
+                       var mclass = mmethoddef.mclassdef.mclass
+                       mmethods[mclass].add(mmethoddef)
+                       for descendant in mclass.in_hierarchy(self.mainmodule).smallers do
+                               mmethods[descendant].add(mmethoddef)
+                       end
+               end
+
                # methods coloration
-               var method_layout = method_layout_builder.build_layout(mclasses)
-               self.method_tables = build_method_tables(mclasses, method_layout)
+               self.method_layout = method_layout_builder.build_layout(mmethods)
+               self.method_tables = build_method_tables(mclasses, super_calls)
                self.compile_color_consts(method_layout.pos)
-               self.method_layout = method_layout
+
+               # attribute null color to dead supercalls
+               for mmodule in self.mainmodule.in_importation.greaters do
+                       for mclassdef in mmodule.mclassdefs do
+                               for mpropdef in mclassdef.mpropdefs do
+                                       if mpropdef.has_supercall then
+                                               compile_color_const(new_visitor, mpropdef, -1)
+                                       end
+                               end
+                       end
+               end
 
                # attributes coloration
-               var attr_layout = attribute_layout_builder.build_layout(mclasses)
-               self.attr_tables = build_attr_tables(mclasses, attr_layout)
+               self.attr_layout = attribute_layout_builder.build_layout(mattributes)
+               self.attr_tables = build_attr_tables(mclasses)
                self.compile_color_consts(attr_layout.pos)
-               self.attr_layout = attr_layout
        end
 
-       fun build_method_tables(mclasses: Set[MClass], layout: Layout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+       fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do
+               var layout = self.method_layout
                var tables = new HashMap[MClass, Array[nullable MPropDef]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
+                       var supercalls = new List[MMethodDef]
+
                        # first, fill table from parents by reverse linearization order
                        var parents = new Array[MClass]
                        if mainmodule.flatten_mclass_hierarchy.has(mclass) then
                                parents = mclass.in_hierarchy(mainmodule).greaters.to_a
                                self.mainmodule.linearize_mclasses(parents)
                        end
+
                        for parent in parents do
                                if parent == mclass then continue
                                for mproperty in self.mainmodule.properties(parent) do
@@ -280,6 +337,15 @@ class SeparateCompiler
                                                end
                                        end
                                end
+
+                               # lookup for super calls in super classes
+                               for mmethoddef in super_calls do
+                                       for mclassdef in parent.mclassdefs do
+                                               if mclassdef.mpropdefs.has(mmethoddef) then
+                                                       supercalls.add(mmethoddef)
+                                               end
+                                       end
+                               end
                        end
 
                        # then override with local properties
@@ -297,12 +363,33 @@ class SeparateCompiler
                                        end
                                end
                        end
+
+                       # lookup for super calls in local class
+                       for mmethoddef in super_calls do
+                               for mclassdef in mclass.mclassdefs do
+                                       if mclassdef.mpropdefs.has(mmethoddef) then
+                                               supercalls.add(mmethoddef)
+                                       end
+                               end
+                       end
+                       # insert super calls in table according to receiver
+                       for supercall in supercalls do
+                               var color = layout.pos[supercall]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               end
+                               var mmethoddef = supercall.lookup_next_definition(self.mainmodule, mclass.intro.bound_mtype)
+                               table[color] = mmethoddef
+                       end
                        tables[mclass] = table
                end
                return tables
        end
 
-       fun build_attr_tables(mclasses: Set[MClass], layout: Layout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+       fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
+               var layout = self.attr_layout
                var tables = new HashMap[MClass, Array[nullable MPropDef]]
                for mclass in mclasses do
                        var table = new Array[nullable MPropDef]
@@ -641,7 +728,7 @@ class SeparateCompiler
                var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
-               var is_dead = not runtime_type_analysis.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray"
+               var is_dead = runtime_type_analysis != null and not runtime_type_analysis.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray"
 
                v.add_decl("/* runtime class {c_name} */")
 
@@ -733,8 +820,6 @@ class SeparateCompiler
                        v.add("return {res};")
                end
                v.add("\}")
-
-               generate_check_init_instance(mtype)
        end
 
        # Add a dynamic test to ensure that the type referenced by `t` is a live type
@@ -750,24 +835,6 @@ class SeparateCompiler
                v.add("\}")
        end
 
-       redef fun generate_check_init_instance(mtype)
-       do
-               if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
-
-               var v = self.new_visitor
-               var c_name = mtype.mclass.c_name
-               var res = new RuntimeVariable("self", mtype, mtype)
-               self.provide_declaration("CHECK_NEW_{c_name}", "void CHECK_NEW_{c_name}({mtype.ctype});")
-               v.add_decl("/* allocate {mtype} */")
-               v.add_decl("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{")
-               if runtime_type_analysis.live_classes.has(mtype.mclass) then
-                       self.generate_check_attr(v, res, mtype)
-               else
-                       v.add_abort("{mtype.mclass} is DEAD")
-               end
-               v.add("\}")
-       end
-
        redef fun new_visitor do return new SeparateCompilerVisitor(self)
 
        # Stats
@@ -862,9 +929,9 @@ class SeparateCompilerVisitor
                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
+                       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("printf(\"Dead code executed!\\n\"); exit(1);")
+                               self.add("printf(\"Dead code executed!\\n\"); show_backtrace(1);")
                                return res
                        end
                        self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
@@ -873,7 +940,7 @@ class SeparateCompilerVisitor
                        # 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);")
+                       self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); show_backtrace(1);")
                        return res
                end
        end
@@ -892,6 +959,8 @@ class SeparateCompilerVisitor
 
        redef fun send(mmethod, arguments)
        do
+               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
+
                if arguments.first.mcasttype.ctype != "val*" 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
@@ -902,6 +971,11 @@ class SeparateCompilerVisitor
                        return res
                end
 
+               return table_send(mmethod, arguments, mmethod.const_color)
+       end
+
+       private fun table_send(mmethod: MMethod, arguments: Array[RuntimeVariable], const_color: String): nullable RuntimeVariable
+       do
                var res: nullable RuntimeVariable
                var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
                var ret = msignature.return_mtype
@@ -920,7 +994,6 @@ class SeparateCompilerVisitor
                var recv = arguments.first
                s.append("val*")
                ss.append("{recv}")
-               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
                for i in [0..msignature.arity[ do
                        var a = arguments[i+1]
                        var t = msignature.mparameters[i].mtype
@@ -980,8 +1053,8 @@ class SeparateCompilerVisitor
 
                var r
                if ret == null then r = "void" else r = ret.ctype
-               self.require_declaration(mmethod.const_color)
-               var call = "(({r} (*)({s}))({arguments.first}->class->vft[{mmethod.const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
+               self.require_declaration(const_color)
+               var call = "(({r} (*)({s}))({arguments.first}->class->vft[{const_color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
 
                if res != null then
                        self.add("{res} = {call};")
@@ -1040,11 +1113,18 @@ class SeparateCompilerVisitor
                return res
        end
 
-       redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
+       redef fun supercall(m: MMethodDef, recvtype: MClassType, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
-               # FIXME implements a polymorphic access in tables
-               m = m.lookup_next_definition(m.mclassdef.mmodule, m.mclassdef.bound_mtype)
-               return self.call(m, recvtype, args)
+               if arguments.first.mcasttype.ctype != "val*" 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.compiler.mainmodule = self.compiler.realmainmodule
+                       var res = self.monomorphic_super_send(m, recvtype, arguments)
+                       self.compiler.mainmodule = main
+                       return res
+               end
+               return table_send(m.mproperty, arguments, m.const_color)
        end
 
        redef fun vararg_instance(mpropdef, recv, varargs, elttype)
@@ -1192,13 +1272,6 @@ class SeparateCompilerVisitor
                return self.new_expr("NEW_{mtype.mclass.c_name}(&type_{mtype.c_name})", mtype)
        end
 
-       redef fun check_init_instance(value, mtype)
-       do
-               if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
-               self.require_declaration("CHECK_NEW_{mtype.mclass.c_name}")
-               self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
-       end
-
        redef fun type_test(value, mtype, tag)
        do
                self.add("/* {value.inspect} isa {mtype} */")
@@ -1265,7 +1338,7 @@ class SeparateCompilerVisitor
                                self.add("count_type_test_resolved_{tag}++;")
                        end
                else
-                       self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); exit(1);")
+                       self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
                end
 
                # check color is in table
@@ -1321,6 +1394,8 @@ class SeparateCompilerVisitor
                self.add_decl("const char* {res};")
                if value.mtype.ctype == "val*" then
                        self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;"
+               else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind then
+                       self.add "{res} = \"{value.mtype.as(MClassType).mclass}\";"
                else
                        self.require_declaration("type_{value.mtype.c_name}")
                        self.add "{res} = type_{value.mtype.c_name}.name;"
@@ -1447,7 +1522,6 @@ class SeparateCompilerVisitor
                        self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
                end
                self.send(self.get_property("with_native", arrayclass.intro.bound_mtype), [res, nat, length])
-               self.check_init_instance(res, arraytype)
                self.add("\}")
                return res
        end
@@ -1604,6 +1678,7 @@ class SeparateRuntimeFunction
                        v.add("return {frame.returnvar.as(not null)};")
                end
                v.add("\}")
+               if not self.c_name.has_substring("VIRTUAL", 0) then compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}:{mmethoddef.location.line_start})"
        end
 end
 
@@ -1681,6 +1756,7 @@ class VirtualRuntimeFunction
                        v.add("return {frame.returnvar.as(not null)};")
                end
                v.add("\}")
+               if not self.c_name.has_substring("VIRTUAL", 0) then compiler.names[self.c_name] = "{mmethoddef.mclassdef.mmodule.name}::{mmethoddef.mclassdef.mclass.name}::{mmethoddef.mproperty.name} ({mmethoddef.location.file.filename}--{mmethoddef.location.line_start})"
        end
 
        # TODO ?
@@ -1694,3 +1770,7 @@ end
 redef class MProperty
        fun const_color: String do return "COLOR_{c_name}"
 end
+
+redef class MPropDef
+       fun const_color: String do return "COLOR_{c_name}"
+end