src: remove remaining references of subclasses on AMethPropdef
[nit.git] / src / separate_compiler.nit
index 01ac4fa..071b706 100644 (file)
@@ -18,7 +18,6 @@ module separate_compiler
 import abstract_compiler
 import layout_builders
 import rapid_type_analysis
-import compiler_ffi
 
 # Add separate compiler specific options
 redef class ToolContext
@@ -36,6 +35,12 @@ redef class ToolContext
        var opt_inline_some_methods: OptionBool = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
        # --direct-call-monomorph
        var opt_direct_call_monomorph: OptionBool = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
+       # --skip-dead-methods
+       var opt_skip_dead_methods = new OptionBool("Do not compile dead methods (semi-global)", "--skip-dead-methods")
+       # --semi-global
+       var opt_semi_global = new OptionBool("Enable all semi-global optimizations", "--semi-global")
+       # --no-colo-dead-methods
+       var opt_no_colo_dead_methods = new OptionBool("Do not colorize dead methods", "--no-colo-dead-methods")
        # --use-naive-coloring
        var opt_bm_typing: OptionBool = new OptionBool("Colorize items incrementaly, used to simulate binary matrix typing", "--bm-typing")
        # --use-mod-perfect-hashing
@@ -52,12 +57,26 @@ redef class ToolContext
                self.option_context.add_option(self.opt_no_inline_intern)
                self.option_context.add_option(self.opt_no_union_attribute)
                self.option_context.add_option(self.opt_no_shortcut_equate)
-               self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph)
+               self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
+               self.option_context.add_option(self.opt_no_colo_dead_methods)
                self.option_context.add_option(self.opt_bm_typing)
                self.option_context.add_option(self.opt_phmod_typing)
                self.option_context.add_option(self.opt_phand_typing)
                self.option_context.add_option(self.opt_tables_metrics)
        end
+
+       redef fun process_options(args)
+       do
+               super
+
+               var tc = self
+               if tc.opt_semi_global.value then
+                       tc.opt_inline_coloring_numbers.value = true
+                       tc.opt_inline_some_methods.value = true
+                       tc.opt_direct_call_monomorph.value = true
+                       tc.opt_skip_dead_methods.value = true
+               end
+       end
 end
 
 redef class ModelBuilder
@@ -249,6 +268,8 @@ class SeparateCompiler
        fun do_property_coloring do
                var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
 
+               var rta = runtime_type_analysis
+
                # Layouts
                var method_layout_builder: PropertyLayoutBuilder[PropertyLayoutElement]
                var attribute_layout_builder: PropertyLayoutBuilder[MAttribute]
@@ -270,6 +291,9 @@ class SeparateCompiler
                attribute_layout_builder = new MPropertyColorer[MAttribute](self.mainmodule, class_layout_builder)
                #end
 
+               # The dead methods, still need to provide a dead color symbol
+               var dead_methods = new Array[MMethod]
+
                # lookup properties to build layout with
                var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
                var mattributes = new HashMap[MClass, Set[MAttribute]]
@@ -278,6 +302,10 @@ class SeparateCompiler
                        mattributes[mclass] = new HashSet[MAttribute]
                        for mprop in self.mainmodule.properties(mclass) do
                                if mprop isa MMethod then
+                                       if modelbuilder.toolcontext.opt_no_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
+                                               dead_methods.add(mprop)
+                                               continue
+                                       end
                                        mmethods[mclass].add(mprop)
                                else if mprop isa MAttribute then
                                        mattributes[mclass].add(mprop)
@@ -300,8 +328,8 @@ class SeparateCompiler
 
                # 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
+               if rta != null then
+                       super_calls = rta.live_super_sends
                else
                        super_calls = all_super_calls
                end
@@ -319,7 +347,10 @@ class SeparateCompiler
                self.method_tables = build_method_tables(mclasses, super_calls)
                self.compile_color_consts(method_layout.pos)
 
