compiler: move compilation stuff from modelbuilder to the compiler
[nit.git] / src / compiler / global_compiler.nit
index 9a82243..0b42b7b 100644 (file)
@@ -59,35 +59,7 @@ redef class ModelBuilder
                self.toolcontext.info("*** GENERATING C ***", 1)
 
                var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
-               compiler.compile_header
-
-               for t in runtime_type_analysis.live_types do
-                       compiler.declare_runtimeclass(t)
-               end
-
-               compiler.compile_class_names
-
-               # Init instance code (allocate and init-arguments)
-               for t in runtime_type_analysis.live_types do
-                       if t.ctype == "val*" then
-                               compiler.generate_init_instance(t)
-                       else
-                               compiler.generate_box_instance(t)
-                       end
-               end
-
-               # The main function of the C
-               compiler.compile_nitni_global_ref_functions
-               compiler.compile_main_function
-
-               # Compile until all runtime_functions are visited
-               while not compiler.todos.is_empty do
-                       var m = compiler.todos.shift
-                       self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
-                       m.compile_to_c(compiler)
-               end
-               self.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
-
+               compiler.do_compilation
                compiler.display_stats
 
                var time1 = get_time
@@ -108,20 +80,59 @@ class GlobalCompiler
        # The result of the RTA (used to know live types and methods)
        var runtime_type_analysis: RapidTypeAnalysis
 
-       init(mainmodule: MModule, modelbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis)
+       init
        do
-               super(mainmodule, modelbuilder)
-               var file = new_file("{mainmodule.name}.nitgg")
+               var file = new_file("{mainmodule.c_name}.nitgg")
                self.header = new CodeWriter(file)
-               self.runtime_type_analysis = runtime_type_analysis
                self.live_primitive_types = new Array[MClassType]
                for t in runtime_type_analysis.live_types do
-                       if t.ctype != "val*" then
+                       if t.ctype != "val*" or t.mclass.name == "Pointer" then
                                self.live_primitive_types.add(t)
                        end
                end
        end
 
+       redef fun do_compilation
+       do
+               var compiler = self
+
+               compiler.compile_header
+
+               if mainmodule.model.get_mclasses_by_name("Pointer") != null then
+                       runtime_type_analysis.live_types.add(mainmodule.pointer_type)
+               end
+               for t in runtime_type_analysis.live_types do
+                       compiler.declare_runtimeclass(t)
+               end
+
+               compiler.compile_class_names
+
+               # Init instance code (allocate and init-arguments)
+               for t in runtime_type_analysis.live_types do
+                       if t.ctype == "val*" then
+                               compiler.generate_init_instance(t)
+                               if t.mclass.kind == extern_kind then
+                                       compiler.generate_box_instance(t)
+                               end
+                       else
+                               compiler.generate_box_instance(t)
+                       end
+               end
+
+               # The main function of the C
+               compiler.compile_nitni_global_ref_functions
+               compiler.compile_main_function
+
+               # Compile until all runtime_functions are visited
+               while not compiler.todos.is_empty do
+                       var m = compiler.todos.shift
+                       modelbuilder.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
+                       m.compile_to_c(compiler)
+               end
+               modelbuilder.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
+
+       end
+
        # Compile class names (for the class_name and output_class_name methods)
        protected fun compile_class_names do
                var v = new_visitor
@@ -157,7 +168,7 @@ class GlobalCompiler
 
        # Subset of runtime_type_analysis.live_types that contains only primitive types
        # Used to implement the equal test
-       var live_primitive_types: Array[MClassType]
+       var live_primitive_types: Array[MClassType] is noinit
 
        # Add a new todo task
        fun todo(m: AbstractRuntimeFunction)
@@ -193,11 +204,11 @@ class GlobalCompiler
                        v.add_decl("{mtype.arguments.first.ctype} values[1];")
                end
 
-               if mtype.ctype != "val*" then
+               if mtype.ctype_extern != "val*" then
                        # Is the Nit type is native then the struct is a box with two fields:
                        # * the `classid` to be polymorph
                        # * the `value` that contains the native value.
-                       v.add_decl("{mtype.ctype} value;")
+                       v.add_decl("{mtype.ctype_extern} value;")
                end
 
                # Collect all attributes and associate them a field in the structure.
@@ -252,7 +263,6 @@ class GlobalCompiler
        fun generate_box_instance(mtype: MClassType)
        do
                assert self.runtime_type_analysis.live_types.has(mtype)
-               assert mtype.ctype != "val*"
                var v = self.new_visitor
 
                self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
@@ -318,6 +328,34 @@ class GlobalCompilerVisitor
                end
        end
 
+       redef fun unbox_extern(value, mtype)
+       do
+               if mtype isa MClassType and mtype.mclass.kind == extern_kind and
+                  mtype.mclass.name != "NativeString" then
+                       var res = self.new_var_extern(mtype)
+                       self.add "{res} = ((struct {mtype.c_name}*){value})->value; /* unboxing {value.mtype} */"
+                       return res
+               else
+                       return value
+               end
+       end
+
+       redef fun box_extern(value, mtype)
+       do
+               if not mtype isa MClassType or mtype.mclass.kind != extern_kind or
+                       mtype.mclass.name == "NativeString" then return value
+
+               var valtype = value.mtype.as(MClassType)
+               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);")
+                       return res
+               end
+               self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
+               return res
+       end
+
        # The runtime types that are acceptable for a given receiver.
        fun collect_types(recv: RuntimeVariable): Array[MClassType]
        do
@@ -365,6 +403,7 @@ class GlobalCompilerVisitor
        redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
        do
                var ret_type = self.get_class("NativeArray").get_mtype([elttype])
