X-Git-Url: http://nitlanguage.org diff --git a/src/global_compiler.nit b/src/global_compiler.nit index 4032931..9a82243 100644 --- a/src/global_compiler.nit +++ b/src/global_compiler.nit @@ -25,7 +25,29 @@ module global_compiler import abstract_compiler import rapid_type_analysis -import compiler_ffi + +redef class ToolContext + # option --global + var opt_global = new OptionBool("Use global compilation", "--global") + + var global_compiler_phase = new GlobalCompilerPhase(self, null) + + redef init do + super + option_context.add_option(opt_global) + end +end + +class GlobalCompilerPhase + super Phase + redef fun process_mainmodule(mainmodule, given_mmodules) do + if not toolcontext.opt_global.value then return + + var modelbuilder = toolcontext.modelbuilder + var analysis = modelbuilder.do_rapid_type_analysis(mainmodule) + modelbuilder.run_global_compiler(mainmodule, analysis) + end +end redef class ModelBuilder # Entry point to performs a global compilation on the AST of a complete program. @@ -55,6 +77,7 @@ redef class ModelBuilder end # The main function of the C + compiler.compile_nitni_global_ref_functions compiler.compile_main_function # Compile until all runtime_functions are visited @@ -102,8 +125,8 @@ class GlobalCompiler # Compile class names (for the class_name and output_class_name methods) protected fun compile_class_names do var v = new_visitor - self.header.add_decl("extern const char const * class_names[];") - v.add("const char const * class_names[] = \{") + self.header.add_decl("extern const char *class_names[];") + v.add("const char *class_names[] = \{") for t in self.runtime_type_analysis.live_types do v.add("\"{t}\", /* {self.classid(t)} */") end @@ -166,6 +189,7 @@ class GlobalCompiler if mtype.mclass.name == "NativeArray" then # NativeArrays are just a instance header followed by an array of values + v.add_decl("int length;") v.add_decl("{mtype.arguments.first.ctype} values[1];") end @@ -213,12 +237,14 @@ class GlobalCompiler if is_native_array then var mtype_elt = mtype.arguments.first v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));") + v.add("((struct {mtype.c_name}*){res})->length = length;") else v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}));") end v.add("{res}->classid = {self.classid(mtype)};") self.generate_init_attr(v, res, mtype) + v.set_finalizer res v.add("return {res};") v.add("\}") end @@ -245,7 +271,14 @@ class GlobalCompiler redef fun compile_nitni_structs do - self.header.add_decl("struct nitni_instance \{ val *value; \};") + self.header.add_decl """ +struct nitni_instance \{ + struct nitni_instance *next, + *prev; /* adjacent global references in global list */ + int count; /* number of time this global reference has been marked */ + val *value; +\};""" + super end end @@ -269,18 +302,18 @@ class GlobalCompilerVisitor 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("printf(\"Dead code executed!\\n\"); show_backtrace(1);") + self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);") return res end self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */") return res - else if value.mtype.cname_blind == "void*" and mtype.cname_blind == "void*" then + else if value.mtype.ctype == "void*" and mtype.ctype == "void*" then return value else # Bad things will appen! var res = self.new_var(mtype) self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */") - self.add("printf(\"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}\"); show_backtrace(1);") return res end end @@ -319,13 +352,22 @@ class GlobalCompilerVisitor else if pname == "[]=" then self.add("{recv}[{arguments[1]}]={arguments[2]};") return + else if pname == "length" then + self.ret(self.new_expr("((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->length", ret_type.as(not null))) + return else if pname == "copy_to" then var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values" - self.add("memcpy({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));") + self.add("memmove({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));") return end end + redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable + do + var ret_type = self.get_class("NativeArray").get_mtype([elttype]) + return self.new_expr("NEW_{ret_type.c_name}({length})", ret_type) + end + redef fun calloc_array(ret_type, arguments) do self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type)) @@ -359,7 +401,7 @@ class GlobalCompilerVisitor if res != null then self.assign(res, res2.as(not null)) return res end - var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or m.name == "==" or m.name == "!=" + var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or m.name == "==" or m.name == "!=" 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 */") @@ -438,7 +480,8 @@ class GlobalCompilerVisitor do check_valid_reciever(recvtype) #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}") - if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then + if m.mproperty.is_toplevel then + # Do not customize top-level methods recvtype = m.mclassdef.bound_mtype end return recvtype @@ -559,7 +602,7 @@ class GlobalCompilerVisitor fun bugtype(recv: RuntimeVariable) do if recv.mtype.ctype != "val*" then return - self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");") + 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);") end @@ -634,7 +677,7 @@ class GlobalCompilerVisitor var ta = a.intro.static_mtype.as(not null) 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_other.value then + if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then if ta.ctype == "val*" then self.add("if ({res2} == NULL) \{") self.add_abort("Uninitialized attribute {a.name}") @@ -702,10 +745,7 @@ class GlobalCompilerVisitor redef fun type_test(value, mtype, tag) do mtype = self.anchor(mtype) - var mclasstype = mtype - if mtype isa MNullableType then mclasstype = mtype.mtype - assert mclasstype isa MClassType - if not self.compiler.runtime_type_analysis.live_cast_types.has(mclasstype) then + if not self.compiler.runtime_type_analysis.live_cast_types.has(mtype) then debug "problem: {mtype} was detected cast-dead" abort end @@ -905,8 +945,8 @@ private class CustomizedRuntimeFunction var frame = new Frame(v, mmethoddef, recv, arguments) v.frame = frame - var sig = new Buffer - var comment = new Buffer + var sig = new FlatBuffer + var comment = new FlatBuffer var ret = mmethoddef.msignature.return_mtype if ret != null then ret = v.resolve_for(ret, selfvar)