-               # attribute null color to dead supercalls
+               # attribute null color to dead methods and supercalls
+               for mproperty in dead_methods do
+                       compile_color_const(new_visitor, mproperty, -1)
+               end
                for mpropdef in all_super_calls do
                        if super_calls.has(mpropdef) then continue
                        compile_color_const(new_visitor, mpropdef, -1)
@@ -349,6 +380,7 @@ class SeparateCompiler
                                if parent == mclass then continue
                                for mproperty in self.mainmodule.properties(parent) do
                                        if not mproperty isa MMethod then continue
+                                       if not layout.pos.has_key(mproperty) then continue
                                        var color = layout.pos[mproperty]
                                        if table.length <= color then
                                                for i in [table.length .. color[ do
@@ -375,6 +407,7 @@ class SeparateCompiler
                        # then override with local properties
                        for mproperty in self.mainmodule.properties(mclass) do
                                if not mproperty isa MMethod then continue
+                               if not layout.pos.has_key(mproperty) then continue
                                var color = layout.pos[mproperty]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
@@ -606,6 +639,8 @@ class SeparateCompiler
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
+                               var rta = runtime_type_analysis
+                               if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
                                #print "compile {pd} @ {cd} @ {mmodule}"
                                var r = pd.separate_runtime_function
                                r.compile_to_c(self)
@@ -752,7 +787,8 @@ class SeparateCompiler
                var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
-               var is_dead = runtime_type_analysis != null and not runtime_type_analysis.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray"
+               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"
 
                v.add_decl("/* runtime class {c_name} */")
 
@@ -768,6 +804,10 @@ class SeparateCompiler
                                        v.add_decl("NULL, /* empty */")
                                else
                                        assert mpropdef isa MMethodDef
+                                       if rta != null and not rta.live_methoddefs.has(mpropdef) then
+                                               v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
+                                               continue
+                                       end
                                        var rf = mpropdef.virtual_runtime_function
                                        v.require_declaration(rf.c_name)
                                        v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
@@ -787,7 +827,7 @@ class SeparateCompiler
                                self.header.add_decl("\};")
                        end
 
-                       if not self.runtime_type_analysis.live_types.has(mtype) then return
+                       if not rta.live_types.has(mtype) then return
 
                        #Build BOX
                        self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
@@ -807,7 +847,8 @@ class SeparateCompiler
                        self.header.add_decl("struct instance_{c_instance_name} \{")
                        self.header.add_decl("const struct type *type;")
                        self.header.add_decl("const struct class *class;")
-                       # NativeArrays are just a instance header followed by an array of values
+                       # NativeArrays are just a instance header followed by a length and an array of values
+                       self.header.add_decl("int length;")
                        self.header.add_decl("val* values[0];")
                        self.header.add_decl("\};")
 
@@ -815,15 +856,16 @@ class SeparateCompiler
                        self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(int length, const struct type* type);")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{")
-                       var res = v.new_named_var(mtype, "self")
-                       res.is_exact = true
+                       var res = v.get_name("self")
+                       v.add_decl("struct instance_{c_instance_name} *{res};")
                        var mtype_elt = mtype.arguments.first
                        v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));")
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       v.add("return {res};")
+                       v.add("{res}->length = length;")
+                       v.add("return (val*){res};")
                        v.add("\}")
                        return
                end
@@ -876,7 +918,9 @@ class SeparateCompiler
                if self.modelbuilder.toolcontext.opt_tables_metrics.value then
                        display_sizes
                end
-
+               if self.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                       display_isset_checks
+               end
                var tc = self.modelbuilder.toolcontext
                tc.info("# implementation of method invocation",2)
                var nb_invok_total = modelbuilder.nb_invok_by_tables + modelbuilder.nb_invok_by_direct + modelbuilder.nb_invok_by_inline
@@ -929,15 +973,25 @@ class SeparateCompiler
                print "\t{total}\t{holes}"
        end
 
+       protected var isset_checks_count = 0
+       protected var attr_read_count = 0
+
+       fun display_isset_checks do
+               print "# total number of compiled attribute reads"
+               print "\t{attr_read_count}"
+               print "# total number of compiled isset-checks"
+               print "\t{isset_checks_count}"
+       end
+
        redef fun compile_nitni_structs
        do
                self.header.add_decl("struct nitni_instance \{struct instance *value;\};")
        end
        
