X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/global_compiler.nit b/src/compiler/global_compiler.nit index 9a82243..7a0f162 100644 --- a/src/compiler/global_compiler.nit +++ b/src/compiler/global_compiler.nit @@ -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) @@ -405,7 +441,7 @@ class GlobalCompilerVisitor if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException self.add("if ({args.first} == NULL) \{ /* Special null case */") - if m.name == "==" then + if m.name == "==" or m.name == "is_same_instance" then assert res != null if args[1].mcasttype isa MNullableType then self.add("{res} = ({args[1]} == NULL);") @@ -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 @@ -942,7 +972,7 @@ private class CustomizedRuntimeFunction selfvar.is_exact = true end var arguments = new Array[RuntimeVariable] - var frame = new Frame(v, mmethoddef, recv, arguments) + var frame = new StaticFrame(v, mmethoddef, recv, arguments) v.frame = frame var sig = new FlatBuffer @@ -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,14 +1027,11 @@ 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 if self.mmethoddef.can_inline(v) then - var frame = new Frame(v, self.mmethoddef, self.recv, arguments) + var frame = new StaticFrame(v, self.mmethoddef, self.recv, arguments) frame.returnlabel = v.get_name("RET_LABEL") if ret != null then frame.returnvar = v.new_var(ret)