+               ret_type = anchor(ret_type).as(MClassType)
                return self.new_expr("NEW_{ret_type.c_name}({length})", ret_type)
        end
 
@@ -379,10 +418,7 @@ class GlobalCompilerVisitor
 
                var res: nullable RuntimeVariable
                var ret = m.intro.msignature.return_mtype
-               if m.is_new then
-                       ret = args.first.mtype
-                       res = self.new_var(ret)
-               else if ret == null then
+               if ret == null then
                        res = null
                else
                        ret = self.resolve_for(ret, args.first)
@@ -487,43 +523,21 @@ class GlobalCompilerVisitor
                return recvtype
        end
 
-       # Subpart of old call function
-       # Gets the receiver boxed and casted if necessary
-       private fun get_recv(recvtype: MClassType, args: Array[RuntimeVariable]): RuntimeVariable
+       redef fun call(m, recvtype, args)
        do
-               return self.autoadapt(self.autobox(args.first, recvtype), recvtype)
-       end
+               var recv_type = get_recvtype(m, recvtype, args)
+               var recv = self.autoadapt(self.autobox(args.first, recvtype), recvtype)
+               if m.is_extern then recv = unbox_extern(recv, recv_type)
+
+               args = args.to_a
+               args.first = recv
 
-       # Finalizes a call to a method ´m´ on type ´recvtype´ with arguments ´args´
-       private fun finalize_call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
-       do
                assert args.length == m.msignature.arity + 1 else debug("Invalid arity for {m}. {args.length} arguments given.")
 
                var rm = new CustomizedRuntimeFunction(m, recvtype)
                return rm.call(self, args)
        end
 
-       redef fun call(m, recvtype, args)
-       do
-               var recv_type = get_recvtype(m, recvtype, args)
-               var recv = get_recv(recv_type, args)
-               var new_args = args.to_a
-               self.varargize(m, m.msignature.as(not null), new_args)
-               new_args.first = recv
-               return finalize_call(m, recv_type, new_args)
-       end
-
-       # Does a call without encapsulating varargs into an array
-       # Avoids multiple encapsulation when calling a super in a variadic function
-       fun call_without_varargize(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
-       do
-               var recv_type = get_recvtype(m, recvtype, args)
-               var recv = get_recv(recv_type, args)
-               var new_args = args.to_a
-               new_args.first = recv
-               return finalize_call(m, recv_type, new_args)
-       end
-
        redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
        do
                var types = self.collect_types(args.first)
@@ -545,7 +559,7 @@ class GlobalCompilerVisitor
                                return res
                        end
                        var propdef = m.lookup_next_definition(self.compiler.mainmodule, mclasstype)
-                       var res2 = self.call_without_varargize(propdef, mclasstype, args)
+                       var res2 = self.call(propdef, mclasstype, args)
                        if res != null then self.assign(res, res2.as(not null))
                        return res
                end
@@ -567,7 +581,7 @@ class GlobalCompilerVisitor
                        else
                                self.add("case {self.compiler.classid(t)}: /* test {t} */")
                        end
-                       var res2 = self.call_without_varargize(propdef, t, args)
+                       var res2 = self.call(propdef, t, args)
                        if res != null then self.assign(res, res2.as(not null))
                        self.add "break;"
                end
@@ -592,6 +606,19 @@ class GlobalCompilerVisitor
                end
        end
 
+       redef fun unbox_signature_extern(m, args)
+       do
+               var recv = args.first
+               for i in [0..m.msignature.arity[ do
+                       var t = m.msignature.mparameters[i].mtype
+                       if i == m.msignature.vararg_rank then
+                               t = args[i+1].mtype
+                       end
+                       t = self.resolve_for(t, recv)
+                       if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t)
+               end
+       end
+
        # FIXME: this is currently buggy since recv is not exact
        redef fun vararg_instance(mpropdef, recv, varargs, elttype)
        do
@@ -846,6 +873,15 @@ class GlobalCompilerVisitor
                                if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
                                s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
                        end
+
+                       if self.compiler.mainmodule.model.get_mclasses_by_name("Pointer") != null then
+                               var pointer_type = self.compiler.mainmodule.pointer_type
+                               if value1.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) or
+                                       value2.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) then
+                                       s.add "(((struct {pointer_type.c_name}*){value1})->value == ((struct {pointer_type.c_name}*){value2})->value)"
+                               end
+                       end
+
                        if s.is_empty then
                                self.add("{res} = {value1} == {value2};")
                        else
@@ -886,12 +922,6 @@ private class CustomizedRuntimeFunction
        # (usually is a live type but no strong guarantee)
        var recv: MClassType
 
-       init(mmethoddef: MMethodDef, recv: MClassType)
-       do
-               super(mmethoddef)
-               self.recv = recv
-       end
-
        redef fun build_c_name
        do
                var res = self.c_name_cache
@@ -951,9 +981,6 @@ private class CustomizedRuntimeFunction
                if ret != null then
                        ret = v.resolve_for(ret, selfvar)
                        sig.append("{ret.ctype} ")
-               else if mmethoddef.mproperty.is_new then
-                       ret = recv
-                       sig.append("{ret.ctype} ")
                else
                        sig.append("void ")
                end
@@ -1000,9 +1027,6 @@ private class CustomizedRuntimeFunction
        redef fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
                var ret = self.mmethoddef.msignature.return_mtype
-               if self.mmethoddef.mproperty.is_new then
-                       ret = recv
-               end
                if ret != null then
                        ret = v.resolve_for(ret, arguments.first)
                end