# Separate compilation of a Nit program with generic type erasure
module separate_erasure_compiler
+intrude import separate_compiler
-import separate_compiler
-
+# Add separate erased compiler specific options
redef class ToolContext
# --erasure
var opt_erasure: OptionBool = new OptionBool("Erase generic types", "--erasure")
-
# --no-check-erasure-cast
var opt_no_check_erasure_cast: OptionBool = new OptionBool("Disable implicit casts on unsafe return with erasure-typing policy (dangerous)", "--no-check-erasure-cast")
var time0 = get_time
self.toolcontext.info("*** COMPILING TO C ***", 1)
- var compiler = new SeparateErasureCompiler(mainmodule, runtime_type_analysis, self)
+ var compiler = new SeparateErasureCompiler(mainmodule, self, runtime_type_analysis)
compiler.compile_header
# compile class structures
+ compiler.new_file
for m in mainmodule.in_importation.greaters do
for mclass in m.intro_mclasses do
compiler.compile_class_to_c(mclass)
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
class SeparateErasureCompiler
super SeparateCompiler
- private var class_ids: HashMap[MClass, Int] = new HashMap[MClass, Int]
- private var class_colors: Map[MClass, Int]
+ private var class_layout: nullable TypingLayout[MClass]
private var class_tables: Map[MClass, Array[nullable MClass]]
- init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
- var mclasses = new HashSet[MClass]
- mclasses.add_all(mmbuilder.model.mclasses)
+ protected var vt_layout: nullable PropertyLayout[MVirtualTypeProp]
+ protected var vt_tables: Map[MClass, Array[nullable MPropDef]]
- # classes coloration
- if modelbuilder.toolcontext.opt_phmod_typing.value then
- # set type unique id
- for mclass in mclasses do
- self.class_ids[mclass] = self.class_ids.length + 1
- end
+ init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: RapidTypeAnalysis) do
+ super
- var class_coloring = new ClassModPerfectHashing(mainmodule)
- self.class_colors = class_coloring.compute_masks(mclasses, class_ids)
- self.class_tables = class_coloring.hash_type_tables(mclasses, class_ids, class_colors)
+ var mclasses = new HashSet[MClass].from(mmbuilder.model.mclasses)
- self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
+ var layout_builder: TypingLayoutBuilder[MClass]
+ if modelbuilder.toolcontext.opt_phmod_typing.value then
+ layout_builder = new PHClassLayoutBuilder(mainmodule, new PHModOperator)
else if modelbuilder.toolcontext.opt_phand_typing.value then
- # set type unique id
- for mclass in mclasses do
- self.class_ids[mclass] = self.class_ids.length + 1
- end
+ layout_builder = new PHClassLayoutBuilder(mainmodule, new PHAndOperator)
+ else if modelbuilder.toolcontext.opt_bm_typing.value then
+ layout_builder = new BMClassLayoutBuilder(mainmodule)
+ else
+ layout_builder = new CLClassLayoutBuilder(mainmodule)
+ end
+ self.class_layout = layout_builder.build_layout(mclasses)
+ self.class_tables = self.build_class_typing_tables(mclasses)
+
+ # vt coloration
+ var vt_coloring = new CLPropertyLayoutBuilder[MVirtualTypeProp](mainmodule)
+ var vt_layout = vt_coloring.build_layout(mclasses)
+ self.vt_tables = build_vt_tables(mclasses, vt_layout)
+ self.compile_color_consts(vt_layout.pos)
+ self.vt_layout = vt_layout
+ end
- var class_coloring = new ClassAndPerfectHashing(mainmodule)
- self.class_colors = class_coloring.compute_masks(mclasses, class_ids)
- self.class_tables = class_coloring.hash_type_tables(mclasses, class_ids, class_colors)
+ fun build_vt_tables(mclasses: Set[MClass], layout: PropertyLayout[MProperty]): Map[MClass, Array[nullable MPropDef]] do
+ 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 = self.mainmodule.super_mclasses(mclass)
+ var lin = self.mainmodule.reverse_linearize_mclasses(parents)
+ for parent in lin do
+ for mproperty in self.mainmodule.properties(parent) do
+ if not mproperty isa MVirtualTypeProp 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
- self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
- else
- var class_coloring
- if modelbuilder.toolcontext.opt_bm_typing.value then
- class_coloring = new NaiveClassColoring(mainmodule)
- else
- class_coloring = new ClassColoring(mainmodule)
+ # then override with local properties
+ for mproperty in self.mainmodule.properties(mclass) do
+ if not mproperty isa MVirtualTypeProp 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 == mclass then
+ table[color] = mpropdef
+ end
+ end
end
- # set type unique id
- for mclass in mclasses do
- self.class_ids[mclass] = self.class_ids.length + 1
+ tables[mclass] = table
+ end
+ return tables
+ end
+
+ # Build class tables
+ fun build_class_typing_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MClass]] do
+ var tables = new HashMap[MClass, Array[nullable MClass]]
+ var layout = self.class_layout
+ for mclass in mclasses do
+ var table = new Array[nullable MClass]
+ var supers = new HashSet[MClass]
+ supers.add_all(self.mainmodule.super_mclasses(mclass))
+ supers.add(mclass)
+ for sup in supers do
+ var color: Int
+ if layout isa PHTypingLayout[MClass] then
+ color = layout.hashes[mclass][sup]
+ else
+ color = layout.pos[sup]
+ end
+ if table.length <= color then
+ for i in [table.length .. color[ do
+ table[i] = null
+ end
+ end
+ table[color] = sup
end
- self.class_colors = class_coloring.colorize(modelbuilder.model.mclasses)
- self.class_tables = class_coloring.build_type_tables(modelbuilder.model.mclasses, class_colors)
+ tables[mclass] = table
end
+ return tables
end
redef fun compile_header_structs do
self.header.add_decl("struct type_table \{ int size; int table[1]; \}; /* colorized type table. */")
self.header.add_decl("struct vts_entry \{ short int is_nullable; struct class *class; \}; /* link (nullable or not) between the vts and is bound. */")
- if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+ if self.vt_layout isa PHPropertyLayoutBuilder[MVirtualTypeProp] then
self.header.add_decl("struct vts_table \{ int mask; struct vts_entry vts[1]; \}; /* vts list of a C type representation. */")
else
self.header.add_decl("struct vts_table \{ struct vts_entry vts[1]; \}; /* vts list of a C type representation. */")
end
+ if modelbuilder.toolcontext.opt_phmod_typing.value then
+ self.header.add_decl("#define HASH(mask, id) ((mask)%(id))")
+ else if modelbuilder.toolcontext.opt_phand_typing.value then
+ self.header.add_decl("#define HASH(mask, id) ((mask)&(id))")
+ end
+
self.header.add_decl("typedef struct val \{ struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
end
var v = self.new_visitor
v.add_decl("/* runtime class {c_name} */")
- var idnum = classids.length
- var idname = "ID_" + c_name
- self.classids[mtype] = idname
- #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
self.header.add_decl("extern const struct class_{c_name} class_{c_name};")
self.header.add_decl("struct class_{c_name} \{")
# Build class vft
v.add_decl("const struct class_{c_name} class_{c_name} = \{")
- v.add_decl("{self.class_ids[mclass]},")
+ v.add_decl("{self.class_layout.ids[mclass]},")
v.add_decl("\"{mclass.name}\", /* class_name_string */")
v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
- v.add_decl("{self.class_colors[mclass]},")
+ var layout = self.class_layout
+ if layout isa PHTypingLayout[MClass] then
+ v.add_decl("{layout.masks[mclass]},")
+ else
+ v.add_decl("{layout.pos[mclass]},")
+ end
if build_class_vts_table(mclass) then
v.add_decl("(const struct vts_table*) &vts_table_{c_name},")
else
if msuper == null then
v.add_decl("-1, /* empty */")
else
- v.add_decl("{self.class_ids[msuper]}, /* {msuper} */")
+ v.add_decl("{self.class_layout.ids[msuper]}, /* {msuper} */")
end
end
v.add_decl("\}")
self.header.add_decl("extern const struct vts_table_{mclass.c_name} vts_table_{mclass.c_name};")
self.header.add_decl("struct vts_table_{mclass.c_name} \{")
- if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
+ if self.vt_layout isa PHPropertyLayoutBuilder[MVirtualTypeProp] then
self.header.add_decl("int mask;")
end
self.header.add_decl("struct vts_entry vts[{self.vt_tables[mclass].length}];")
var v = new_visitor
v.add_decl("const struct vts_table_{mclass.c_name} vts_table_{mclass.c_name} = \{")
- if modelbuilder.toolcontext.opt_phmod_typing.value or modelbuilder.toolcontext.opt_phand_typing.value then
- v.add_decl("{vt_masks[mclass]},")
+ if self.vt_layout isa PHPropertyLayoutBuilder[MVirtualTypeProp] then
+ #TODO redo this when PHPropertyLayoutBuilder will be implemented
+ #v.add_decl("{vt_masks[mclass]},")
end
v.add_decl("\{")
v.add_decl("\{-1, NULL\}, /* empty */")
else
var is_null = 0
- var bound = retrieve_vt_bound(mclass.intro.bound_mtype, vt.bound)
+ var bound = retrieve_vt_bound(mclass.intro.bound_mtype, vt.as(MVirtualTypeDef).bound)
while bound isa MNullableType do
bound = retrieve_vt_bound(mclass.intro.bound_mtype, bound.mtype)
is_null = 1
end
redef fun new_visitor do return new SeparateErasureCompilerVisitor(self)
+
+ # Stats
+
+ redef fun display_sizes
+ do
+ print "# size of tables"
+ print "\trs size\trs hole\tst size\tst hole"
+ var rt_table = 0
+ var rt_holes = 0
+ var st_table = 0
+ var st_holes = 0
+ var rtables = vt_tables
+ for unanch, table in rtables do
+ rt_table += table.length
+ for e in table do if e == null then rt_holes += 1
+ end
+
+ var ttables = class_tables
+ for t, table in ttables do
+ st_table += table.length
+ for e in table do if e == null then st_holes += 1
+ end
+ print "\t{rt_table}\t{rt_holes}\t{st_table}\t{st_holes}"
+ end
end
class SeparateErasureCompilerVisitor
return res
end
- redef fun init_instance(mtype)
- do
- return self.new_expr("NEW_{mtype.mclass.c_name}()", mtype)
- end
+ redef fun init_instance(mtype) do return self.new_expr("NEW_{mtype.mclass.c_name}()", mtype)
redef fun type_test(value, mtype, tag)
do
self.add_decl("int {cltype};")
var idtype = self.get_name("idtype")
self.add_decl("int {idtype};")
- var is_nullable = self.get_name("is_nullable")
- self.add_decl("short int {is_nullable};")
- var is_null = self.get_name("is_null")
- self.add_decl("short int {is_null};")
- var maybe_null = 0
+ var maybe_null = self.maybe_null(value)
+ var accept_null = "0"
if mtype isa MNullableType then
mtype = mtype.mtype
- maybe_null = 1
- self.add("{is_nullable} = 1;")
+ accept_null = "1"
end
if mtype isa MParameterType then
# Here we get the bound of the the formal type (eh, erasure...)
mtype = mtype.resolve_for(self.frame.mpropdef.mclassdef.bound_mtype, self.frame.mpropdef.mclassdef.bound_mtype, self.frame.mpropdef.mclassdef.mmodule, false)
if mtype isa MNullableType then
mtype = mtype.mtype
- maybe_null = 1
- self.add("{is_nullable} = 1;")
+ accept_null = "1"
end
end
- if mtype isa MVirtualType then
- # FIXME virtual types should not be erased but got from the class table of the current receiver (self.frame.arguments.first)
- #mtype = mtype.resolve_for(self.frame.mpropdef.mclassdef.bound_mtype, self.frame.mpropdef.mclassdef.bound_mtype, self.frame.mpropdef.mclassdef.mmodule, true)
- #if mtype isa MNullableType then
- # mtype = mtype.mtype
- # maybe_null = true
- #end
- 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}*/")
var type_table
if value.mtype.ctype == "val*" then
class_ptr = "{value}->class->"
- self.add("{is_null} = {value} == NULL;")
else
var mclass = value.mtype.as(MClassType).mclass
class_ptr = "class_{mclass.c_name}."
- self.add("{is_null} = 0;")
end
if mtype isa MClassType then
self.add("{cltype} = class_{mtype.mclass.c_name}.color;")
self.add("{idtype} = class_{mtype.mclass.c_name}.id;")
- if maybe_null == 0 then
- self.add("{is_nullable} = 0;")
- end
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
var entry = self.get_name("entry")
self.add("struct vts_entry {entry};")
- if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
+ if self.compiler.as(SeparateErasureCompiler).vt_layout isa PHPropertyLayoutBuilder[MVirtualTypeProp] then
self.add("{entry} = {recv_ptr}vts_table->vts[HASH({recv_ptr}vts_table->mask, {mtype.mproperty.const_color})];")
else
self.add("{entry} = {recv_ptr}vts_table->vts[{mtype.mproperty.const_color}];")
end
self.add("{cltype} = {entry}.class->color;")
self.add("{idtype} = {entry}.class->id;")
- if maybe_null == 0 then
+ if maybe_null and accept_null == "0" then
+ var is_nullable = self.get_name("is_nullable")
+ self.add_decl("short int {is_nullable};")
self.add("{is_nullable} = {entry}.is_nullable;")
+ accept_null = is_nullable.to_s
end
if compiler.modelbuilder.toolcontext.opt_typing_test_metrics.value then
self.compiler.count_type_test_unresolved[tag] += 1
end
# check color is in table
- self.add("if({is_null}) \{")
- self.add("{res} = {is_nullable};")
- self.add("\} else \{")
- if compiler.modelbuilder.toolcontext.opt_phmod_typing.value or compiler.modelbuilder.toolcontext.opt_phand_typing.value then
+ if maybe_null then
+ self.add("if({value} == NULL) \{")
+ self.add("{res} = {accept_null};")
+ self.add("\} else \{")
+ end
+ if self.compiler.as(SeparateErasureCompiler).class_layout isa PHTypingLayout[MClass] then
self.add("{cltype} = HASH({class_ptr}color, {idtype});")
end
self.add("if({cltype} >= {class_ptr}type_table->size) \{")
self.add("\} else \{")
self.add("{res} = {class_ptr}type_table->table[{cltype}] == {idtype};")
self.add("\}")
- self.add("\}")
+ if maybe_null then
+ self.add("\}")
+ end
return res
end