module separate_compiler
import abstract_compiler
-import layout_builders
+import coloring
import rapid_type_analysis
# Add separate compiler specific options
# --semi-global
var opt_semi_global = new OptionBool("Enable all semi-global optimizations", "--semi-global")
# --no-colo-dead-methods
- var opt_no_colo_dead_methods = new OptionBool("Do not colorize dead methods", "--no-colo-dead-methods")
+ var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
# --tables-metrics
var opt_tables_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
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, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
- self.option_context.add_option(self.opt_no_colo_dead_methods)
+ self.option_context.add_option(self.opt_colo_dead_methods)
self.option_context.add_option(self.opt_tables_metrics)
end
# The main function of the C
compiler.new_file("{mainmodule.name}.main")
+ compiler.compile_nitni_global_ref_functions
compiler.compile_main_function
+ compiler.compile_finalizer_function
# compile methods
for m in mainmodule.in_importation.greaters do
private var undead_types: Set[MType] = new HashSet[MType]
private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
- private var type_layout: nullable Layout[MType]
- private var resolution_layout: nullable Layout[MType]
- protected var method_layout: nullable Layout[PropertyLayoutElement]
- protected var attr_layout: nullable Layout[MAttribute]
+ private var type_ids: Map[MType, Int]
+ private var type_colors: Map[MType, Int]
+ private var opentype_colors: Map[MType, Int]
+ protected var method_colors: Map[PropertyLayoutElement, Int]
+ protected var attr_colors: Map[MAttribute, Int]
init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
super(mainmodule, mmbuilder)
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
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]
var rta = runtime_type_analysis
# Layouts
- var mclasses = new HashSet[MClass].from(modelbuilder.model.mclasses)
var poset = mainmodule.flatten_mclass_hierarchy
+ var mclasses = new HashSet[MClass].from(poset)
var colorer = new POSetColorer[MClass]
colorer.colorize(poset)
mattributes[mclass] = new HashSet[MAttribute]
for mprop in self.mainmodule.properties(mclass) do
if mprop isa MMethod then
- if modelbuilder.toolcontext.opt_no_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
+ if not modelbuilder.toolcontext.opt_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
dead_methods.add(mprop)
continue
end
# methods coloration
var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts)
- self.method_layout = new Layout[PropertyLayoutElement]
- self.method_layout.pos = meth_colorer.colorize(mmethods)
- self.method_tables = build_method_tables(mclasses, super_calls)
- self.compile_color_consts(method_layout.pos)
+ method_colors = meth_colorer.colorize(mmethods)
+ method_tables = build_method_tables(mclasses, super_calls)
+ compile_color_consts(method_colors)
# attribute null color to dead methods and supercalls
for mproperty in dead_methods do
# attributes coloration
var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts)
- self.attr_layout = new Layout[MAttribute]
- self.attr_layout.pos = attr_colorer.colorize(mattributes)
- self.attr_tables = build_attr_tables(mclasses)
- self.compile_color_consts(attr_layout.pos)
+ attr_colors = attr_colorer.colorize(mattributes)
+ attr_tables = build_attr_tables(mclasses)
+ compile_color_consts(attr_colors)
end
fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do
- var layout = self.method_layout
var tables = new HashMap[MClass, Array[nullable MPropDef]]
for mclass in mclasses do
var table = new Array[nullable MPropDef]
- var supercalls = new List[MMethodDef]
-
- # first, fill table from parents by reverse linearization order
- var parents = new Array[MClass]
- if mainmodule.flatten_mclass_hierarchy.has(mclass) then
- parents = mclass.in_hierarchy(mainmodule).greaters.to_a
- self.mainmodule.linearize_mclasses(parents)
- end
-
- for parent in parents do
- if parent == mclass then continue
- for mproperty in self.mainmodule.properties(parent) do
- if not mproperty isa MMethod then continue
- if not layout.pos.has_key(mproperty) then continue
- var color = layout.pos[mproperty]
- if table.length <= color then
- for i in [table.length .. color[ do
- table[i] = null
- end
- end
- for mpropdef in mproperty.mpropdefs do
- if mpropdef.mclassdef.mclass == parent then
- table[color] = mpropdef
- end
- end
- end
+ tables[mclass] = table
- # lookup for super calls in super classes
- for mmethoddef in super_calls do
- for mclassdef in parent.mclassdefs do
- if mclassdef.mpropdefs.has(mmethoddef) then
- supercalls.add(mmethoddef)
- end
- end
- end
- end
+ var mproperties = self.mainmodule.properties(mclass)
+ var mtype = mclass.intro.bound_mtype
- # then override with local properties
- for mproperty in self.mainmodule.properties(mclass) do
+ for mproperty in mproperties do
if not mproperty isa MMethod then continue
- if not layout.pos.has_key(mproperty) then continue
- var color = layout.pos[mproperty]
+ if not method_colors.has_key(mproperty) then continue
+ var color = method_colors[mproperty]
if table.length <= color then
for i in [table.length .. color[ do
table[i] = null
end
end
- for mpropdef in mproperty.mpropdefs do
- if mpropdef.mclassdef.mclass == mclass then
- table[color] = mpropdef
- end
- end
+ table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
end
- # lookup for super calls in local class
- for mmethoddef in super_calls do
- for mclassdef in mclass.mclassdefs do
- if mclassdef.mpropdefs.has(mmethoddef) then
- supercalls.add(mmethoddef)
- end
- end
- end
- # insert super calls in table according to receiver
- for supercall in supercalls do
- var color = layout.pos[supercall]
+ for supercall in super_calls do
+ if not mtype.collect_mclassdefs(mainmodule).has(supercall.mclassdef) then continue
+
+ var color = method_colors[supercall]
if table.length <= color then
for i in [table.length .. color[ do
table[i] = null
end
end
- var mmethoddef = supercall.lookup_next_definition(self.mainmodule, mclass.intro.bound_mtype)
+ var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype)
table[color] = mmethoddef
end
- tables[mclass] = table
+
end
return tables
end
fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
- var layout = self.attr_layout
var tables = new HashMap[MClass, Array[nullable MPropDef]]
for mclass in mclasses do
var table = new Array[nullable MPropDef]
- # first, fill table from parents by reverse linearization order
- var parents = new Array[MClass]
- if mainmodule.flatten_mclass_hierarchy.has(mclass) then
- parents = mclass.in_hierarchy(mainmodule).greaters.to_a
- self.mainmodule.linearize_mclasses(parents)
- end
- for parent in parents do
- if parent == mclass then continue
- for mproperty in self.mainmodule.properties(parent) do
- if not mproperty isa MAttribute then continue
- var color = layout.pos[mproperty]
- if table.length <= color then
- for i in [table.length .. color[ do
- table[i] = null
- end
- end
- for mpropdef in mproperty.mpropdefs do
- if mpropdef.mclassdef.mclass == parent then
- table[color] = mpropdef
- end
- end
- end
- end
+ tables[mclass] = table
- # then override with local properties
- for mproperty in self.mainmodule.properties(mclass) do
+ var mproperties = self.mainmodule.properties(mclass)
+ var mtype = mclass.intro.bound_mtype
+
+ for mproperty in mproperties do
if not mproperty isa MAttribute then continue
- var color = layout.pos[mproperty]
+ if not attr_colors.has_key(mproperty) then continue
+ var color = attr_colors[mproperty]
if table.length <= color then
for i in [table.length .. color[ do
table[i] = null
end
end
- for mpropdef in mproperty.mpropdefs do
- if mpropdef.mclassdef.mclass == mclass then
- table[color] = mpropdef
- end
- end
+ table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
end
- tables[mclass] = table
end
return tables
end
var poset = poset_from_mtypes(mtypes)
var colorer = new POSetColorer[MType]
colorer.colorize(poset)
- self.type_layout = colorer.to_layout
- self.type_tables = self.build_type_tables(poset)
+ type_ids = colorer.ids
+ type_colors = colorer.colors
+ type_tables = build_type_tables(poset)
# VT and FT are stored with other unresolved types in the big resolution_tables
self.compile_resolution_tables(mtypes)
# Build type tables
fun build_type_tables(mtypes: POSet[MType]): Map[MType, Array[nullable MType]] do
var tables = new HashMap[MType, Array[nullable MType]]
- var layout = self.type_layout
for mtype in mtypes do
var table = new Array[nullable MType]
for sup in mtypes[mtype].greaters do
- var color: Int
- if layout isa PHLayout[MType, MType] then
- color = layout.hashes[mtype][sup]
- else
- color = layout.pos[sup]
- end
+ var color = type_colors[sup]
if table.length <= color then
for i in [table.length .. color[ do
table[i] = null
end
# Compute the table layout with the prefered method
- var resolution_builder = new ResolutionColorer
- self.resolution_layout = resolution_builder.build_layout(mtype2unresolved)
- self.resolution_tables = self.build_resolution_tables(mtype2unresolved)
+ var colorer = new BucketsColorer[MType, MType]
+ opentype_colors = colorer.colorize(mtype2unresolved)
+ resolution_tables = self.build_resolution_tables(mtype2unresolved)
# Compile a C constant for each collected unresolved type.
# Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
end
var all_unresolved_types_colors = new HashMap[MType, Int]
for t in all_unresolved do
- if self.resolution_layout.pos.has_key(t) then
- all_unresolved_types_colors[t] = self.resolution_layout.pos[t]
+ if opentype_colors.has_key(t) then
+ all_unresolved_types_colors[t] = opentype_colors[t]
else
all_unresolved_types_colors[t] = -1
end
fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
var tables = new HashMap[MClassType, Array[nullable MType]]
- var layout = self.resolution_layout
for mclasstype, mtypes in elements do
var table = new Array[nullable MType]
for mtype in mtypes do
- var color: Int
- if layout isa PHLayout[MClassType, MType] then
- color = layout.hashes[mclasstype][mtype]
- else
- color = layout.pos[mtype]
- end
+ var color = opentype_colors[mtype]
if table.length <= color then
for i in [table.length .. color[ do
table[i] = null
fun compile_type_to_c(mtype: MType)
do
assert not mtype.need_anchor
- var layout = self.type_layout
var is_live = mtype isa MClassType and runtime_type_analysis.live_types.has(mtype)
var is_cast_live = runtime_type_analysis.live_cast_types.has(mtype)
var c_name = mtype.c_name
# type id (for cast target)
if is_cast_live then
- v.add_decl("{layout.ids[mtype]},")
+ v.add_decl("{type_ids[mtype]},")
else
v.add_decl("-1, /*CAST DEAD*/")
end
# type color (for cast target)
if is_cast_live then
- if layout isa PHLayout[MType, MType] then
- v.add_decl("{layout.masks[mtype]},")
- else
- v.add_decl("{layout.pos[mtype]},")
- end
+ v.add_decl("{type_colors[mtype]},")
else
v.add_decl("-1, /*CAST DEAD*/")
end
# resolution table (for receiver)
if is_live then
- var mclass_type = mtype
- if mclass_type isa MNullableType then mclass_type = mclass_type.mtype
+ var mclass_type = mtype.as_notnullable
assert mclass_type isa MClassType
if resolution_tables[mclass_type].is_empty then
v.add_decl("NULL, /*NO RESOLUTIONS*/")
if stype == null then
v.add_decl("-1, /* empty */")
else
- v.add_decl("{layout.ids[stype]}, /* {stype} */")
+ v.add_decl("{type_ids[stype]}, /* {stype} */")
end
end
v.add_decl("\},")
fun compile_type_resolution_table(mtype: MType) do
- var mclass_type: MClassType
- if mtype isa MNullableType then
- mclass_type = mtype.mtype.as(MClassType)
- else
- mclass_type = mtype.as(MClassType)
- end
-
- var layout = self.resolution_layout
+ var mclass_type = mtype.as_notnullable.as(MClassType)
# extern const struct resolution_table_X resolution_table_X
self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
# const struct fts_table_X fts_table_X
var v = new_visitor
v.add_decl("const struct types resolution_table_{mtype.c_name} = \{")
- if layout isa PHLayout[MClassType, MType] then
- v.add_decl("{layout.masks[mclass_type]},")
- else
- v.add_decl("0, /* dummy */")
- end
+ v.add_decl("0, /* dummy */")
v.add_decl("\{")
for t in self.resolution_tables[mclass_type] do
if t == null then
# the value stored is tv.
var tv = t.resolve_for(mclass_type, mclass_type, self.mainmodule, true)
# FIXME: What typeids means here? How can a tv not be live?
- if self.type_layout.ids.has_key(tv) then
+ if type_ids.has_key(tv) then
v.require_declaration("type_{tv.c_name}")
v.add_decl("&type_{tv.c_name}, /* {t}: {tv} */")
else
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} */")
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
- if not rta.live_types.has(mtype) then return
+ #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) 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}")
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
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}")
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
v.require_declaration("class_{c_name}")
v.add("{res}->class = &class_{c_name};")
self.generate_init_attr(v, res, mtype)
+ v.set_finalizer res
v.add("return {res};")
end
v.add("\}")
v.add_abort("type null")
v.add("\}")
v.add("if({t}->table_size == 0) \{")
- v.add("fprintf(stderr, \"Insantiation of a dead type: %s\\n\", {t}->name);")
+ v.add("PRINT_ERROR(\"Insantiation of a dead type: %s\\n\", {t}->name);")
v.add_abort("type dead")
v.add("\}")
end
redef fun compile_nitni_structs
do
- self.header.add_decl("struct nitni_instance \{struct instance *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 */
+ struct instance *value;
+\};
+"""
+ super
end
-
+
redef fun finalize_ffi_for_module(mmodule)
do
var old_module = self.mainmodule
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
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! */")
- 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.require_declaration("BOX_{valtype.c_name}")
self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
return res
- else if value.mtype.ctype == "void*" and mtype.ctype == "void*" then
+ else if (value.mtype.ctype == "void*" and mtype.ctype == "void*") or
+ (value.mtype.ctype == "char*" and mtype.ctype == "void*") or
+ (value.mtype.ctype == "void*" and mtype.ctype == "char*") 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
+
+ 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
do
var rta = compiler.runtime_type_analysis
var recv = args.first.mtype
- if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null then
+ var mmethod = callsite.mproperty
+ # TODO: Inlining of new-style constructors
+ if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then
var tgs = rta.live_targets(callsite)
if tgs.length == 1 then
# DIRECT CALL
- var mmethod = callsite.mproperty
self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args)
var res0 = before_send(mmethod, args)
var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
do
var res: nullable RuntimeVariable = null
var recv = arguments.first
- var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or mmethod.name == "==" or mmethod.name == "!="
+ var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or mmethod.name == "==" or mmethod.name == "!="
var maybenull = recv.mcasttype isa MNullableType and consider_null
if maybenull then
self.add("if ({recv} == NULL) \{")
# 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} */")
self.require_declaration(mtype.const_color)
var col = mtype.const_color
self.add("if({col} == -1) \{")
- self.add("fprintf(stderr, \"Resolution of a dead open type: %s\\n\", \"{mtype.to_s.escape_to_c}\");")
+ self.add("PRINT_ERROR(\"Resolution of a dead open type: %s\\n\", \"{mtype.to_s.escape_to_c}\");")
self.add_abort("open type dead")
self.add("\}")
end
add_abort("cast type null")
add("\}")
add("if({t}->id == -1 || {t}->color == -1) \{")
- add("fprintf(stderr, \"Try to cast on a dead cast type: %s\\n\", {t}->name);")
+ add("PRINT_ERROR(\"Try to cast on a dead cast type: %s\\n\", {t}->name);")
add_abort("cast type dead")
add("\}")
end
self.add("count_type_test_resolved_{tag}++;")
end
else
- self.add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
+ self.add("PRINT_ERROR(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); show_backtrace(1);")
end
# check color is in table
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}")
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
fun can_be_primitive(value: RuntimeVariable): Bool
do
- var t = value.mcasttype
- if t isa MNullableType then t = t.mtype
+ var t = value.mcasttype.as_notnullable
if not t isa MClassType then return false
var k = t.mclass.kind
return k == interface_kind or t.ctype != "val*"
return res
end
- fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
+ redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
do
var mtype = self.get_class("NativeArray").get_mtype([elttype])
self.require_declaration("NEW_{mtype.mclass.c_name}")
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
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"
- self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
+ var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
+ self.add("memmove({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
return
end
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
redef class MProperty
+ super PropertyLayoutElement
fun const_color: String do return "COLOR_{c_name}"
end
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