# --separate
var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
+ # --no-inline-intern
+ var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
+
redef init
do
super
self.option_context.add_option(self.opt_separate)
+ self.option_context.add_option(self.opt_no_inline_intern)
end
end
v.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
# Class abstract representation
- v.add_decl("struct class \{ nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
+ v.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
# Type abstract representation
v.add_decl("struct type \{ int id; int color; int livecolor; short int is_nullable; struct vts_table *vts_table; struct fts_table *fts_table; int table_size; int type_table[1]; \}; /* general C type representing a Nit type. */")
v.add_decl("struct fts_table \{ struct type *fts[1]; \}; /* fts list of a C type representation. */")
# Instance abstract representation
v.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
+ compiler.compile_box_kinds
+
# Declare global instances
v.add_decl("extern int glob_argc;")
v.add_decl("extern char **glob_argv;")
self.ft_tables = ft_coloring.build_ft_tables
end
+ fun compile_box_kinds
+ do
+ # Collect all bas box class
+ # FIXME: this is not completely fine with a separate compilation scheme
+ for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
+ var classes = self.mainmodule.model.get_mclasses_by_name(classname)
+ if classes == null then continue
+ assert classes.length == 1 else print classes.join(", ")
+ self.box_kinds[classes.first] = self.box_kinds.length + 1
+ end
+ end
+
+ var box_kinds = new HashMap[MClass, Int]
+
+ fun box_kind_of(mclass: MClass): Int
+ do
+ if mclass.mclass_type.ctype == "val*" then
+ return 0
+ else if mclass.kind == extern_kind then
+ return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
+ else
+ return self.box_kinds[mclass]
+ end
+
+ end
+
protected fun compile_class_names do
# Build type names table
#self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
self.header.add_decl("struct class_{c_name} \{")
+ self.header.add_decl("int box_kind;")
self.header.add_decl("nitmethod_t vft[{vft.length}];")
self.header.add_decl("\};")
# Build class vft
self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
v.add_decl("const struct class_{c_name} class_{c_name} = \{")
+ v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
v.add_decl("\{")
for i in [0 .. vft.length[ do
var mpropdef = vft[i]
v.add("{res}->type = type;")
v.add("{res}->class = (struct class*) &class_{c_name};")
- for cd in mtype.collect_mclassdefs(self.mainmodule)
- do
- var n = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in n.n_propdefs do
- if npropdef isa AAttrPropdef then
- npropdef.init_expr(v, res)
- end
- end
- end
+ self.generate_init_attr(v, res, mtype)
v.add("return {res};")
v.add("\}")
+
+ generate_check_init_instance(mtype)
+ end
+
+ redef fun generate_check_init_instance(mtype)
+ do
+ if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
+
+ var v = self.new_visitor
+ var c_name = mtype.mclass.c_name
+ var res = new RuntimeVariable("self", mtype, mtype)
+ self.header.add_decl("void CHECK_NEW_{c_name}({mtype.ctype});")
+ v.add_decl("/* allocate {mtype} */")
+ v.add_decl("void CHECK_NEW_{c_name}({mtype.ctype} {res}) \{")
+ self.generate_check_attr(v, res, mtype)
+ v.add("\}")
end
redef fun new_visitor do return new SeparateCompilerVisitor(self)
# ENSURE: result.mtype.ctype == mtype.ctype
redef fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
do
- if value.mtype.ctype == mtype.ctype then
+ if value.mtype == mtype then
+ return value
+ 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_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
ss.append(", {a}")
end
- var maybenull = recv.mcasttype isa MNullableType
+ var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
+ var maybenull = recv.mcasttype isa MNullableType and consider_null
if maybenull then
self.add("if ({recv} == NULL) \{")
if mmethod.name == "==" then
end
if self.compiler.modelbuilder.mpropdef2npropdef.has_key(mmethoddef) and
- self.compiler.modelbuilder.mpropdef2npropdef[mmethoddef] isa AInternMethPropdef then
+ self.compiler.modelbuilder.mpropdef2npropdef[mmethoddef] isa AInternMethPropdef and
+ not compiler.modelbuilder.toolcontext.opt_no_inline_intern.value then
var frame = new Frame(self, mmethoddef, recvtype, arguments)
frame.returnlabel = self.get_name("RET_LABEL")
frame.returnvar = res
self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */")
# Check for Uninitialized attribute
- if not ret isa MNullableType then
+ if not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then
self.add("if ({res} == NULL) \{")
self.add_abort("Uninitialized attribute {a.name}")
self.add("\}")
return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
end
+ redef fun check_init_instance(value, mtype)
+ do
+ if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
+ self.add("CHECK_NEW_{mtype.mclass.c_name}({value});")
+ end
+
+
redef fun type_test(value, mtype)
do
var compiler = self.compiler.as(SeparateCompiler)
value2 = tmp
end
if value1.mtype.ctype != "val*" then
- if value2.mtype.ctype == value1.mtype.ctype then
+ if value2.mtype == value1.mtype then
self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
else if value2.mtype.ctype != "val*" then
self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
value2 = tmp
end
if value1.mtype.ctype != "val*" then
- if value2.mtype.ctype == value1.mtype.ctype then
+ if value2.mtype == value1.mtype then
self.add("{res} = {value1} == {value2};")
else if value2.mtype.ctype != "val*" then
self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
self.add("\}")
end
+ return res
+ end
+ var maybe_null = true
+ var test = new Array[String]
+ var t1 = value1.mcasttype
+ if t1 isa MNullableType then
+ test.add("{value1} != NULL")
+ t1 = t1.mtype
else
- var s = new Array[String]
- # This is just ugly on so many level. this works but must be rewriten
- for t in self.compiler.live_primitive_types do
- if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
- if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
- s.add "({value1}->class == (struct class*)&class_{t.c_name} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
+ maybe_null = false
+ end
+ var t2 = value2.mcasttype
+ if t2 isa MNullableType then
+ test.add("{value2} != NULL")
+ t2 = t2.mtype
+ else
+ maybe_null = false
+ end
+
+ var incompatible = false
+ var primitive
+ if t1.ctype != "val*" then
+ primitive = t1
+ if t1 == t2 then
+ # No need to compare class
+ else if t2.ctype != "val*" then
+ incompatible = true
+ else if can_be_primitive(value2) then
+ test.add("{value1}->class == {value2}->class")
+ else
+ incompatible = true
end
- if s.is_empty then
- self.add("{res} = {value1} == {value2};")
+ else if t2.ctype != "val*" then
+ primitive = t2
+ if can_be_primitive(value1) then
+ test.add("{value1}->class == {value2}->class")
+ else
+ incompatible = true
+ end
+ else
+ primitive = null
+ end
+
+ if incompatible then
+ if maybe_null then
+ self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
+ return res
else
- self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class && ({s.join(" || ")}));")
+ self.add("{res} = 0; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
+ return res
end
end
+ if primitive != null then
+ 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.as(SeparateCompiler).box_kinds do
+ 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
+ self.add("{res} = {value1} == {value2};")
+ return res
+ end
+ self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
return res
end
+ fun can_be_primitive(value: RuntimeVariable): Bool
+ do
+ var t = value.mcasttype
+ if t isa MNullableType then t = t.mtype
+ if not t isa MClassType then return false
+ var k = t.mclass.kind
+ return k == interface_kind or t.ctype != "val*"
+ end
+
+ fun maybe_null(value: RuntimeVariable): Bool
+ do
+ var t = value.mcasttype
+ return t isa MNullableType or t isa MNullType
+ end
+
redef fun array_instance(array, elttype)
do
var compiler = self.compiler.as(SeparateCompiler)
end
var length = self.int_instance(array.length)
self.send(self.get_property("with_native", arraytype), [res, nat, length])
- self.check_init_instance(res)
+ self.check_init_instance(res, arraytype)
self.add("\}")
return res
end