X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index fe348b4..c3952e3 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -120,20 +120,16 @@ redef class ModelBuilder # Simple indirection to `Toolchain::write_and_make` protected fun write_and_make(compiler: AbstractCompiler) do - var platform = compiler.mainmodule.target_platform - var toolchain - if platform == null then - toolchain = new MakefileToolchain(toolcontext) - else - toolchain = platform.toolchain(toolcontext) - end + var platform = compiler.target_platform + var toolchain = platform.toolchain(toolcontext) compile_dir = toolchain.compile_dir toolchain.write_and_make compiler end end redef class Platform - fun toolchain(toolcontext: ToolContext): Toolchain is abstract + # The specific tool-chain associated to the platform + fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext) end class Toolchain @@ -189,10 +185,10 @@ class MakefileToolchain fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) do - var platform = compiler.mainmodule.target_platform - if self.toolcontext.opt_stacktrace.value == "nitstack" and (platform == null or platform.supports_libunwind) then compiler.build_c_to_nit_bindings + var platform = compiler.target_platform + if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings var cc_opt_with_libgc = "-DWITH_LIBGC" - if platform != null and not platform.supports_libgc then cc_opt_with_libgc = "" + if not platform.supports_libgc then cc_opt_with_libgc = "" # Add gc_choser.h to aditionnal bodies var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc) @@ -216,7 +212,7 @@ class MakefileToolchain var hfilename = compiler.header.file.name + ".h" var hfilepath = "{compile_dir}/{hfilename}" - var h = new OFStream.open(hfilepath) + var h = new FileWriter.open(hfilepath) for l in compiler.header.decl_lines do h.write l h.write "\n" @@ -231,7 +227,7 @@ class MakefileToolchain for f in compiler.files do var i = 0 var count = 0 - var file: nullable OFStream = null + var file: nullable FileWriter = null for vis in f.writers do if vis == compiler.header then continue var total_lines = vis.lines.length + vis.decl_lines.length @@ -244,7 +240,7 @@ class MakefileToolchain var cfilepath = "{compile_dir}/{cfilename}" self.toolcontext.info("new C source files to compile: {cfilepath}", 3) cfiles.add(cfilename) - file = new OFStream.open(cfilepath) + file = new FileWriter.open(cfilepath) file.write "#include \"{f.name}.0.h\"\n" count = total_lines end @@ -262,8 +258,8 @@ class MakefileToolchain var cfilename = "{f.name}.0.h" var cfilepath = "{compile_dir}/{cfilename}" - var hfile: nullable OFStream = null - hfile = new OFStream.open(cfilepath) + var hfile: nullable FileWriter = null + hfile = new FileWriter.open(cfilepath) hfile.write "#include \"{hfilename}\"\n" for key in f.required_declarations do if not compiler.provided_declarations.has_key(key) then @@ -311,7 +307,7 @@ class MakefileToolchain fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) do var mainmodule = compiler.mainmodule - var platform = compiler.mainmodule.target_platform + var platform = compiler.target_platform var outname = outfile(mainmodule) @@ -325,7 +321,7 @@ class MakefileToolchain end var makename = makefile_name(mainmodule) var makepath = "{compile_dir}/{makename}" - var makefile = new OFStream.open(makepath) + var makefile = new FileWriter.open(makepath) var linker_options = new HashSet[String] for m in mainmodule.in_importation.greaters do @@ -336,7 +332,7 @@ class MakefileToolchain makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") var ost = toolcontext.opt_stacktrace.value - if (ost == "libunwind" or ost == "nitstack") and (platform == null or platform.supports_libunwind) then makefile.write("NEED_LIBUNWIND := YesPlease\n") + if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n") # Dynamic adaptations # While `platform` enable complex toolchains, they are statically applied @@ -375,7 +371,7 @@ class MakefileToolchain if not compiler.linker_script.is_empty then var linker_script_path = "{compile_dir}/linker_script" ofiles.add "linker_script" - var f = new OFStream.open(linker_script_path) + var f = new FileWriter.open(linker_script_path) for l in compiler.linker_script do f.write l f.write "\n" @@ -488,9 +484,13 @@ abstract class AbstractCompiler # Is hardening asked? (see --hardening) fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value + # The targeted specific platform + var target_platform: Platform is noinit + init do self.realmainmodule = mainmodule + target_platform = mainmodule.target_platform or else new Platform end # Do the full code generation of the program `mainmodule` @@ -546,7 +546,7 @@ abstract class AbstractCompiler do var compile_dir = modelbuilder.compile_dir - var stream = new OFStream.open("{compile_dir}/c_functions_hash.c") + var stream = new FileWriter.open("{compile_dir}/c_functions_hash.c") stream.write("#include \n") stream.write("#include \n") stream.write("#include \"c_functions_hash.h\"\n") @@ -576,7 +576,7 @@ abstract class AbstractCompiler stream.write("\}\n") stream.close - stream = new OFStream.open("{compile_dir}/c_functions_hash.h") + stream = new FileWriter.open("{compile_dir}/c_functions_hash.h") stream.write("const char* get_nit_name(register const char* procname, register unsigned int len);\n") stream.close @@ -603,9 +603,9 @@ abstract class AbstractCompiler var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value if gccd_disable.has("noreturn") or gccd_disable.has("all") then # Signal handler function prototype - self.header.add_decl("void show_backtrace(int);") + self.header.add_decl("void fatal_exit(int);") else - self.header.add_decl("void show_backtrace(int) __attribute__ ((noreturn));") + self.header.add_decl("void fatal_exit(int) __attribute__ ((noreturn));") end if gccd_disable.has("likely") or gccd_disable.has("all") then @@ -697,11 +697,11 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); var v = self.new_visitor v.add_decl("#include ") var ost = modelbuilder.toolcontext.opt_stacktrace.value - var platform = mainmodule.target_platform + var platform = target_platform - if platform != null and not platform.supports_libunwind then ost = "none" + if not platform.supports_libunwind then ost = "none" - var no_main = (platform != null and platform.no_main) or modelbuilder.toolcontext.opt_no_main.value + var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value if ost == "nitstack" or ost == "libunwind" then v.add_decl("#define UNW_LOCAL_ONLY") @@ -741,12 +741,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.compiler.header.add_decl("extern long count_isset_checks;") end - v.add_decl("void sig_handler(int signo)\{") - v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));") - v.add_decl("show_backtrace(signo);") - v.add_decl("\}") - - v.add_decl("void show_backtrace (int signo) \{") + v.add_decl("static void show_backtrace(void) \{") if ost == "nitstack" or ost == "libunwind" then v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");") v.add_decl("unw_cursor_t cursor;") @@ -776,7 +771,19 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add_decl("free(procname);") v.add_decl("\}") end - v.add_decl("exit(signo);") + v.add_decl("\}") + + v.add_decl("void sig_handler(int signo)\{") + v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));") + v.add_decl("show_backtrace();") + # rethrows + v.add_decl("signal(signo, SIG_DFL);") + v.add_decl("kill(getpid(), signo);") + v.add_decl("\}") + + v.add_decl("void fatal_exit(int status) \{") + v.add_decl("show_backtrace();") + v.add_decl("exit(status);") v.add_decl("\}") if no_main then @@ -856,6 +863,12 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add("return 0;") v.add("\}") + + for m in mainmodule.in_importation.greaters do + var f = "FILE_"+m.c_name + v.add "const char {f}[] = \"{m.location.file.filename.escape_to_c}\";" + provide_declaration(f, "extern const char {f}[];") + end end # Copile all C functions related to the [incr|decr]_ref features of the FFI @@ -1056,8 +1069,8 @@ abstract class AbstractCompilerVisitor # The current visited AST node var current_node: nullable ANode = null is writable - # The current `Frame` - var frame: nullable Frame = null is writable + # The current `StaticFrame` + var frame: nullable StaticFrame = null is writable # Alias for self.compiler.mainmodule.object_type fun object_type: MClassType do return self.compiler.mainmodule.object_type @@ -1072,9 +1085,6 @@ abstract class AbstractCompilerVisitor self.writer = new CodeWriter(compiler.files.last) end - # Force to get the primitive class named `name` or abort - fun get_class(name: String): MClass do return self.compiler.mainmodule.get_primitive_class(name) - # Force to get the primitive property named `name` in the instance `recv` or abort fun get_property(name: String, recv: MType): MMethod do @@ -1381,6 +1391,24 @@ abstract class AbstractCompilerVisitor # Generate a alloc-instance + init-attributes fun init_instance(mtype: MClassType): RuntimeVariable is abstract + # Allocate and init attributes of an instance of a standard or extern class + # + # Does not support universals and the pseudo-internal `NativeArray` class. + fun init_instance_or_extern(mtype: MClassType): RuntimeVariable + do + var recv + var ctype = mtype.ctype + assert mtype.mclass.name != "NativeArray" + if not mtype.is_c_primitive then + recv = init_instance(mtype) + else if ctype == "char*" then + recv = new_expr("NULL/*special!*/", mtype) + else + recv = new_expr("({ctype})0/*special!*/", mtype) + end + return recv + end + # Set a GC finalizer on `recv`, only if `recv` isa Finalizable fun set_finalizer(recv: RuntimeVariable) do @@ -1392,37 +1420,64 @@ abstract class AbstractCompilerVisitor end end + # The currently processed module + # + # alias for `compiler.mainmodule` + fun mmodule: MModule do return compiler.mainmodule + # Generate an integer value fun int_instance(value: Int): RuntimeVariable do - var res = self.new_var(self.get_class("Int").mclass_type) - self.add("{res} = {value};") + var t = mmodule.int_type + var res = new RuntimeVariable("{value.to_s}l", t, t) + return res + end + + # Generate a char value + fun char_instance(value: Char): RuntimeVariable + do + var t = mmodule.char_type + var res = new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t) + return res + end + + # Generate a float value + # + # FIXME pass a Float, not a string + fun float_instance(value: String): RuntimeVariable + do + var t = mmodule.float_type + var res = new RuntimeVariable("{value}", t, t) return res end # Generate an integer value fun bool_instance(value: Bool): RuntimeVariable do - var res = self.new_var(self.get_class("Bool").mclass_type) - if value then - self.add("{res} = 1;") - else - self.add("{res} = 0;") - end + var s = if value then "1" else "0" + var res = new RuntimeVariable(s, bool_type, bool_type) + return res + end + + # Generate the `null` value + fun null_instance: RuntimeVariable + do + var t = compiler.mainmodule.model.null_type + var res = new RuntimeVariable("((val*)NULL)", t, t) return res end # Generate a string value fun string_instance(string: String): RuntimeVariable do - var mtype = self.get_class("String").mclass_type + var mtype = mmodule.string_type var name = self.get_name("varonce") self.add_decl("static {mtype.ctype} {name};") var res = self.new_var(mtype) - self.add("if ({name}) \{") + self.add("if (likely({name}!=NULL)) \{") self.add("{res} = {name};") self.add("\} else \{") - var native_mtype = self.get_class("NativeString").mclass_type + var native_mtype = mmodule.native_string_type var nat = self.new_var(native_mtype) self.add("{nat} = \"{string.escape_to_c}\";") var length = self.int_instance(string.length) @@ -1525,12 +1580,15 @@ abstract class AbstractCompilerVisitor fun add_raw_abort do - if self.current_node != null and self.current_node.location.file != null then - self.add("PRINT_ERROR(\" (%s:%d)\\n\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});") + if self.current_node != null and self.current_node.location.file != null and + self.current_node.location.file.mmodule != null then + var f = "FILE_{self.current_node.location.file.mmodule.c_name}" + self.require_declaration(f) + self.add("PRINT_ERROR(\" (%s:%d)\\n\", {f}, {current_node.location.line_start});") else self.add("PRINT_ERROR(\"\\n\");") end - self.add("show_backtrace(1);") + self.add("fatal_exit(1);") end # Add a dynamic cast @@ -1686,8 +1744,8 @@ class RuntimeVariable end end -# A frame correspond to a visited property in a `GlobalCompilerVisitor` -class Frame +# The static context of a visited property in a `AbstractCompilerVisitor` +class StaticFrame type VISITOR: AbstractCompilerVisitor @@ -1727,12 +1785,16 @@ redef class MType # Short name of the `ctype` to use in unions fun ctypename: String do return "val" + + # Is the associated C type a primitive one? + # + # ENSURE `result == (ctype != "val*")` + fun is_c_primitive: Bool do return false end redef class MClassType - redef fun ctype: String - do + redef var ctype is lazy do if mclass.name == "Int" then return "long" else if mclass.name == "Bool" then @@ -1750,6 +1812,8 @@ redef class MClassType end end + redef var is_c_primitive is lazy do return ctype != "val*" + redef fun ctype_extern: String do if mclass.kind == extern_kind then @@ -1807,6 +1871,15 @@ redef class MMethodDef var modelbuilder = v.compiler.modelbuilder var val = constant_value var node = modelbuilder.mpropdef2node(self) + + if is_abstract then + var cn = v.class_name_string(arguments.first) + v.current_node = node + v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mproperty.name.escape_to_c}\", {cn});") + v.add_raw_abort + return null + end + if node isa APropdef then var oldnode = v.current_node v.current_node = node @@ -1866,13 +1939,6 @@ end redef class AMethPropdef redef fun compile_to_c(v, mpropdef, arguments) do - if mpropdef.is_abstract then - var cn = v.class_name_string(arguments.first) - v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});") - v.add_raw_abort - return - end - # Call the implicit super-init var auto_super_inits = self.auto_super_inits if auto_super_inits != null then @@ -2237,7 +2303,7 @@ redef class AAttrPropdef if is_lazy then var set var ret = self.mpropdef.static_mtype - var useiset = ret.ctype == "val*" and not ret isa MNullableType + var useiset = not ret.is_c_primitive and not ret isa MNullableType var guard = self.mlazypropdef.mproperty if useiset then set = v.isset_attribute(self.mpropdef.mproperty, recv) @@ -2252,7 +2318,7 @@ redef class AAttrPropdef v.assign(res, value) if not useiset then - var true_v = v.new_expr("1", v.bool_type) + var true_v = v.bool_instance(true) v.write_attribute(guard, arguments.first, true_v) end v.add("\}") @@ -2265,9 +2331,9 @@ redef class AAttrPropdef v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1]) if is_lazy then var ret = self.mpropdef.static_mtype - var useiset = ret.ctype == "val*" and not ret isa MNullableType + var useiset = not ret.is_c_primitive and not ret isa MNullableType if not useiset then - v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.new_expr("1", v.bool_type)) + v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true)) end end else @@ -2277,7 +2343,7 @@ redef class AAttrPropdef fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable) do - if has_value and not is_lazy then evaluate_expr(v, recv) + if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv) end # Evaluate, store and return the default value of the attribute @@ -2286,7 +2352,7 @@ redef class AAttrPropdef var oldnode = v.current_node v.current_node = self var old_frame = v.frame - var frame = new Frame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv]) + var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv]) v.frame = frame var value @@ -2325,7 +2391,7 @@ redef class AAttrPropdef var oldnode = v.current_node v.current_node = self var old_frame = v.frame - var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv]) + var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv]) v.frame = frame # Force read to check the initialization v.read_attribute(self.mpropdef.mproperty, recv) @@ -2665,15 +2731,15 @@ redef class AOrElseExpr end redef class AIntExpr - redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null)) + redef fun expr(v) do return v.int_instance(self.value.as(not null)) end redef class AFloatExpr - redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float + redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float end redef class ACharExpr - redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null)) + redef fun expr(v) do return v.char_instance(self.value.as(not null)) end redef class AArrayExpr @@ -2738,15 +2804,15 @@ redef class AOrangeExpr end redef class ATrueExpr - redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null)) + redef fun expr(v) do return v.bool_instance(true) end redef class AFalseExpr - redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null)) + redef fun expr(v) do return v.bool_instance(false) end redef class ANullExpr - redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null)) + redef fun expr(v) do return v.null_instance end redef class AIsaExpr @@ -2774,7 +2840,7 @@ redef class AAsNotnullExpr var i = v.expr(self.n_expr, null) if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i - if i.mtype.ctype != "val*" then return i + if i.mtype.is_c_primitive then return i v.add("if (unlikely({i} == NULL)) \{") v.add_abort("Cast failed") @@ -2796,7 +2862,7 @@ redef class AOnceExpr v.add_decl("static {mtype.ctype} {name};") v.add_decl("static int {guard};") var res = v.new_var(mtype) - v.add("if ({guard}) \{") + v.add("if (likely({guard})) \{") v.add("{res} = {name};") v.add("\} else \{") var i = v.expr(self.n_expr, mtype) @@ -2874,22 +2940,17 @@ redef class ANewExpr do var mtype = self.recvtype assert mtype != null - var recv - var ctype = mtype.ctype + if mtype.mclass.name == "NativeArray" then assert self.n_args.n_exprs.length == 1 var l = v.expr(self.n_args.n_exprs.first, null) assert mtype isa MGenericType var elttype = mtype.arguments.first return v.native_array_instance(elttype, l) - else if ctype == "val*" then - recv = v.init_instance(mtype) - else if ctype == "char*" then - recv = v.new_expr("NULL/*special!*/", mtype) - else - recv = v.new_expr("({ctype})0/*special!*/", mtype) end + var recv = v.init_instance_or_extern(mtype) + var callsite = self.callsite.as(not null) var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs) var res2 = v.compile_callsite(callsite, args) @@ -2990,7 +3051,7 @@ redef class MModule # Give requided addinional system libraries (as given to LD_LIBS) # Note: can return null instead of an empty set - fun collect_linker_libs: nullable Set[String] do return null + fun collect_linker_libs: nullable Array[String] do return null end # Create a tool context to handle options and paths