X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index 4dfbeb0..43d06c2 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -191,7 +191,11 @@ class SeparateCompiler self.header.add_decl("void* val;") for c, v in self.box_kinds do var t = c.mclass_type - self.header.add_decl("{t.ctype} {t.ctypename};") + + # `Pointer` reuse the `val` field + if t.mclass.name == "Pointer" then continue + + self.header.add_decl("{t.ctype_extern} {t.ctypename};") end self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */") end @@ -213,9 +217,11 @@ class SeparateCompiler fun box_kind_of(mclass: MClass): Int do - if mclass.mclass_type.ctype == "val*" then + #var pointer_type = self.mainmodule.pointer_type + #if mclass.mclass_type.ctype == "val*" or mclass.mclass_type.is_subtype(self.mainmodule, mclass.mclass_type pointer_type) then + if mclass.mclass_type.ctype_extern == "val*" then return 0 - else if mclass.kind == extern_kind then + else if mclass.kind == extern_kind and mclass.name != "NativeString" then return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")] else return self.box_kinds[mclass] @@ -662,14 +668,13 @@ class SeparateCompiler do var mtype = mclass.intro.bound_mtype var c_name = mclass.c_name - var c_instance_name = mclass.c_instance_name var vft = self.method_tables[mclass] var attrs = self.attr_tables[mclass] var v = new_visitor var rta = runtime_type_analysis - var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" + var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" and mclass.name != "Pointer" v.add_decl("/* runtime class {c_name} */") @@ -698,23 +703,24 @@ class SeparateCompiler v.add_decl("\};") end - if mtype.ctype != "val*" then - if mtype.mclass.name == "Pointer" or mtype.mclass.kind != extern_kind then - #Build instance struct - self.header.add_decl("struct instance_{c_instance_name} \{") - self.header.add_decl("const struct type *type;") - self.header.add_decl("const struct class *class;") - self.header.add_decl("{mtype.ctype} value;") - self.header.add_decl("\};") - end + if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then + # Is a primitive type or the Pointer class, not any other extern class + + #Build instance struct + self.header.add_decl("struct instance_{c_name} \{") + self.header.add_decl("const struct type *type;") + self.header.add_decl("const struct class *class;") + self.header.add_decl("{mtype.ctype_extern} value;") + self.header.add_decl("\};") - if not rta.live_types.has(mtype) then return + if not rta.live_types.has(mtype) and mtype.mclass.name != "Pointer" then return #Build BOX - self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});") + self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});") v.add_decl("/* allocate {mtype} */") - v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{") - v.add("struct instance_{c_instance_name}*res = nit_alloc(sizeof(struct instance_{c_instance_name}));") + v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype_extern} value) \{") + v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));") + v.compiler.undead_types.add(mtype) v.require_declaration("type_{c_name}") v.add("res->type = &type_{c_name};") v.require_declaration("class_{c_name}") @@ -722,10 +728,31 @@ class SeparateCompiler v.add("res->value = value;") v.add("return (val*)res;") v.add("\}") + + if mtype.mclass.name != "Pointer" then return + + v = new_visitor + self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);") + v.add_decl("/* allocate {mtype} */") + v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{") + if is_dead then + v.add_abort("{mclass} is DEAD") + else + var res = v.new_named_var(mtype, "self") + res.is_exact = true + v.add("{res} = nit_alloc(sizeof(struct instance_{mtype.c_name}));") + v.add("{res}->type = type;") + hardening_live_type(v, "type") + v.require_declaration("class_{c_name}") + v.add("{res}->class = &class_{c_name};") + v.add("((struct instance_{mtype.c_name}*){res})->value = NULL;") + v.add("return {res};") + end + v.add("\}") return else if mclass.name == "NativeArray" then #Build instance struct - self.header.add_decl("struct instance_{c_instance_name} \{") + self.header.add_decl("struct instance_{c_name} \{") self.header.add_decl("const struct type *type;") self.header.add_decl("const struct class *class;") # NativeArrays are just a instance header followed by a length and an array of values @@ -738,9 +765,9 @@ class SeparateCompiler v.add_decl("/* allocate {mtype} */") v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{") var res = v.get_name("self") - v.add_decl("struct instance_{c_instance_name} *{res};") + v.add_decl("struct instance_{c_name} *{res};") var mtype_elt = mtype.arguments.first - v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));") + v.add("{res} = nit_alloc(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));") v.add("{res}->type = type;") hardening_live_type(v, "type") v.require_declaration("class_{c_name}") @@ -749,6 +776,30 @@ class SeparateCompiler v.add("return (val*){res};") v.add("\}") return + else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then + # Is an extern class (other than Pointer and NativeString) + # Pointer is caught in a previous `if`, and NativeString is internal + + var pointer_type = mainmodule.pointer_type + + self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);") + v.add_decl("/* allocate {mtype} */") + v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{") + if is_dead then + v.add_abort("{mclass} is DEAD") + else + var res = v.new_named_var(mtype, "self") + res.is_exact = true + v.add("{res} = nit_alloc(sizeof(struct instance_{pointer_type.c_name}));") + v.add("{res}->type = type;") + hardening_live_type(v, "type") + v.require_declaration("class_{c_name}") + v.add("{res}->class = &class_{c_name};") + v.add("((struct instance_{pointer_type.c_name}*){res})->value = NULL;") + v.add("return {res};") + end + v.add("\}") + return end #Build NEW @@ -909,6 +960,22 @@ class SeparateCompilerVisitor end end + redef fun unbox_signature_extern(m, args) + do + var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true) + var recv = args.first + if not m.mproperty.is_init and m.is_extern then + args.first = self.unbox_extern(args.first, m.mclassdef.mclass.mclass_type) + end + for i in [0..msignature.arity[ do + var t = msignature.mparameters[i].mtype + if i == msignature.vararg_rank then + t = args[i+1].mtype + end + if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t) + end + end + redef fun autobox(value, mtype) do if value.mtype == mtype then @@ -916,9 +983,12 @@ class SeparateCompilerVisitor else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then return value else if value.mtype.ctype == "val*" then - return self.new_expr("((struct instance_{mtype.c_instance_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) + return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) else if mtype.ctype == "val*" then var valtype = value.mtype.as(MClassType) + if mtype isa MClassType and mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then + valtype = compiler.mainmodule.pointer_type + end var res = self.new_var(mtype) if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(valtype) then self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */") @@ -941,6 +1011,42 @@ class SeparateCompilerVisitor end end + redef fun unbox_extern(value, mtype) + do + if mtype isa MClassType and mtype.mclass.kind == extern_kind and + mtype.mclass.name != "NativeString" then + var pointer_type = compiler.mainmodule.pointer_type + var res = self.new_var_extern(mtype) + self.add "{res} = ((struct instance_{pointer_type.c_name}*){value})->value; /* unboxing {value.mtype} */" + return res + else + return value + end + end + + redef fun box_extern(value, mtype) + do + if mtype isa MClassType and mtype.mclass.kind == extern_kind and + mtype.mclass.name != "NativeString" then + var valtype = compiler.mainmodule.pointer_type + var res = self.new_var(mtype) + if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then + self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */") + self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);") + return res + end + self.require_declaration("BOX_{valtype.c_name}") + self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */") + self.require_declaration("type_{mtype.c_name}") + self.add("{res}->type = &type_{mtype.c_name};") + self.require_declaration("class_{mtype.c_name}") + self.add("{res}->class = &class_{mtype.c_name};") + return res + else + return value + end + end + # Return a C expression returning the runtime type structure of the value # The point of the method is to works also with primitives types. fun type_info(value: RuntimeVariable): String @@ -1307,7 +1413,7 @@ class SeparateCompilerVisitor # The attribute is primitive, thus we store it in a box # The trick is to create the box the first time then resuse the box self.add("if ({attr} != NULL) \{") - self.add("((struct instance_{mtype.c_instance_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */") + self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */") self.add("\} else \{") value = self.autobox(value, self.object_type.as_nullable) self.add("{attr} = {value}; /* {a} on {recv.inspect} */") @@ -1481,7 +1587,8 @@ class SeparateCompilerVisitor self.add_decl("const char* {res};") if value.mtype.ctype == "val*" then self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;" - else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind then + else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind and + value.mtype.as(MClassType).name != "NativeString" then self.add "{res} = \"{value.mtype.as(MClassType).mclass}\";" else self.require_declaration("type_{value.mtype.c_name}") @@ -1564,12 +1671,12 @@ class SeparateCompilerVisitor end end if primitive != null then - test.add("((struct instance_{primitive.c_instance_name}*){value1})->value == ((struct instance_{primitive.c_instance_name}*){value2})->value") + test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value") else if can_be_primitive(value1) and can_be_primitive(value2) then test.add("{value1}->class == {value2}->class") var s = new Array[String] for t, v in self.compiler.box_kinds do - s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_instance_name}*){value1})->value == ((struct instance_{t.c_instance_name}*){value2})->value)" + s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)" end test.add("({s.join(" || ")})") else @@ -1635,7 +1742,7 @@ class SeparateCompilerVisitor do var elttype = arguments.first.mtype var nclass = self.get_class("NativeArray") - var recv = "((struct instance_{nclass.c_instance_name}*){arguments[0]})->values" + var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values" if pname == "[]" then self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null))) return @@ -1643,10 +1750,10 @@ class SeparateCompilerVisitor self.add("{recv}[{arguments[1]}]={arguments[2]};") return else if pname == "length" then - self.ret(self.new_expr("((struct instance_{nclass.c_instance_name}*){arguments[0]})->length", ret_type.as(not null))) + self.ret(self.new_expr("((struct instance_{nclass.c_name}*){arguments[0]})->length", ret_type.as(not null))) return else if pname == "copy_to" then - var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values" + var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values" self.add("memmove({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));") return end @@ -1851,23 +1958,6 @@ end redef class MType fun const_color: String do return "COLOR_{c_name}" - - # C name of the instance type to use - fun c_instance_name: String do return c_name -end - -redef class MClassType - redef fun c_instance_name do return mclass.c_instance_name -end - -redef class MClass - # Extern classes use the C instance of kernel::Pointer - fun c_instance_name: String - do - if kind == extern_kind then - return "kernel__Pointer" - else return c_name - end end interface PropertyLayoutElement end @@ -1881,3 +1971,8 @@ redef class MPropDef super PropertyLayoutElement fun const_color: String do return "COLOR_{c_name}" end + +redef class AExternInitPropdef + # The semi-global compilation does not support inlining calls to extern news + redef fun can_inline do return false +end