-       redef fun finalize_ffi_for_module(nmodule)
+       redef fun finalize_ffi_for_module(mmodule)
        do
                var old_module = self.mainmodule
-               self.mainmodule = nmodule.mmodule.as(not null)
+               self.mainmodule = mmodule
                super
                self.mainmodule = old_module
        end
@@ -984,7 +1038,7 @@ class SeparateCompilerVisitor
                        self.require_declaration("BOX_{valtype.c_name}")
                        self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
                        return res
-               else if value.mtype.cname_blind == "void*" and mtype.cname_blind == "void*" then
+               else if value.mtype.ctype == "void*" and mtype.ctype == "void*" then
                        return value
                else
                        # Bad things will appen!
@@ -1012,13 +1066,21 @@ class SeparateCompilerVisitor
        do
                var rta = compiler.runtime_type_analysis
                var recv = args.first.mtype
-               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and recv isa MClassType then
+               if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null then
                        var tgs = rta.live_targets(callsite)
                        if tgs.length == 1 then
                                # DIRECT CALL
                                var mmethod = callsite.mproperty
                                self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args)
-                               return call(tgs.first, recv, args)
+                               var res0 = before_send(mmethod, args)
+                               var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
+                               if res0 != null then
+                                       assert res != null
+                                       self.assign(res0, res)
+                                       res = res0
+                               end
+                               add("\}") # close the before_send
+                               return res
                        end
                end
                return super
@@ -1125,8 +1187,8 @@ class SeparateCompilerVisitor
                        res = self.new_var(ret)
                end
 
-               var s = new Buffer
-               var ss = new Buffer
+               var s = new FlatBuffer
+               var ss = new FlatBuffer
 
                s.append("val*")
                ss.append("{recv}")
@@ -1284,6 +1346,11 @@ class SeparateCompilerVisitor
                var intromclassdef = a.intro.mclassdef
                ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
 
+               if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                       self.compiler.attr_read_count += 1
+                       self.add("count_attr_reads++;")
+               end
+
                self.require_declaration(a.const_color)
                if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
                        # Get the attribute or a box (ie. always a val*)
@@ -1294,10 +1361,15 @@ class SeparateCompilerVisitor
                        self.add("{res} = {recv}->attrs[{a.const_color}]; /* {a} on {recv.inspect} */")
 
                        # Check for Uninitialized attribute
-                       if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
+                       if 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("\}")
+
+                               if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                                       self.compiler.isset_checks_count += 1
+                                       self.add("count_isset_checks++;")
+                               end
                        end
 
                        # Return the attribute or its unboxed version
@@ -1308,10 +1380,14 @@ class SeparateCompilerVisitor
                        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_initialization.value then
+                       if ret.ctype == "val*" 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("\}")
+                               if self.compiler.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
+                                       self.compiler.isset_checks_count += 1
+                                       self.add("count_isset_checks++;")
+                               end
                        end
 
                        return res
@@ -1689,6 +1765,9 @@ class SeparateCompilerVisitor
                else if pname == "[]=" then
                        self.add("{recv}[{arguments[1]}]={arguments[2]};")
                        return
+               else if pname == "length" then
+                       self.ret(self.new_expr("((struct instance_{nclass.c_instance_name}*){arguments[0]})->length", ret_type.as(not null)))
+                       return
                else if pname == "copy_to" then
                        var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values"
                        self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
@@ -1759,8 +1838,8 @@ class SeparateRuntimeFunction
 
                var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
 
-               var sig = new Buffer
-               var comment = new Buffer
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
                var ret = msignature.return_mtype
                if ret != null then
                        sig.append("{ret.ctype} ")
@@ -1832,8 +1911,8 @@ class VirtualRuntimeFunction
                var frame = new Frame(v, mmethoddef, recv, arguments)
                v.frame = frame
 
-               var sig = new Buffer
-               var comment = new Buffer
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
 
                # Because the function is virtual, the signature must match the one of the original class
                var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef