X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/global_compiler.nit b/src/compiler/global_compiler.nit index 4a4cbda..ede1beb 100644 --- a/src/compiler/global_compiler.nit +++ b/src/compiler/global_compiler.nit @@ -59,6 +59,43 @@ redef class ModelBuilder self.toolcontext.info("*** GENERATING C ***", 1) var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis) + compiler.do_compilation + compiler.display_stats + + var time1 = get_time + self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2) + write_and_make(compiler) + end +end + +# Compiler that use global compilation and perform hard optimisations like: +# * customization +# * switch dispatch +# * inlining +class GlobalCompiler + super AbstractCompiler + + redef type VISITOR: GlobalCompilerVisitor + + # The result of the RTA (used to know live types and methods) + var runtime_type_analysis: RapidTypeAnalysis + + init + do + var file = new_file("{mainmodule.c_name}.nitgg") + self.header = new CodeWriter(file) + self.live_primitive_types = new Array[MClassType] + for t in runtime_type_analysis.live_types do + if t.is_c_primitive 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 @@ -72,7 +109,7 @@ redef class ModelBuilder # Init instance code (allocate and init-arguments) for t in runtime_type_analysis.live_types do - if t.ctype == "val*" then + if not t.is_c_primitive then compiler.generate_init_instance(t) if t.mclass.kind == extern_kind then compiler.generate_box_instance(t) @@ -89,43 +126,11 @@ redef class ModelBuilder # 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) + modelbuilder.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.display_stats - - var time1 = get_time - self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2) - write_and_make(compiler) - end -end - -# Compiler that use global compilation and perform hard optimisations like: -# * customization -# * switch dispatch -# * inlining -class GlobalCompiler - super AbstractCompiler + modelbuilder.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2) - redef type VISITOR: GlobalCompilerVisitor - - # 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) - do - super(mainmodule, modelbuilder) - var file = new_file("{mainmodule.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*" or t.mclass.name == "Pointer" then - self.live_primitive_types.add(t) - end - end end # Compile class names (for the class_name and output_class_name methods) @@ -163,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) @@ -223,7 +228,7 @@ class GlobalCompiler fun generate_init_instance(mtype: MClassType) do assert self.runtime_type_analysis.live_types.has(mtype) - assert mtype.ctype == "val*" + assert not mtype.is_c_primitive var v = self.new_visitor var is_native_array = mtype.mclass.name == "NativeArray" @@ -298,16 +303,16 @@ class GlobalCompilerVisitor do if value.mtype == mtype then return value - else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then + else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then return value - else if value.mtype.ctype == "val*" then + else if not value.mtype.is_c_primitive then return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) - else if mtype.ctype == "val*" then + else if not mtype.is_c_primitive then var valtype = value.mtype.as(MClassType) 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} */") @@ -318,7 +323,7 @@ class GlobalCompilerVisitor # 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 @@ -344,7 +349,7 @@ class GlobalCompilerVisitor 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} */") @@ -397,10 +402,24 @@ class GlobalCompilerVisitor 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 + redef fun native_array_get(nat, i) + do + var recv = "((struct {nat.mcasttype.c_name}*){nat})->values" + var ret_type = nat.mcasttype.as(MClassType).arguments.first + return self.new_expr("{recv}[{i}]", ret_type) + end + + redef fun native_array_set(nat, i, val) + do + var recv = "((struct {nat.mcasttype.c_name}*){nat})->values" + self.add("{recv}[{i}]={val};") + end + redef fun calloc_array(ret_type, arguments) do self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type)) @@ -412,10 +431,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) @@ -423,7 +439,7 @@ class GlobalCompilerVisitor end self.add("/* send {m} on {args.first.inspect} */") - if args.first.mtype.ctype != "val*" then + if args.first.mtype.is_c_primitive then var mclasstype = args.first.mtype.as(MClassType) if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then self.add("/* skip, no method {m} */") @@ -438,7 +454,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);") @@ -474,7 +490,7 @@ class GlobalCompilerVisitor var defaultpropdef: nullable MMethodDef = null for t in types do var propdef = m.lookup_first_definition(self.compiler.mainmodule, t) - if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then + if propdef.mclassdef.mclass.name == "Object" and not t.is_c_primitive then defaultpropdef = propdef continue end @@ -512,52 +528,24 @@ class GlobalCompilerVisitor private fun get_recvtype(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): MClassType do check_valid_reciever(recvtype) - #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}") - if m.mproperty.is_toplevel then - # Do not customize top-level methods - recvtype = m.mclassdef.bound_mtype - end 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) - if m.is_extern then recv = unbox_extern(recv, recv_type) - var new_args = args.to_a - 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) - if m.is_extern then recv = unbox_extern(recv, recv_type) - 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) @@ -572,14 +560,14 @@ class GlobalCompilerVisitor end self.add("/* super {m} on {args.first.inspect} */") - if args.first.mtype.ctype != "val*" then + if args.first.mtype.is_c_primitive then var mclasstype = args.first.mtype.as(MClassType) if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then self.add("/* skip, no method {m} */") 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 @@ -601,7 +589,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 @@ -648,9 +636,9 @@ class GlobalCompilerVisitor fun bugtype(recv: RuntimeVariable) do - if recv.mtype.ctype != "val*" then return + if recv.mtype.is_c_primitive 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) @@ -679,7 +667,7 @@ class GlobalCompilerVisitor ta = self.resolve_for(ta, recv2) var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta) if not ta isa MNullableType then - if ta.ctype == "val*" then + if not ta.is_c_primitive then self.add("{res} = ({attr} != NULL);") else self.add("{res} = 1; /*NOTYET isset on primitive attributes*/") @@ -725,7 +713,7 @@ class GlobalCompilerVisitor ta = self.resolve_for(ta, recv2) var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta) if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then - if ta.ctype == "val*" then + if not ta.is_c_primitive then self.add("if ({res2} == NULL) \{") self.add_abort("Uninitialized attribute {a.name}") self.add("\}") @@ -801,7 +789,7 @@ class GlobalCompilerVisitor var res = self.new_var(bool_type) self.add("/* isa {mtype} on {value.inspect} */") - if value.mtype.ctype != "val*" then + if value.mtype.is_c_primitive then if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then self.add("{res} = 1;") else @@ -836,14 +824,14 @@ class GlobalCompilerVisitor redef fun is_same_type_test(value1, value2) do var res = self.new_var(bool_type) - if value2.mtype.ctype == "val*" then - if value1.mtype.ctype == "val*" then + if not value2.mtype.is_c_primitive then + if not value1.mtype.is_c_primitive then self.add "{res} = {value1}->classid == {value2}->classid;" else self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;" end else - if value1.mtype.ctype == "val*" then + if not value1.mtype.is_c_primitive then self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};" else if value1.mcasttype == value2.mcasttype then self.add "{res} = 1;" @@ -858,7 +846,7 @@ class GlobalCompilerVisitor do var res = self.get_name("var_class_name") self.add_decl("const char* {res};") - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then self.add "{res} = class_names[{value}->classid];" else self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];" @@ -869,15 +857,15 @@ class GlobalCompilerVisitor redef fun equal_test(value1, value2) do var res = self.new_var(bool_type) - if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then + if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then var tmp = value1 value1 = value2 value2 = tmp end - if value1.mtype.ctype != "val*" then + if value1.mtype.is_c_primitive then if value2.mtype == value1.mtype then self.add("{res} = {value1} == {value2};") - else if value2.mtype.ctype != "val*" then + else if value2.mtype.is_c_primitive then self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/") else var mtype1 = value1.mtype.as(MClassType) @@ -914,10 +902,10 @@ class GlobalCompilerVisitor 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 @@ -942,12 +930,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 @@ -998,7 +980,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 @@ -1007,9 +989,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 @@ -1020,7 +999,7 @@ private class CustomizedRuntimeFunction 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}") @@ -1056,14 +1035,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)