X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index abfbf3f..aa57850 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 @@ -333,10 +329,10 @@ class MakefileToolchain if libs != null then linker_options.add_all(libs) end - makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") + 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 @@ -371,6 +367,18 @@ class MakefileToolchain dep_rules.add(o) end + # Generate linker script, if any + if not compiler.linker_script.is_empty then + var linker_script_path = "{compile_dir}/linker_script" + ofiles.add "linker_script" + var f = new FileWriter.open(linker_script_path) + for l in compiler.linker_script do + f.write l + f.write "\n" + end + f.close + end + var java_files = new Array[ExternFile] var pkgconfigs = new Array[String] @@ -476,11 +484,19 @@ 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` + # It is the main method usually called after the instantiation + fun do_compilation is abstract + # Force the creation of a new file # The point is to avoid contamination between must-be-compiled-separately files fun new_file(name: String): CodeFile @@ -507,6 +523,10 @@ abstract class AbstractCompiler # Where global declaration are stored (the main .h) var header: CodeWriter is writable, noinit + # Additionnal linker script for `ld`. + # Mainly used to do specific link-time symbol resolution + var linker_script = new Array[String] + # Provide a declaration that can be requested (before or latter) by a visitor fun provide_declaration(key: String, s: String) do @@ -526,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") @@ -556,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 @@ -677,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") @@ -836,6 +856,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 @@ -914,12 +940,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) { var cds = mtype.collect_mclassdefs(self.mainmodule).to_a self.mainmodule.linearize_mclassdefs(cds) for cd in cds do - if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue - var n = self.modelbuilder.mclassdef2nclassdef[cd] - for npropdef in n.n_propdefs do - if npropdef isa AAttrPropdef then - npropdef.init_expr(v, recv) - end + for npropdef in modelbuilder.collect_attr_propdef(cd) do + npropdef.init_expr(v, recv) end end end @@ -930,12 +952,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) { var cds = mtype.collect_mclassdefs(self.mainmodule).to_a self.mainmodule.linearize_mclassdefs(cds) for cd in cds do - if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue - var n = self.modelbuilder.mclassdef2nclassdef[cd] - for npropdef in n.n_propdefs do - if npropdef isa AAttrPropdef then - npropdef.check_expr(v, recv) - end + for npropdef in modelbuilder.collect_attr_propdef(cd) do + npropdef.check_expr(v, recv) end end end @@ -1044,8 +1062,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 @@ -1287,11 +1305,11 @@ abstract class AbstractCompilerVisitor fun escapemark_name(e: nullable EscapeMark): String do assert e != null - if escapemark_names.has_key(e) then return escapemark_names[e] + if frame.escapemark_names.has_key(e) then return frame.escapemark_names[e] var name = e.name if name == null then name = "label" name = get_name(name) - escapemark_names[e] = name + frame.escapemark_names[e] = name return name end @@ -1303,8 +1321,6 @@ abstract class AbstractCompilerVisitor add("BREAK_{escapemark_name(e)}: (void)0;") end - private var escapemark_names = new HashMap[EscapeMark, String] - # Return a "const char*" variable associated to the classname of the dynamic type of an object # NOTE: we do not return a `RuntimeVariable` "NativeString" as the class may not exist in the module/program fun class_name_string(value: RuntimeVariable): String is abstract @@ -1371,6 +1387,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 ctype == "val*" 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 @@ -1409,7 +1443,7 @@ abstract class AbstractCompilerVisitor 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 @@ -1468,10 +1502,11 @@ abstract class AbstractCompilerVisitor self.require_declaration(s) 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) + # Look for a needed .h and .c file for a given module + # This is used for the legacy FFI + fun add_extern(mmodule: MModule) do + var file = mmodule.location.file.filename file = file.strip_extension(".nit") var tryfile = file + ".nit.h" if tryfile.file_exists then @@ -1514,8 +1549,11 @@ 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 @@ -1544,6 +1582,15 @@ abstract class AbstractCompilerVisitor fun stmt(nexpr: nullable AExpr) do if nexpr == null then return + + var narray = nexpr.comprehension + if narray != null then + var recv = frame.comprehension.as(not null) + var val = expr(nexpr, narray.element_mtype) + compile_callsite(narray.push_callsite.as(not null), [recv, val]) + return + end + var old = self.current_node self.current_node = nexpr nexpr.stmt(self) @@ -1666,8 +1713,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 @@ -1689,6 +1736,13 @@ class Frame # The label at the end of the property var returnlabel: nullable String = null is writable + + # Labels associated to a each escapemarks. + # Because of inlinings, escape-marks must be associated to their context (the frame) + private var escapemark_names = new HashMap[EscapeMark, String] + + # The array comprehension currently filled, if any + private var comprehension: nullable RuntimeVariable = null end redef class MType @@ -1700,21 +1754,9 @@ redef class MType # Short name of the `ctype` to use in unions fun ctypename: String do return "val" - - # Return the name of the C structure associated to a Nit live type - fun c_name: String is abstract - protected var c_name_cache: nullable String is protected writable end redef class MClassType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "{mclass.intro_mmodule.c_name}__{mclass.name.to_cmangle}" - self.c_name_cache = res - return res - end redef fun ctype: String do @@ -1765,90 +1807,8 @@ redef class MClassType end end -redef class MGenericType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = super - for t in self.arguments do - res = res + t.c_name - end - self.c_name_cache = res - return res - end -end - -redef class MParameterType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "{self.mclass.c_name}_FT{self.rank}" - self.c_name_cache = res - return res - end -end - -redef class MVirtualType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "{self.mproperty.intro.mclassdef.mclass.c_name}_VT{self.mproperty.name}" - self.c_name_cache = res - return res - end -end - -redef class MNullableType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "nullable_{self.mtype.c_name}" - self.c_name_cache = res - return res - end -end - -redef class MClass - # Return the name of the C structure associated to a Nit class - fun c_name: String do - var res = self.c_name_cache - if res != null then return res - res = "{intro_mmodule.c_name}__{name.to_cmangle}" - self.c_name_cache = res - return res - end - private var c_name_cache: nullable String -end - -redef class MProperty - fun c_name: String do - var res = self.c_name_cache - if res != null then return res - res = "{self.intro.c_name}" - self.c_name_cache = res - return res - end - private var c_name_cache: nullable String -end - redef class MPropDef type VISITOR: AbstractCompilerVisitor - - private var c_name_cache: nullable String - - # The mangled name associated to the property - fun c_name: String - do - var res = self.c_name_cache - if res != null then return res - res = "{self.mclassdef.mmodule.c_name}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}" - self.c_name_cache = res - return res - end end redef class MMethodDef @@ -1857,10 +1817,10 @@ redef class MMethodDef do if is_abstract then return true var modelbuilder = v.compiler.modelbuilder - if modelbuilder.mpropdef2npropdef.has_key(self) then - var npropdef = modelbuilder.mpropdef2npropdef[self] - return npropdef.can_inline - else if self.mproperty.is_root_init then + var node = modelbuilder.mpropdef2node(self) + if node isa APropdef then + return node.can_inline + else if node isa AClassdef then # Automatic free init is always inlined since it is empty or contains only attribtes assigments return true else @@ -1873,19 +1833,27 @@ redef class MMethodDef do var modelbuilder = v.compiler.modelbuilder var val = constant_value - if modelbuilder.mpropdef2npropdef.has_key(self) then - var npropdef = modelbuilder.mpropdef2npropdef[self] + 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 = npropdef + v.current_node = node self.compile_parameter_check(v, arguments) - npropdef.compile_to_c(v, self, arguments) + node.compile_to_c(v, self, arguments) v.current_node = oldnode - else if self.mproperty.is_root_init then - var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef] + else if node isa AClassdef then var oldnode = v.current_node - v.current_node = nclassdef + v.current_node = node self.compile_parameter_check(v, arguments) - nclassdef.compile_to_c(v, self, arguments) + node.compile_to_c(v, self, arguments) v.current_node = oldnode else if val != null then v.ret(v.value_instance(val)) @@ -1934,13 +1902,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 @@ -2240,16 +2201,13 @@ redef class AMethPropdef do var externname var at = self.get_single_annotation("extern", v.compiler.modelbuilder) - if at != null then + if at != null and at.n_args.length == 1 then externname = at.arg_as_string(v.compiler.modelbuilder) if externname == null then return false else return false end - if location.file != null then - var file = location.file.filename - v.add_extern(file) - end + v.add_extern(mpropdef.mclassdef.mmodule) var res: nullable RuntimeVariable = null var ret = mpropdef.msignature.return_mtype if ret != null then @@ -2281,10 +2239,7 @@ redef class AMethPropdef else return false end - if location.file != null then - var file = location.file.filename - v.add_extern(file) - end + v.add_extern(mpropdef.mclassdef.mmodule) v.adapt_signature(mpropdef, arguments) v.unbox_signature_extern(mpropdef, arguments) var ret = arguments.first.mtype @@ -2300,6 +2255,8 @@ redef class AMethPropdef end redef class AAttrPropdef + redef fun can_inline: Bool do return not is_lazy + redef fun compile_to_c(v, mpropdef, arguments) do if mpropdef == mreadpropdef then @@ -2349,7 +2306,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 @@ -2358,7 +2315,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(MClassType), [recv]) + var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv]) v.frame = frame var value @@ -2397,7 +2354,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) @@ -2751,13 +2708,18 @@ end redef class AArrayExpr redef fun expr(v) do - var mtype = self.mtype.as(MClassType).arguments.first + var mtype = self.element_mtype.as(not null) var array = new Array[RuntimeVariable] - for nexpr in self.n_exprs.n_exprs do - var i = v.expr(nexpr, mtype) - array.add(i) + var res = v.array_instance(array, mtype) + + var old_comprehension = v.frame.comprehension + v.frame.comprehension = res + for nexpr in self.n_exprs do + v.stmt(nexpr) end - return v.array_instance(array, mtype) + v.frame.comprehension = old_comprehension + + return res end end @@ -2863,7 +2825,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) @@ -2941,22 +2903,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) @@ -3029,19 +2986,6 @@ redef class Array[E] end redef class MModule - # Return the name of the global C identifier associated to `self`. - # This name is used to prefix files and other C identifiers associated with `self`. - var c_name: String is lazy do - var g = mgroup - var res - if g != null and g.mproject.name != name then - res = g.mproject.name.to_cmangle + "__" + name.to_cmangle - else - res = name.to_cmangle - end - return res - end - # All `MProperty` associated to all `MClassDef` of `mclass` fun properties(mclass: MClass): Set[MProperty] do if not self.properties_cache.has_key(mclass) then @@ -3070,13 +3014,13 @@ 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 var toolcontext = new ToolContext -toolcontext.tooldescription = "Usage: nitg [OPTION]... file.nit...\nCompiles Nit programs." +toolcontext.tooldescription = "Usage: nitc [OPTION]... file.nit...\nCompiles Nit programs." # We do not add other options, so process them now! toolcontext.process_options(args)