X-Git-Url: http://nitlanguage.org diff --git a/src/global_compiler.nit b/src/global_compiler.nit index 3a9a590..df8be17 100644 --- a/src/global_compiler.nit +++ b/src/global_compiler.nit @@ -94,8 +94,11 @@ redef class ModelBuilder # Init instance code (allocate and init-arguments) for t in runtime_type_analysis.live_types do - if t.ctype != "val*" then continue # skip primitive types - compiler.generate_init_instance(t) + if t.ctype == "val*" then + compiler.generate_init_instance(t) + else + compiler.generate_box_instance(t) + end end # The main function of the C @@ -118,6 +121,7 @@ redef class ModelBuilder if main_method != null then v.send(main_method, [glob_sys]) end + v.add("return 0;") v.add("\}") # Compile until all runtime_functions are visited @@ -125,13 +129,23 @@ redef class ModelBuilder 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, self) + m.compile_to_c(compiler) end self.toolcontext.info("Total methods to compile to C: {compiler.visitors.length}", 2) + var time1 = get_time + self.toolcontext.info("*** END VISITING: {time1-time0} ***", 2) + write_and_make(compiler) + end + + private fun write_and_make(compiler: GlobalCompiler) + do + var mainmodule = compiler.mainmodule + # Generate the .h and .c files # A single C file regroups many compiled rumtime functions # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files + var time0 = get_time var outname = self.toolcontext.opt_output.value if outname == null then @@ -202,7 +216,7 @@ redef class ModelBuilder ofiles.add(o) end # Link edition - makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) $(LDLIBS) -o {outname} {ofiles.join(" ")}\n\n") + makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n") # Clean makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n") makefile.close @@ -366,6 +380,23 @@ private class GlobalCompiler v.add("\}") end + fun generate_box_instance(mtype: MClassType) + do + assert self.runtime_type_analysis.live_types.has(mtype) + assert mtype.ctype != "val*" + var v = new GlobalCompilerVisitor(self) + + self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});") + v.add_decl("/* allocate {mtype} */") + v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{") + v.add("struct {mtype.c_name}*res = GC_MALLOC(sizeof(struct {mtype.c_name}));") + v.add("res->classid = {self.classid(mtype)};") + v.add("res->value = value;") + v.add("return (val*)res;") + v.add("\}") + + end + # look for a needed .h and .c file for a given .nit source-file # FIXME: bad API, parameter should be a MModule, not its source-file fun add_extern(file: String) @@ -535,7 +566,7 @@ private abstract class RuntimeFunction # Generate the code for the RuntimeFunction # Warning: compile more than once compilation makes CC unhappy - fun compile_to_c(compiler: GlobalCompiler, modelbuilder: ModelBuilder) is abstract + fun compile_to_c(compiler: GlobalCompiler) is abstract end # A runtime function customized on a specific monomrph receiver type @@ -593,16 +624,81 @@ private class CustomizedRuntimeFunction end end - redef fun compile_to_c(compiler, modelbuilder) + # compile the code customized for the reciever + redef fun compile_to_c(compiler) do - self.mmethoddef.compile_to_c(compiler, modelbuilder, self.recv) + var recv = self.recv + var mmethoddef = self.mmethoddef + if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then + print("problem: why do we compile {self} for {recv}?") + abort + end + + var v = new GlobalCompilerVisitor(compiler) + var selfvar = new RuntimeVariable("self", recv, recv) + if compiler.runtime_type_analysis.live_types.has(recv) then + selfvar.is_exact = true + end + var arguments = new Array[RuntimeVariable] + var frame = new Frame(v, mmethoddef, recv, arguments) + v.frame = frame + + var sig = new Buffer + var comment = new Buffer + var ret = mmethoddef.msignature.return_mtype + 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 + sig.append(self.c_name) + sig.append("({recv.ctype} self") + comment.append("(self: {recv}") + arguments.add(selfvar) + 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]) + end + mtype = v.resolve_for(mtype, selfvar) + comment.append(", {mtype}") + sig.append(", {mtype.ctype} p{i}") + var argvar = new RuntimeVariable("p{i}", mtype, mtype) + arguments.add(argvar) + end + sig.append(")") + comment.append(")") + if ret != null then + comment.append(": {ret}") + end + compiler.header.add_decl("{sig};") + + v.add_decl("/* method {self} for {comment} */") + v.add_decl("{sig} \{") + #v.add("printf(\"method {self} for {comment}\\n\");") + if ret != null then + frame.returnvar = v.new_var(ret) + end + frame.returnlabel = v.get_name("RET_LABEL") + + mmethoddef.compile_inside_to_c(v, arguments) + + v.add("{frame.returnlabel.as(not null)}:;") + if ret != null then + v.add("return {frame.returnvar.as(not null)};") + end + v.add("\}") end redef fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do var ret = self.mmethoddef.msignature.return_mtype if self.mmethoddef.mproperty.is_new then - ret = arguments.first.mtype + ret = recv end if ret != null then ret = v.resolve_for(ret, arguments.first) @@ -653,6 +749,15 @@ private class RuntimeVariable # false (usual value) means that the variable is a mcasttype or a subtype. var is_exact: Bool = false + init(name: String, mtype: MType, mcasttype: MType) + do + self.name = name + self.mtype = mtype + self.mcasttype = mcasttype + assert not mtype.need_anchor + assert not mcasttype.need_anchor + end + redef fun to_s do return name redef fun inspect @@ -700,7 +805,7 @@ private class GlobalCompilerVisitor # Force to get the primitive property named `name' in the instance `recv' or abort fun get_property(name: String, recv: MType): MMethod do - return self.compiler.mainmodule.force_get_primitive_method(name, recv) + return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule) end # The current Frame @@ -755,16 +860,16 @@ private class GlobalCompilerVisitor fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable do mtype = self.anchor(mtype) - if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then + var valmtype = value.mcasttype + if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then return value end - var valmtype = value.mtype if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then - var res = new RuntimeVariable(value.name, value.mtype, valmtype.mtype) + var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype) return res else - var res = new RuntimeVariable(value.name, value.mtype, mtype) + var res = new RuntimeVariable(value.name, valmtype, mtype) return res end end @@ -785,9 +890,7 @@ private class GlobalCompilerVisitor self.add("printf(\"Dead code executed!\\n\"); exit(1);") return res end - self.add("{res} = GC_MALLOC(sizeof(struct {valtype.c_name})); /* autobox from {value.mtype} to {mtype} */") - self.add("{res}->classid = {self.compiler.classid(valtype)};") - self.add("((struct {valtype.c_name}*){res})->value = {value};") + self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */") return res else # Bad things will appen! @@ -838,11 +941,7 @@ private class GlobalCompilerVisitor # Return a new uninitialized local runtime_variable fun new_var(mtype: MType): RuntimeVariable do - if mtype isa MNullType then - mtype = self.object_type - else - mtype = self.anchor(mtype) - end + mtype = self.anchor(mtype) var name = self.get_name("var") var res = new RuntimeVariable(name, mtype, mtype) self.add_decl("{mtype.ctype} {name} /* : {mtype} */;") @@ -986,18 +1085,23 @@ private class GlobalCompilerVisitor return res end if args.first.mcasttype isa MNullableType 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 assert res != null - if args[1].mcasttype.ctype == "val*" then + if args[1].mcasttype isa MNullableType then self.add("{res} = ({args[1]} == NULL);") + else if args[1].mcasttype isa MNullType then + self.add("{res} = 1; /* is null */") else self.add("{res} = 0; /* {args[1].inspect} cannot be null */") end else if m.name == "!=" then assert res != null - if args[1].mcasttype.ctype == "val*" then + if args[1].mcasttype isa MNullableType then self.add("{res} = ({args[1]} != NULL);") + else if args[1].mcasttype isa MNullType then + self.add("{res} = 0; /* is null */") else self.add("{res} = 1; /* {args[1].inspect} cannot be null */") end @@ -1015,6 +1119,9 @@ private class GlobalCompilerVisitor self.add("/* skip {t}, no method {m} */") continue end + if propdefs.length > 1 then + self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first") + end var propdef = propdefs.first if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then defaultpropdef = propdef @@ -1041,6 +1148,21 @@ private class GlobalCompilerVisitor return res end + # Generate a monomorphic send for the method `m', the type `t' and the arguments `args' + fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable + do + assert t isa MClassType + var propdefs = m.lookup_definitions(self.compiler.mainmodule, t) + if propdefs.length == 0 then + abort + end + if propdefs.length > 1 then + self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first") + end + var propdef = propdefs.first + return self.call(propdef, t, args) + end + fun check_valid_reciever(recvtype: MClassType) do if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return @@ -1087,7 +1209,11 @@ private class GlobalCompilerVisitor else args = args.to_a end - assert args.length == m.msignature.arity + 1 # because of self + if args.length != m.msignature.arity + 1 then # because of self + add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);") + debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.") + return null + end args.first = recv var rm = new CustomizedRuntimeFunction(m, recvtype) @@ -1291,7 +1417,8 @@ private class GlobalCompilerVisitor fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable do elttype = self.anchor(elttype) - var res = self.init_instance(self.get_class("Array").get_mtype([elttype])) + var arraytype = self.get_class("Array").get_mtype([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])) nat.is_exact = true @@ -1301,7 +1428,7 @@ private class GlobalCompilerVisitor self.add("{nat}[{i}] = {r};") end var length = self.int_instance(array.length) - self.send(self.get_property("with_native", res.mtype), [res, nat, length]) + self.send(self.get_property("with_native", arraytype), [res, nat, length]) self.check_init_instance(res) self.add("\}") return res @@ -1322,7 +1449,7 @@ private class GlobalCompilerVisitor var res2 = self.init_instance(mtype) self.add("{res} = {res2};") var length = self.int_instance(string.length) - self.send(self.get_property("with_native", res.mtype), [res, nat, length]) + self.send(self.get_property("with_native", mtype), [res, nat, length]) self.check_init_instance(res) self.add("{name} = {res};") self.add("\}") @@ -1410,77 +1537,6 @@ redef class MMethodDef end return null end - - # Compile the body in a new visitor - private fun compile_to_c(compiler: GlobalCompiler, modelbuilder: ModelBuilder, recv: MClassType) - do - if not recv.is_subtype(compiler.mainmodule, null, self.mclassdef.bound_mtype) then - print("problem: why do we compile {self} for {recv}?") - abort - end - - var v = new GlobalCompilerVisitor(compiler) - var selfvar = new RuntimeVariable("self", recv, recv) - if compiler.runtime_type_analysis.live_types.has(recv) then - selfvar.is_exact = true - end - var arguments = new Array[RuntimeVariable] - var frame = new Frame(v, self, recv, arguments) - v.frame = frame - - var sig = new Buffer - var comment = new Buffer - var ret = self.msignature.return_mtype - if ret != null then - ret = v.resolve_for(ret, selfvar) - sig.append("{ret.ctype} ") - else if self.mproperty.is_new then - ret = recv - sig.append("{ret.ctype} ") - else - sig.append("void ") - end - sig.append(self.c_name) - if recv != self.mclassdef.bound_mtype then - sig.append("__{recv.c_name}") - end - sig.append("({recv.ctype} self") - comment.append("(self: {recv}") - arguments.add(selfvar) - for i in [0..self.msignature.arity[ do - var mtype = self.msignature.mparameters[i].mtype - if i == self.msignature.vararg_rank then - mtype = v.get_class("Array").get_mtype([mtype]) - end - mtype = v.resolve_for(mtype, selfvar) - comment.append(", {mtype}") - sig.append(", {mtype.ctype} p{i}") - var argvar = new RuntimeVariable("p{i}", mtype, mtype) - arguments.add(argvar) - end - sig.append(")") - comment.append(")") - if ret != null then - comment.append(": {ret}") - end - compiler.header.add_decl("{sig};") - - v.add_decl("/* method {self} for {comment} */") - v.add_decl("{sig} \{") - #v.add("printf(\"method {self} for {comment}\\n\");") - if ret != null then - frame.returnvar = v.new_var(ret) - end - frame.returnlabel = v.get_name("RET_LABEL") - - self.compile_inside_to_c(v, arguments) - - v.add("{frame.returnlabel.as(not null)}:;") - if ret != null then - v.add("return {frame.returnvar.as(not null)};") - end - v.add("\}") - end end redef class APropdef @@ -1790,7 +1846,7 @@ redef class AInternMethPropdef end return end - v.add("printf(\"NOT IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");") + v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");") debug("Not implemented {mpropdef}") end end @@ -2424,6 +2480,7 @@ redef class ASuperExpr # FIXME: we do not want an ugly static call! var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype) if mpropdefs.length != 1 then + v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");") debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}") end mpropdef = mpropdefs.first