X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 55b644f..d2f0b11 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -28,15 +28,15 @@ import counter # Add compiling options redef class ToolContext # --output - var opt_output = new OptionString("Output file", "-o", "--output") + var opt_output = new OptionString("Filename of the generated executable", "-o", "--output") # --dir var opt_dir = new OptionString("Output directory", "--dir") # --no-cc - var opt_no_cc = new OptionBool("Do not invoke C compiler", "--no-cc") + var opt_no_cc = new OptionBool("Do not invoke the C compiler", "--no-cc") # --no-main var opt_no_main = new OptionBool("Do not generate main entry point", "--no-main") # --make-flags - var opt_make_flags = new OptionString("Additional options to make", "--make-flags") + var opt_make_flags = new OptionString("Additional options to the `make` command", "--make-flags") # --max-c-lines var opt_max_c_lines = new OptionInt("Maximum number of lines in generated C files. Use 0 for unlimited", 10000, "--max-c-lines") # --group-c-files @@ -50,7 +50,7 @@ redef class ToolContext # --no-check-attr-isset var opt_no_check_attr_isset = new OptionBool("Disable isset tests before each attribute access (dangerous)", "--no-check-attr-isset") # --no-check-assert - var opt_no_check_assert = new OptionBool("Disable the evaluation of explicit 'assert' and 'as' (dangerous)", "--no-check-assert") + var opt_no_check_assert = new OptionBool("Disable the evaluation of explicit `assert` and `as` (dangerous)", "--no-check-assert") # --no-check-autocast var opt_no_check_autocast = new OptionBool("Disable implicit casts on unsafe expression usage (dangerous)", "--no-check-autocast") # --no-check-null @@ -66,11 +66,11 @@ redef class ToolContext # --no-stacktrace var opt_no_stacktrace = new OptionBool("Disable the generation of stack traces", "--no-stacktrace") # --no-gcc-directives - var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive") + var opt_no_gcc_directive = new OptionArray("Disable advanced gcc directives for optimization", "--no-gcc-directive") # --release var opt_release = new OptionBool("Compile in release mode and finalize application", "--release") # -g - var opt_debug = new OptionBool("Compile in debug mode (no C-side optimization)", "--debug", "-g") + var opt_debug = new OptionBool("Compile in debug mode (no C-side optimization)", "-g", "--debug") redef init do @@ -349,7 +349,7 @@ class MakefileToolchain end var debug = toolcontext.opt_debug.value - makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g{ if not debug then " -O2 " else " "}-Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") + makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g{ if not debug then " -O2 " else " "}-Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n" if platform.supports_libunwind then @@ -654,9 +654,23 @@ abstract class AbstractCompiler self.header.add_decl("#include \n") self.header.add_decl("#include \n") self.header.add_decl("#include \n") + self.header.add_decl("#ifdef __linux__") + self.header.add_decl(" #include ") + self.header.add_decl("#endif") self.header.add_decl("#include \n") self.header.add_decl("#include \"gc_chooser.h\"") + self.header.add_decl("#ifdef __APPLE__") + self.header.add_decl(" #include ") + self.header.add_decl(" #define be32toh(x) OSSwapBigToHostInt32(x)") + self.header.add_decl("#endif") + self.header.add_decl("#ifdef __pnacl__") + self.header.add_decl(" #define be16toh(val) (((val) >> 8) | ((val) << 8))") + self.header.add_decl(" #define be32toh(val) ((be16toh((val) << 16) | (be16toh((val) >> 16))))") + self.header.add_decl("#endif") self.header.add_decl("#ifdef ANDROID") + self.header.add_decl(" #ifndef be32toh") + self.header.add_decl(" #define be32toh(val) betoh32(val)") + self.header.add_decl(" #endif") self.header.add_decl(" #include ") self.header.add_decl(" #define PRINT_ERROR(...) (void)__android_log_print(ANDROID_LOG_WARN, \"Nit\", __VA_ARGS__)") self.header.add_decl("#else") @@ -853,12 +867,14 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add_decl("int main(int argc, char** argv) \{") end + v.add "#if !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE)" v.add("signal(SIGABRT, sig_handler);") v.add("signal(SIGFPE, sig_handler);") v.add("signal(SIGILL, sig_handler);") v.add("signal(SIGINT, sig_handler);") v.add("signal(SIGTERM, sig_handler);") v.add("signal(SIGSEGV, sig_handler);") + v.add "#endif" v.add("signal(SIGPIPE, SIG_IGN);") v.add("glob_argc = argc; glob_argv = argv;") @@ -1148,29 +1164,6 @@ abstract class AbstractCompilerVisitor fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do if callsite.is_broken then return null - var initializers = callsite.mpropdef.initializers - if not initializers.is_empty then - var recv = arguments.first - - var i = 1 - for p in initializers do - if p isa MMethod then - var args = [recv] - for x in p.intro.msignature.mparameters do - args.add arguments[i] - i += 1 - end - self.send(p, args) - else if p isa MAttribute then - self.write_attribute(p, recv, arguments[i]) - i += 1 - else abort - end - assert i == arguments.length - - return self.send(callsite.mproperty, [recv]) - end - return self.send(callsite.mproperty, arguments) end @@ -1178,7 +1171,7 @@ abstract class AbstractCompilerVisitor fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable]) is abstract - fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract + fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]): Bool do return false # Return an element of a native array. # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays @@ -1193,7 +1186,7 @@ abstract class AbstractCompilerVisitor # of runtime variables to use in the call. fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable] do - var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null) + var msignature = mpropdef.msignature.as(not null) var res = new Array[RuntimeVariable] res.add(recv) @@ -1222,8 +1215,8 @@ abstract class AbstractCompilerVisitor res.add(null_instance) continue end - if param.is_vararg and map.vararg_decl > 0 then - var vararg = exprs.sub(j, map.vararg_decl) + if param.is_vararg and args[i].vararg_decl > 0 then + var vararg = exprs.sub(j, args[i].vararg_decl) var elttype = param.mtype var arg = self.vararg_instance(mpropdef, recv, vararg, elttype) res.add(arg) @@ -1257,17 +1250,21 @@ abstract class AbstractCompilerVisitor do mtype = self.anchor(mtype) var valmtype = value.mcasttype + + # Do nothing if useless autocast if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then return value end + # Just as_not_null if the target is not nullable. + # + # eg `nullable PreciseType` adapted to `Object` gives precisetype. if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then - var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype) - return res - else - var res = new RuntimeVariable(value.name, valmtype, mtype) - return res + mtype = valmtype.mtype end + + var res = new RuntimeVariable(value.name, value.mtype, mtype) + return res end # Generate a super call from a method definition @@ -1335,13 +1332,18 @@ abstract class AbstractCompilerVisitor # Checks + # Can value be null? (according to current knowledge) + fun maybenull(value: RuntimeVariable): Bool + do + return value.mcasttype isa MNullableType or value.mcasttype isa MNullType + end + # Add a check and an abort for a null receiver if needed fun check_recv_notnull(recv: RuntimeVariable) do if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return - var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType - if maybenull then + if maybenull(recv) then self.add("if (unlikely({recv} == NULL)) \{") self.add_abort("Receiver is null") self.add("\}") @@ -1657,7 +1659,7 @@ abstract class AbstractCompilerVisitor # This is used for the legacy FFI fun add_extern(mmodule: MModule) do - var file = mmodule.location.file.filename + var file = mmodule.filepath file = file.strip_extension(".nit") var tryfile = file + ".nit.h" if tryfile.file_exists then @@ -2022,6 +2024,7 @@ redef class MMethodDef fun can_inline(v: VISITOR): Bool do if is_abstract then return true + if constant_value != null then return true var modelbuilder = v.compiler.modelbuilder var node = modelbuilder.mpropdef2node(self) if node isa APropdef then @@ -2029,6 +2032,8 @@ redef class MMethodDef else if node isa AClassdef then # Automatic free init is always inlined since it is empty or contains only attribtes assigments return true + else if node == null then + return true else abort end @@ -2074,20 +2079,23 @@ redef class MMethodDef do if v.compiler.modelbuilder.toolcontext.opt_no_check_covariance.value then return + var msignature = self.msignature.as(not null) + for i in [0..msignature.arity[ do + var mp = msignature.mparameters[i] # skip test for vararg since the array is instantiated with the correct polymorphic type - if msignature.vararg_rank == i then continue + if mp.is_vararg then continue # skip if the cast is not required var origmtype = self.mproperty.intro.msignature.mparameters[i].mtype if not origmtype.need_anchor then continue # get the parameter type - var mtype = self.msignature.mparameters[i].mtype + var mtype = mp.mtype # generate the cast # note that v decides if and how to implements the cast - v.add("/* Covariant cast for argument {i} ({self.msignature.mparameters[i].name}) {arguments[i+1].inspect} isa {mtype} */") + v.add("/* Covariant cast for argument {i} ({mp.name}) {arguments[i+1].inspect} isa {mtype} */") v.add_cast(arguments[i+1], mtype, "covariance") end end @@ -2129,7 +2137,8 @@ redef class AMethPropdef # Try special compilation if mpropdef.is_intern then if compile_intern_to_c(v, mpropdef, arguments) then return - else if mpropdef.is_extern then + end + if mpropdef.is_extern then if mpropdef.mproperty.is_init then if compile_externinit_to_c(v, mpropdef, arguments) then return else @@ -2244,6 +2253,21 @@ redef class AMethPropdef else if pname == "to_b" then v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) return true + else if pname == "code_point" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true + else if pname == "&" then + v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null))) + return true + else if pname == "|" then + v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null))) + return true + else if pname == ">>" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "<<" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true end else if cname == "Char" then if pname == "object_id" then @@ -2277,6 +2301,9 @@ redef class AMethPropdef else if pname == "to_i" then v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null))) return true + else if pname == "code_point" then + v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) + return true end else if cname == "Byte" then if pname == "output" then @@ -2325,6 +2352,15 @@ redef class AMethPropdef else if pname == ">=" then v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) return true + else if pname == ">>" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "<<" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true + else if pname == "&" then + v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null))) + return true else if pname == "to_i" then v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) return true @@ -2346,6 +2382,9 @@ redef class AMethPropdef else if pname == "to_u32" then v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) return true + else if pname == "ascii" then + v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null))) + return true end else if cname == "Bool" then if pname == "output" then @@ -2450,13 +2489,25 @@ redef class AMethPropdef else if pname == "fast_cstring" then v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) return true + else if pname == "==" then + v.ret(v.equal_test(arguments[0], arguments[1])) + return true + else if pname == "!=" then + var res = v.equal_test(arguments[0], arguments[1]) + v.ret(v.new_expr("!{res}", ret.as(not null))) + return true else if pname == "new" then v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null))) return true + else if pname == "fetch_4_chars" then + v.ret(v.new_expr("(long)*((uint32_t*)({arguments[0]} + {arguments[1]}))", ret.as(not null))) + return true + else if pname == "fetch_4_hchars" then + v.ret(v.new_expr("(long)be32toh(*((uint32_t*)({arguments[0]} + {arguments[1]})))", ret.as(not null))) + return true end else if cname == "NativeArray" then - v.native_array_def(pname, ret, arguments) - return true + return v.native_array_def(pname, ret, arguments) else if cname == "Int8" then if pname == "output" then v.add("printf(\"%\"PRIi8 \"\\n\", {arguments.first});") @@ -3031,7 +3082,18 @@ redef class AAttrPropdef v.assign(v.frame.returnvar.as(not null), res) else if mpropdef == mwritepropdef then assert arguments.length == 2 - v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1]) + var recv = arguments.first + var arg = arguments[1] + if is_optional and v.maybenull(arg) then + var value = v.new_var(self.mpropdef.static_mtype.as(not null)) + v.add("if ({arg} == NULL) \{") + v.assign(value, evaluate_expr(v, recv)) + v.add("\} else \{") + v.assign(value, arg) + v.add("\}") + arg = value + end + v.write_attribute(self.mpropdef.mproperty, arguments.first, arg) if is_lazy then var ret = self.mtype var useiset = not ret.is_c_primitive and not ret isa MNullableType @@ -3106,13 +3168,38 @@ end redef class AClassdef private fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do - if mpropdef == self.mfree_init then - assert mpropdef.mproperty.is_root_init + if mpropdef.mproperty.is_root_init then assert arguments.length == 1 if not mpropdef.is_intro then v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments) end return + else if mclassdef.auto_init == mpropdef then + var recv = arguments.first + var initializers = mpropdef.initializers + var no_init = false + if not initializers.is_empty then + + var i = 1 + for p in initializers do + if p isa MMethod then + var args = [recv] + for x in p.intro.msignature.mparameters do + args.add arguments[i] + i += 1 + end + v.send(p, args) + if p.intro.is_calling_init then no_init = true + else if p isa MAttribute then + v.write_attribute(p, recv, arguments[i]) + i += 1 + else abort + end + assert i == arguments.length + + end + if not no_init then v.send(mclass.the_root_init_mmethod.as(not null), [recv]) + return else abort end @@ -3445,6 +3532,9 @@ redef class AOrElseExpr do var res = v.new_var(self.mtype.as(not null)) var i1 = v.expr(self.n_expr, null) + + if not v.maybenull(i1) then return i1 + v.add("if ({i1}!=NULL) \{") v.assign(res, i1) v.add("\} else \{") @@ -3474,7 +3564,11 @@ redef class AFloatExpr end redef class ACharExpr - redef fun expr(v) do return v.char_instance(self.value.as(not null)) + redef fun expr(v) do + if is_ascii then return v.byte_instance(value.as(not null).ascii) + if is_code_point then return v.int_instance(value.as(not null).code_point) + return v.char_instance(self.value.as(not null)) + end end redef class AArrayExpr @@ -3627,7 +3721,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.is_c_primitive then return i + if not v.maybenull(i) then return i v.add("if (unlikely({i} == NULL)) \{") v.add_abort("Cast failed") @@ -3696,7 +3790,8 @@ end redef class ASuperExpr redef fun expr(v) do - var recv = v.frame.arguments.first + var frame = v.frame.as(not null) + var recv = frame.arguments.first var callsite = self.callsite if callsite != null then @@ -3707,7 +3802,7 @@ redef class ASuperExpr # Add automatic arguments for the super init call args = [recv] for i in [0..callsite.msignature.arity[ do - args.add(v.frame.arguments[i+1]) + args.add(frame.arguments[i+1]) end else args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs) @@ -3722,7 +3817,7 @@ redef class ASuperExpr var args if self.n_args.n_exprs.is_empty then - args = v.frame.arguments + args = frame.arguments else args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs) end @@ -3890,11 +3985,7 @@ end # Here we load an process all modules passed on the command line var mmodules = modelbuilder.parse(arguments) -if mmodules.is_empty then - toolcontext.check_errors - toolcontext.errors_info - if toolcontext.error_count > 0 then exit(1) else exit(0) -end +if mmodules.is_empty then toolcontext.quit modelbuilder.run_phases