# --no-inline-intern
var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
+ # --no-union-attribute
+ var opt_no_union_attribute: OptionBool = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
+
+ # --no-shortcut-equate
+ var opt_no_shortcut_equate: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
+
# --inline-coloring-numbers
var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids", "--inline-coloring-numbers")
super
self.option_context.add_option(self.opt_separate)
self.option_context.add_option(self.opt_no_inline_intern)
+ self.option_context.add_option(self.opt_no_union_attribute)
+ self.option_context.add_option(self.opt_no_shortcut_equate)
self.option_context.add_option(self.opt_inline_coloring_numbers)
self.option_context.add_option(self.opt_bm_typing)
self.option_context.add_option(self.opt_phmod_typing)
self.toolcontext.info("*** COMPILING TO C ***", 1)
var compiler = new SeparateCompiler(mainmodule, runtime_type_analysis, self)
+ compiler.compile_header
# compile class structures
for m in mainmodule.in_importation.greaters do
end
# The main function of the C
+ compiler.new_file
compiler.compile_main_function
# compile methods
for m in mainmodule.in_importation.greaters do
+ compiler.new_file
compiler.compile_module_to_c(m)
end
# compile live & cast type structures
+ compiler.new_file
var mtypes = compiler.do_type_coloring
for t in mtypes do
compiler.compile_type_to_c(t)
end
end
+ compiler.display_stats
+
write_and_make(compiler)
end
end
redef fun compile_header_structs do
self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
- self.header.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
+ self.compile_header_attribute_structs
self.header.add_decl("struct class \{ int box_kind; nitmethod_t vft[1]; \}; /* general C type representing a Nit class. */")
if modelbuilder.toolcontext.opt_generic_tree.value then
self.header.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
end
+ fun compile_header_attribute_structs
+ do
+ if modelbuilder.toolcontext.opt_no_union_attribute.value then
+ self.header.add_decl("typedef void* nitattribute_t; /* general C type representing a Nit attribute. */")
+ else
+ self.header.add_decl("typedef union \{")
+ 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};")
+ end
+ self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */")
+ end
+ end
+
redef fun compile_class_names do
abort # There is no class name compilation since the name is stored in the type structure
end
v.add("if(type == NULL) \{")
v.add_abort("type null")
v.add("\}")
- v.add("if(type->unanchored_table == NULL) \{")
- v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", type->name);")
- v.add_abort("type dead")
- v.add("\}")
+ if not v.compiler.modelbuilder.toolcontext.opt_generic_tree.value then
+ v.add("if(type->unanchored_table == NULL) \{")
+ v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", type->name);")
+ v.add_abort("type dead")
+ v.add("\}")
+ end
end
v.add("{res}->class = (struct class*) &class_{c_name};")
var recv = arguments.first
s.append("val*")
ss.append("{recv}")
- self.varargize(msignature, arguments)
+ self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
for i in [0..msignature.arity[ do
var a = arguments[i+1]
var t = msignature.mparameters[i].mtype
end
self.add("\} else \{")
end
+ if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
+ assert res != null
+ # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
+ var arg = arguments[1]
+ if arg.mcasttype isa MNullType then
+ if mmethod.name == "==" then
+ self.add("{res} = 0; /* arg is null but recv is not */")
+ else
+ self.add("{res} = 1; /* arg is null and recv is not */")
+ end
+ if maybenull then
+ self.add("\}")
+ end
+ return res
+ end
+ end
var r
if ret == null then r = "void" else r = ret.ctype
return res
end
+ redef fun vararg_instance(mpropdef, recv, varargs, elttype)
+ do
+ # A vararg must be stored into an new array
+ # The trick is that the dymaic type of the array may depends on the receiver
+ # of the method (ie recv) if the static type is unresolved
+ # This is more complex than usual because the unanchored type must not be resolved
+ # with the current receiver (ie self).
+ # Therefore to isolate the resolution from self, a local Frame is created.
+ # One can see this implementation as an inlined method of the receiver whose only
+ # job is to allocate the array
+ var old_frame = self.frame
+ var frame = new Frame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
+ self.frame = frame
+ #print "required Array[{elttype}] for recv {recv.inspect}. bound=Array[{self.resolve_for(elttype, recv)}]. selfvar={frame.arguments.first.inspect}"
+ var res = self.array_instance(varargs, elttype)
+ self.frame = old_frame
+ return res
+ end
+
redef fun isset_attribute(a, recv)
do
self.check_recv_notnull(recv)
var res = self.new_var(bool_type)
- self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
+
+ # What is the declared type of the attribute?
+ var mtype = a.intro.static_mtype.as(not null)
+ var intromclassdef = a.intro.mclassdef
+ mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
+
+ if mtype isa MNullableType then
+ self.add("{res} = 1; /* easy isset: {a} on {recv.inspect} */")
+ return res
+ end
+
+ if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
+ self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/")
+ else
+
+ if mtype.ctype == "val*" then
+ self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */")
+ else
+ self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */")
+ end
+ end
return res
end
var intromclassdef = a.intro.mclassdef
ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
- # Get the attribute or a box (ie. always a val*)
- var cret = self.object_type.as_nullable
- var res = self.new_var(cret)
- res.mcasttype = ret
- self.add("{res} = {recv}->attrs[{a.const_color}]; /* {a} on {recv.inspect} */")
+ if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
+ # Get the attribute or a box (ie. always a val*)
+ var cret = self.object_type.as_nullable
+ var res = self.new_var(cret)
+ res.mcasttype = ret
- # Check for Uninitialized attribute
- 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("\}")
- end
+ self.add("{res} = {recv}->attrs[{a.const_color}]; /* {a} on {recv.inspect} */")
+
+ # Check for Uninitialized attribute
+ 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("\}")
+ end
+
+ # Return the attribute or its unboxed version
+ # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
+ return self.autobox(res, ret)
+ else
+ var res = self.new_var(ret)
+ self.add("{res} = {recv}->attrs[{a.const_color}].{ret.ctypename}; /* {a} on {recv.inspect} */")
+
+ # Check for Uninitialized attribute
+ if ret.ctype == "val*" and 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("\}")
+ end
- # Return the attribute or its unboxed version
- # Note: it is mandatory since we reuse the box on write, we do not whant that the box escapes
- return self.autobox(res, ret)
+ return res
+ end
end
redef fun write_attribute(a, recv, value)
# Adapt the value to the declared type
value = self.autobox(value, mtype)
- var attr = "{recv}->attrs[{a.const_color}]"
- if mtype.ctype != "val*" then
- assert mtype isa MClassType
- # 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_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} */")
- self.add("\}")
+
+ if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then
+ var attr = "{recv}->attrs[{a.const_color}]"
+ if mtype.ctype != "val*" then
+ assert mtype isa MClassType
+ # 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_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} */")
+ self.add("\}")
+ else
+ # The attribute is not primitive, thus store it direclty
+ self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
+ end
else
- # The attribute is not primitive, thus store it direclty
- self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
+ self.add("{recv}->attrs[{a.const_color}].{mtype.ctypename} = {value}; /* {a} on {recv.inspect} */")
end
end
end
- redef fun type_test(value, mtype)
+ redef fun type_test(value, mtype, tag)
do
self.add("/* {value.inspect} isa {mtype} */")
var compiler = self.compiler.as(SeparateCompiler)
ntype = ntype.mtype
end
+ if value.mcasttype.is_subtype(self.frame.mpropdef.mclassdef.mmodule, self.frame.mpropdef.mclassdef.bound_mtype, mtype) then
+ self.add("{res} = 1; /* easy {value.inspect} isa {mtype}*/")
+ if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
+ self.compiler.count_type_test_skipped[tag] += 1
+ self.add("count_type_test_skipped_{tag}++;")
+ end
+ return res
+ end
+
if ntype.need_anchor then
var type_struct = self.get_name("type_struct")
self.add_decl("struct type* {type_struct};")
else
self.add("{type_struct} = {recv_type_info}->unanchored_table->types[{ntype.const_color}];")
end
+ if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
+ self.compiler.count_type_test_unresolved[tag] += 1
+ self.add("count_type_test_unresolved_{tag}++;")
+ end
end
self.add("{cltype} = {type_struct}->color;")
self.add("{idtype} = {type_struct}->id;")
self.add("{cltype} = type_{mtype.c_name}.color;")
self.add("{idtype} = type_{mtype.c_name}.id;")
self.add("{is_nullable} = type_{mtype.c_name}.is_nullable;")
+ if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
+ self.compiler.count_type_test_resolved[tag] += 1
+ self.add("count_type_test_resolved_{tag}++;")
+ end
else
self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); exit(1);")
end