From: Jean Privat Date: Tue, 31 Mar 2015 03:21:57 +0000 (+0700) Subject: Merge: Rewrite the coloration for properties and types. X-Git-Tag: v0.7.3~2 X-Git-Url: http://nitlanguage.org?hp=-c Merge: Rewrite the coloration for properties and types. This introduce a new colorer, `POSetGroupColorer` that colors elements introduced by the classes in a class-hierarchy. The advantage of this new colorer is that it uses conflict graphs of classes to colorize elements. By comparison, the previously used colorers work with conflict graphs of elements; that are therefore much larger. An other advantage is that only the introductions of elements are needed by the colorer, so filling the information from the model is far more easier. The construction of the poset of types is also removed. Instead, subtyping tables are computed with a more standard way: * target cast types are grouped by classes: a map class->types is created * the map is colored: a table layout by class is computed * for each live type, the table layout of the associated class is used to build the type table Results are so good that most of the time of the coloring is removed. For nitc/nitc/nit Before: user: 0m6.044s total: 15096 MIr do_property_coloring: 1420 MIr do_type_coloring: 2600 MIr After: user: 0m5.608s (-7%) total: 12800 MIr (-15%) do_property_coloring: 452 MIr (-68%) do_type_coloring: 895 MIr (-65%) note that in the previous numbers, most of the time is done in the model to inherit or resolve things. Pure coloring algorithm is now negligible: conflict_graph: 34 MIr (<1% of the total Ir) coloring: 60 MIr (<1% of the total Ir) Unfortunately, with types the coloring can degenerate and produce big tables. If this is an issue, the options `--type-poset` use the previous coloring method for types Pull-Request: #1215 Reviewed-by: Alexandre Terrasa Reviewed-by: Lucas Bajolet Reviewed-by: Romain Chanoir Reviewed-by: Alexis Laferrière --- bb979d4c4ad336340e67414ad5f0897e602ce211 diff --combined src/compiler/abstract_compiler.nit index 311d71b,72e6447..43fd172 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@@ -23,6 -23,7 +23,7 @@@ import platfor import c_tools private import annotation import mixin + import counter # Add compiling options redef class ToolContext @@@ -121,30 -122,20 +122,30 @@@ redef class ModelBuilde protected fun write_and_make(compiler: AbstractCompiler) do var platform = compiler.target_platform - var toolchain = platform.toolchain(toolcontext) + var toolchain = platform.toolchain(toolcontext, compiler) compile_dir = toolchain.compile_dir - toolchain.write_and_make compiler + toolchain.write_and_make end end redef class Platform # The specific tool-chain associated to the platform - fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext) + fun toolchain(toolcontext: ToolContext, compiler: AbstractCompiler): Toolchain + do + return new MakefileToolchain(toolcontext, compiler) + end end +# Build toolchain for a specific target program, varies per `Platform` class Toolchain + + # Toolcontext var toolcontext: ToolContext + # Compiler of the target program + var compiler: AbstractCompiler + + # Directory where to generate all C files fun compile_dir: String do var compile_dir = toolcontext.opt_compile_dir.value @@@ -152,15 -143,13 +153,15 @@@ return compile_dir end - fun write_and_make(compiler: AbstractCompiler) is abstract + # Write all C files and compile them + fun write_and_make is abstract end +# Default toolchain using a Makefile class MakefileToolchain super Toolchain - redef fun write_and_make(compiler) + redef fun write_and_make do var compile_dir = compile_dir @@@ -173,11 -162,11 +174,11 @@@ compile_dir.mkdir var cfiles = new Array[String] - write_files(compiler, compile_dir, cfiles) + write_files(compile_dir, cfiles) # Generate the Makefile - write_makefile(compiler, compile_dir, cfiles) + write_makefile(compile_dir, cfiles) var time1 = get_time self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2) @@@ -189,14 -178,13 +190,14 @@@ time0 = time1 self.toolcontext.info("*** COMPILING C ***", 1) - compile_c_code(compiler, compile_dir) + compile_c_code(compile_dir) time1 = get_time self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2) end - fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) + # Write all source files to the `compile_dir` + fun write_files(compile_dir: String, cfiles: Array[String]) do var platform = compiler.target_platform if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings @@@ -293,14 -281,10 +294,14 @@@ self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2) end - fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk" + # Get the name of the Makefile to use + fun makefile_name: String do return "{compiler.mainmodule.c_name}.mk" - fun default_outname(mainmodule: MModule): String + # Get the default name of the executable to produce + fun default_outname: String do + var mainmodule = compiler.mainmodule + # Search a non fictive module var res = mainmodule.name while mainmodule.is_fictive do @@@ -315,14 -299,13 +316,14 @@@ do var res = self.toolcontext.opt_output.value if res != null then return res - res = default_outname(mainmodule) + res = default_outname var dir = self.toolcontext.opt_dir.value if dir != null then return dir.join_path(res) return res end - fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) + # Write the Makefile + fun write_makefile(compile_dir: String, cfiles: Array[String]) do var mainmodule = compiler.mainmodule var platform = compiler.target_platform @@@ -337,7 -320,7 +338,7 @@@ # 2. copy the binary at the right place in the `all` goal. outpath = mainmodule.c_name end - var makename = makefile_name(mainmodule) + var makename = makefile_name var makepath = "{compile_dir}/{makename}" var makefile = new FileWriter.open(makepath) @@@ -462,10 -445,9 +463,10 @@@ endi makepath.file_copy_to "{compile_dir}/Makefile" end - fun compile_c_code(compiler: AbstractCompiler, compile_dir: String) + # The C code is generated, compile it to an executable + fun compile_c_code(compile_dir: String) do - var makename = makefile_name(compiler.mainmodule) + var makename = makefile_name var makeflags = self.toolcontext.opt_make_flags.value if makeflags == null then makeflags = "" @@@ -608,8 -590,6 +609,8 @@@ abstract class AbstractCompile self.header.add_decl("#include ") self.header.add_decl("#include ") self.header.add_decl("#include ") + self.header.add_decl("#include \n") + self.header.add_decl("#include \n") self.header.add_decl("#include \"gc_chooser.h\"") self.header.add_decl("#ifdef ANDROID") self.header.add_decl(" #include ") @@@ -1042,14 -1022,6 +1043,6 @@@ extern void nitni_global_ref_decr( stru end fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self) - - # Division facility - # Avoid division by zero by returning the string "n/a" - fun div(a,b:Int):String - do - if b == 0 then return "n/a" - return ((a*10000/b).to_f / 100.0).to_precision(2) - end end # A file unit (may be more than one file if @@@ -1106,6 -1078,9 +1099,6 @@@ abstract class AbstractCompilerVisito self.writer = new CodeWriter(compiler.files.last) end - # Force to get the primitive class named `name` or abort - fun get_class(name: String): MClass do return self.compiler.mainmodule.get_primitive_class(name) - # Force to get the primitive property named `name` in the instance `recv` or abort fun get_property(name: String, recv: MType): MMethod do @@@ -1147,14 -1122,6 +1140,14 @@@ fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract + # Return an element of a native array. + # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays + fun native_array_get(native_array: RuntimeVariable, index: Int): RuntimeVariable is abstract + + # Store an element in a native array. + # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays + fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract + # Evaluate `args` as expressions in the call of `mpropdef` on `recv`. # This method is used to manage varargs in signatures and returns the real array # of runtime variables to use in the call. @@@ -1428,7 -1395,7 +1421,7 @@@ var recv var ctype = mtype.ctype assert mtype.mclass.name != "NativeArray" - if ctype == "val*" then + if not mtype.is_c_primitive then recv = init_instance(mtype) else if ctype == "char*" then recv = new_expr("NULL/*special!*/", mtype) @@@ -1449,64 -1416,37 +1442,64 @@@ end end + # The currently processed module + # + # alias for `compiler.mainmodule` + fun mmodule: MModule do return compiler.mainmodule + # Generate an integer value fun int_instance(value: Int): RuntimeVariable do - var res = self.new_var(self.get_class("Int").mclass_type) - self.add("{res} = {value};") + var t = mmodule.int_type + var res = new RuntimeVariable("{value.to_s}l", t, t) + return res + end + + # Generate a char value + fun char_instance(value: Char): RuntimeVariable + do + var t = mmodule.char_type + var res = new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t) + return res + end + + # Generate a float value + # + # FIXME pass a Float, not a string + fun float_instance(value: String): RuntimeVariable + do + var t = mmodule.float_type + var res = new RuntimeVariable("{value}", t, t) return res end # Generate an integer value fun bool_instance(value: Bool): RuntimeVariable do - var res = self.new_var(self.get_class("Bool").mclass_type) - if value then - self.add("{res} = 1;") - else - self.add("{res} = 0;") - end + var s = if value then "1" else "0" + var res = new RuntimeVariable(s, bool_type, bool_type) + return res + end + + # Generate the `null` value + fun null_instance: RuntimeVariable + do + var t = compiler.mainmodule.model.null_type + var res = new RuntimeVariable("((val*)NULL)", t, t) return res end # Generate a string value fun string_instance(string: String): RuntimeVariable do - var mtype = self.get_class("String").mclass_type + var mtype = mmodule.string_type var name = self.get_name("varonce") self.add_decl("static {mtype.ctype} {name};") var res = self.new_var(mtype) self.add("if (likely({name}!=NULL)) \{") self.add("{res} = {name};") self.add("\} else \{") - var native_mtype = self.get_class("NativeString").mclass_type + var native_mtype = mmodule.native_string_type var nat = self.new_var(native_mtype) self.add("{nat} = \"{string.escape_to_c}\";") var length = self.int_instance(string.length) @@@ -1814,16 -1754,12 +1807,16 @@@ redef class MTyp # Short name of the `ctype` to use in unions fun ctypename: String do return "val" + + # Is the associated C type a primitive one? + # + # ENSURE `result == (ctype != "val*")` + fun is_c_primitive: Bool do return false end redef class MClassType - redef fun ctype: String - do + redef var ctype is lazy do if mclass.name == "Int" then return "long" else if mclass.name == "Bool" then @@@ -1841,8 -1777,6 +1834,8 @@@ end end + redef var is_c_primitive is lazy do return ctype != "val*" + redef fun ctype_extern: String do if mclass.kind == extern_kind then @@@ -2332,7 -2266,7 +2325,7 @@@ redef class AAttrPropde if is_lazy then var set var ret = self.mpropdef.static_mtype - var useiset = ret.ctype == "val*" and not ret isa MNullableType + var useiset = not ret.is_c_primitive and not ret isa MNullableType var guard = self.mlazypropdef.mproperty if useiset then set = v.isset_attribute(self.mpropdef.mproperty, recv) @@@ -2347,7 -2281,7 +2340,7 @@@ v.assign(res, value) if not useiset then - var true_v = v.new_expr("1", v.bool_type) + var true_v = v.bool_instance(true) v.write_attribute(guard, arguments.first, true_v) end v.add("\}") @@@ -2360,9 -2294,9 +2353,9 @@@ v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1]) if is_lazy then var ret = self.mpropdef.static_mtype - var useiset = ret.ctype == "val*" and not ret isa MNullableType + var useiset = not ret.is_c_primitive and not ret isa MNullableType if not useiset then - v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.new_expr("1", v.bool_type)) + v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true)) end end else @@@ -2760,15 -2694,15 +2753,15 @@@ redef class AOrElseExp end redef class AIntExpr - redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null)) + redef fun expr(v) do return v.int_instance(self.value.as(not null)) end redef class AFloatExpr - redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float + redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float end redef class ACharExpr - redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null)) + redef fun expr(v) do return v.char_instance(self.value.as(not null)) end redef class AArrayExpr @@@ -2796,64 -2730,14 +2789,64 @@@ en redef class ASuperstringExpr redef fun expr(v) do - var array = new Array[RuntimeVariable] + var type_string = mtype.as(not null) + + # Collect elements of the superstring + var array = new Array[AExpr] for ne in self.n_exprs do + # Drop literal empty string. + # They appears in things like "{a}" that is ["", a, ""] if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings - var i = v.expr(ne, null) - array.add(i) + array.add(ne) + end + + # Store the allocated native array in a static variable + # For reusing later + var varonce = v.get_name("varonce") + v.add("if (unlikely({varonce}==NULL)) \{") + + # The native array that will contains the elements to_s-ized. + # For fast concatenation. + var a = v.native_array_instance(type_string, v.int_instance(array.length)) + + v.add_decl("static {a.mtype.ctype} {varonce};") + + # Pre-fill the array with the literal string parts. + # So they do not need to be filled again when reused + for i in [0..array.length[ do + var ne = array[i] + if not ne isa AStringFormExpr then continue + var e = v.expr(ne, null) + v.native_array_set(a, i, e) end - var a = v.array_instance(array, v.object_type) - var res = v.send(v.get_property("to_s", a.mtype), [a]) + + v.add("\} else \{") + # Take the native-array from the store. + # The point is to prevent that some recursive execution use (and corrupt) the same native array + # WARNING: not thread safe! (FIXME?) + v.add("{a} = {varonce};") + v.add("{varonce} = NULL;") + v.add("\}") + + # Stringify the elements and put them in the native array + var to_s_method = v.get_property("to_s", v.object_type) + for i in [0..array.length[ do + var ne = array[i] + if ne isa AStringFormExpr then continue + var e = v.expr(ne, null) + # Skip the `to_s` if the element is already a String + if not e.mcasttype.is_subtype(v.compiler.mainmodule, null, type_string) then + e = v.send(to_s_method, [e]).as(not null) + end + v.native_array_set(a, i, e) + end + + # Fast join the native string to get the result + var res = v.send(v.get_property("native_to_s", a.mtype), [a]) + + # We finish to work with the native array, + # so store it so that it can be reused + v.add("{varonce} = {a};") return res end end @@@ -2883,15 -2767,15 +2876,15 @@@ redef class AOrangeExp end redef class ATrueExpr - redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null)) + redef fun expr(v) do return v.bool_instance(true) end redef class AFalseExpr - redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null)) + redef fun expr(v) do return v.bool_instance(false) end redef class ANullExpr - redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null)) + redef fun expr(v) do return v.null_instance end redef class AIsaExpr @@@ -2919,7 -2803,7 +2912,7 @@@ redef class AAsNotnullExp var i = v.expr(self.n_expr, null) if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i - if i.mtype.ctype != "val*" then return i + if i.mtype.is_c_primitive then return i v.add("if (unlikely({i} == NULL)) \{") v.add_abort("Cast failed") diff --combined src/compiler/separate_compiler.nit index f590c1a,555c220..dab4a79 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@@ -59,6 -59,8 +59,8 @@@ redef class ToolContex var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods") # --tables-metrics var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics") + # --type-poset + var opt_type_poset = new OptionBool("Build a poset of types to create more condensed tables.", "--type-poset") redef init do @@@ -72,6 -74,7 +74,7 @@@ 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_colo_dead_methods) self.option_context.add_option(self.opt_tables_metrics) + self.option_context.add_option(self.opt_type_poset) end redef fun process_options(args) @@@ -146,8 -149,6 +149,6 @@@ class SeparateCompile private var type_ids: Map[MType, Int] is noinit private var type_colors: Map[MType, Int] is noinit private var opentype_colors: Map[MType, Int] is noinit - protected var method_colors: Map[PropertyLayoutElement, Int] is noinit - protected var attr_colors: Map[MAttribute, Int] is noinit init do var file = new_file("nit.common") @@@ -268,7 -269,7 +269,7 @@@ if mclass.mclass_type.ctype_extern == "val*" then return 0 else if mclass.kind == extern_kind and mclass.name != "NativeString" then - return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")] + return self.box_kinds[self.mainmodule.pointer_type.mclass] else return self.box_kinds[mclass] end @@@ -305,170 -306,147 +306,147 @@@ private var color_consts_done = new HashSet[Object] + # The conflict graph of classes used for coloration + var class_conflict_graph: POSetConflictGraph[MClass] is noinit + # colorize classe properties fun do_property_coloring do var rta = runtime_type_analysis - # Layouts - var poset = mainmodule.flatten_mclass_hierarchy - var mclasses = new HashSet[MClass].from(poset) - var colorer = new POSetColorer[MClass] - colorer.colorize(poset) - - # The dead methods, still need to provide a dead color symbol - var dead_methods = new Array[MMethod] + # Class graph + var mclasses = mainmodule.flatten_mclass_hierarchy + class_conflict_graph = mclasses.to_conflict_graph - # lookup properties to build layout with + # Prepare to collect elements to color and build layout with var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]] var mattributes = new HashMap[MClass, Set[MAttribute]] + + # The dead methods and super-call, still need to provide a dead color symbol + var dead_methods = new Array[PropertyLayoutElement] + for mclass in mclasses do mmethods[mclass] = new HashSet[PropertyLayoutElement] mattributes[mclass] = new HashSet[MAttribute] - for mprop in self.mainmodule.properties(mclass) do - if mprop isa MMethod 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 - mmethods[mclass].add(mprop) - else if mprop isa MAttribute then - mattributes[mclass].add(mprop) - end + end + + # Pre-collect known live things + if rta != null then + for m in rta.live_methods do + mmethods[m.intro_mclassdef.mclass].add m + end + for m in rta.live_super_sends do + var mclass = m.mclassdef.mclass + mmethods[mclass].add m end end - # Collect all super calls (dead or not) - var all_super_calls = new HashSet[MMethodDef] - for mmodule in self.mainmodule.in_importation.greaters do - for mclassdef in mmodule.mclassdefs do - for mpropdef in mclassdef.mpropdefs do - if not mpropdef isa MMethodDef then continue - if mpropdef.has_supercall then - all_super_calls.add(mpropdef) + for m in mainmodule.in_importation.greaters do for cd in m.mclassdefs do + var mclass = cd.mclass + # Collect methods ad attributes + for p in cd.intro_mproperties do + if p isa MMethod then + if rta == null then + mmethods[mclass].add p + else if not rta.live_methods.has(p) then + dead_methods.add p end + else if p isa MAttribute then + mattributes[mclass].add p end end - end - # lookup super calls and add it to the list of mmethods to build layout with - var super_calls - if rta != null then - super_calls = rta.live_super_sends - else - super_calls = all_super_calls - end - - for mmethoddef in super_calls do - var mclass = mmethoddef.mclassdef.mclass - mmethods[mclass].add(mmethoddef) - for descendant in mclass.in_hierarchy(self.mainmodule).smallers do - mmethods[descendant].add(mmethoddef) + # Collect all super calls (dead or not) + for mpropdef in cd.mpropdefs do + if not mpropdef isa MMethodDef then continue + if mpropdef.has_supercall then + if rta == null then + mmethods[mclass].add mpropdef + else if not rta.live_super_sends.has(mpropdef) then + dead_methods.add mpropdef + end + end end end # methods coloration - var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts) - method_colors = meth_colorer.colorize(mmethods) - method_tables = build_method_tables(mclasses, super_calls) + var meth_colorer = new POSetGroupColorer[MClass, PropertyLayoutElement](class_conflict_graph, mmethods) + var method_colors = meth_colorer.colors compile_color_consts(method_colors) - # attribute null color to dead methods and supercalls - for mproperty in dead_methods do - compile_color_const(new_visitor, mproperty, -1) - end - for mpropdef in all_super_calls do - if super_calls.has(mpropdef) then continue - compile_color_const(new_visitor, mpropdef, -1) - end + # give null color to dead methods and supercalls + for mproperty in dead_methods do compile_color_const(new_visitor, mproperty, -1) - # attributes coloration - var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts) - attr_colors = attr_colorer.colorize(mattributes) - attr_tables = build_attr_tables(mclasses) + # attribute coloration + var attr_colorer = new POSetGroupColorer[MClass, MAttribute](class_conflict_graph, mattributes) + var attr_colors = attr_colorer.colors#ize(poset, mattributes) compile_color_consts(attr_colors) - end - fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do - var tables = new HashMap[MClass, Array[nullable MPropDef]] + # Build method and attribute tables + method_tables = new HashMap[MClass, Array[nullable MPropDef]] + attr_tables = new HashMap[MClass, Array[nullable MProperty]] for mclass in mclasses do - var table = new Array[nullable MPropDef] - tables[mclass] = table + if not mclass.has_new_factory and (mclass.kind == abstract_kind or mclass.kind == interface_kind) then continue + if rta != null and not rta.live_classes.has(mclass) then continue - var mproperties = self.mainmodule.properties(mclass) var mtype = mclass.intro.bound_mtype - for mproperty in mproperties do - if not mproperty isa MMethod then continue - 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 - table[color] = mproperty.lookup_first_definition(mainmodule, mtype) - end - - 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 + # Resolve elements in the layout to get the final table + var meth_layout = meth_colorer.build_layout(mclass) + var meth_table = new Array[nullable MPropDef].with_capacity(meth_layout.length) + method_tables[mclass] = meth_table + for e in meth_layout do + if e == null then + meth_table.add null + else if e isa MMethod then + # Standard method call of `e` + meth_table.add e.lookup_first_definition(mainmodule, mtype) + else if e isa MMethodDef then + # Super-call in the methoddef `e` + meth_table.add e.lookup_next_definition(mainmodule, mtype) + else + abort end - var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype) - table[color] = mmethoddef end + # Do not need to resolve attributes as only the position is used + attr_tables[mclass] = attr_colorer.build_layout(mclass) end - return tables - end - - fun build_attr_tables(mclasses: Set[MClass]): 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] - tables[mclass] = table - var mproperties = self.mainmodule.properties(mclass) - var mtype = mclass.intro.bound_mtype end # colorize live types of the program - private fun do_type_coloring: POSet[MType] do + private fun do_type_coloring: Collection[MType] do # Collect types to colorize var live_types = runtime_type_analysis.live_types var live_cast_types = runtime_type_analysis.live_cast_types - # Compute colors - var poset = poset_from_mtypes(live_types, live_cast_types) - var colorer = new POSetColorer[MType] - colorer.colorize(poset) - type_ids = colorer.ids - type_colors = colorer.colors - type_tables = build_type_tables(poset) + var res = new HashSet[MType] + res.add_all live_types + res.add_all live_cast_types + + if modelbuilder.toolcontext.opt_type_poset.value then + # Compute colors with a type poset + var poset = poset_from_mtypes(live_types, live_cast_types) + var colorer = new POSetColorer[MType] + colorer.colorize(poset) + type_ids = colorer.ids + type_colors = colorer.colors + type_tables = build_type_tables(poset) + else + # Compute colors using the class poset + # Faster to compute but the number of holes can degenerate + compute_type_test_layouts(live_types, live_cast_types) + + type_ids = new HashMap[MType, Int] + for x in res do type_ids[x] = type_ids.length + 1 + end # VT and FT are stored with other unresolved types in the big resolution_tables self.compute_resolution_tables(live_types) - return poset + return res end private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do @@@ -527,6 -505,48 +505,48 @@@ return tables end + + private fun compute_type_test_layouts(mtypes: Set[MClassType], cast_types: Set[MType]) do + # Group cast_type by their classes + var bucklets = new HashMap[MClass, Set[MType]] + for e in cast_types do + var c = e.as_notnullable.as(MClassType).mclass + if not bucklets.has_key(c) then + bucklets[c] = new HashSet[MType] + end + bucklets[c].add(e) + end + + # Colorize cast_types from the class hierarchy + var colorer = new POSetGroupColorer[MClass, MType](class_conflict_graph, bucklets) + type_colors = colorer.colors + + var layouts = new HashMap[MClass, Array[nullable MType]] + for c in runtime_type_analysis.live_classes do + layouts[c] = colorer.build_layout(c) + end + + # Build the table for each live type + for t in mtypes do + # A live type use the layout of its class + var c = t.mclass + var layout = layouts[c] + var table = new Array[nullable MType].with_capacity(layout.length) + type_tables[t] = table + + # For each potential super-type in the layout + for sup in layout do + if sup == null then + table.add null + else if t.is_subtype(mainmodule, null, sup) then + table.add sup + else + table.add null + end + end + end + end + # resolution_tables is used to perform a type resolution at runtime in O(1) private fun compute_resolution_tables(mtypes: Set[MType]) do # During the visit of the body of classes, live_unresolved_types are collected @@@ -534,21 -554,26 +554,26 @@@ # Collect all live_unresolved_types (visited in the body of classes) # Determinate fo each livetype what are its possible requested anchored types - var mtype2unresolved = new HashMap[MClassType, Set[MType]] + var mtype2unresolved = new HashMap[MClass, Set[MType]] for mtype in self.runtime_type_analysis.live_types do - var set = new HashSet[MType] + var mclass = mtype.mclass + var set = mtype2unresolved.get_or_null(mclass) + if set == null then + set = new HashSet[MType] + mtype2unresolved[mclass] = set + end for cd in mtype.collect_mclassdefs(self.mainmodule) do if self.live_unresolved_types.has_key(cd) then set.add_all(self.live_unresolved_types[cd]) end end end # Compute the table layout with the prefered method - var colorer = new BucketsColorer[MType, MType] + var colorer = new BucketsColorer[MClass, MType] + opentype_colors = colorer.colorize(mtype2unresolved) - resolution_tables = self.build_resolution_tables(mtype2unresolved) + resolution_tables = self.build_resolution_tables(self.runtime_type_analysis.live_types, 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) @@@ -573,9 -598,10 +598,10 @@@ #print "" end - fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do + fun build_resolution_tables(elements: Set[MClassType], map: Map[MClass, Set[MType]]): Map[MClassType, Array[nullable MType]] do var tables = new HashMap[MClassType, Array[nullable MType]] - for mclasstype, mtypes in elements do + for mclasstype in elements do + var mtypes = map[mclasstype.mclass] var table = new Array[nullable MType] for mtype in mtypes do var color = opentype_colors[mtype] @@@ -788,12 -814,10 +814,10 @@@ var mtype = mclass.intro.bound_mtype var c_name = mclass.c_name 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" and mclass.name != "Pointer" + var is_dead = rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" and mclass.name != "Pointer" v.add_decl("/* runtime class {c_name} */") @@@ -803,7 -827,8 +827,8 @@@ v.add_decl("const struct class class_{c_name} = \{") v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */") v.add_decl("\{") - for i in [0 .. vft.length[ do + var vft = self.method_tables.get_or_null(mclass) + if vft != null then for i in [0 .. vft.length[ do var mpropdef = vft[i] if mpropdef == null then v.add_decl("NULL, /* empty */") @@@ -822,7 -847,7 +847,7 @@@ v.add_decl("\};") end - if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then + if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then # Is a primitive type or the Pointer class, not any other extern class if mtype.is_tagged then return @@@ -932,13 -957,20 +957,20 @@@ else var res = v.new_named_var(mtype, "self") res.is_exact = true - v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));") + var attrs = self.attr_tables.get_or_null(mclass) + if attrs == null then + v.add("{res} = nit_alloc(sizeof(struct instance));") + else + v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));") + end v.add("{res}->type = type;") hardening_live_type(v, "type") v.require_declaration("class_{c_name}") v.add("{res}->class = &class_{c_name};") - self.generate_init_attr(v, res, mtype) - v.set_finalizer res + if attrs != null then + self.generate_init_attr(v, res, mtype) + v.set_finalizer res + end v.add("return {res};") end v.add("\}") @@@ -1017,7 -1049,7 +1049,7 @@@ private var type_tables: Map[MType, Array[nullable MType]] = new HashMap[MType, Array[nullable MType]] private var resolution_tables: Map[MClassType, Array[nullable MType]] = new HashMap[MClassType, Array[nullable MType]] protected var method_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]] - protected var attr_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]] + protected var attr_tables: Map[MClass, Array[nullable MProperty]] = new HashMap[MClass, Array[nullable MProperty]] redef fun display_stats do @@@ -1153,9 -1185,9 +1185,9 @@@ class SeparateCompilerVisito do if value.mtype == mtype then return value - else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then + else if not value.mtype.is_c_primitive and not mtype.is_c_primitive then return value - else if value.mtype.ctype == "val*" then + else if not value.mtype.is_c_primitive then if mtype.is_tagged then if mtype.name == "Int" then return self.new_expr("(long)({value})>>2", mtype) @@@ -1168,7 -1200,7 +1200,7 @@@ end end return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype) - else if mtype.ctype == "val*" then + else if not mtype.is_c_primitive then if value.mtype.is_tagged then if value.mtype.name == "Int" then return self.new_expr("(val*)({value}<<2|1)", mtype) @@@ -1248,7 -1280,7 +1280,7 @@@ # Thus the expression can be used as a condition. fun extract_tag(value: RuntimeVariable): String do - assert value.mtype.ctype == "val*" + assert not value.mtype.is_c_primitive return "((long){value}&3)" # Get the two low bits end @@@ -1256,7 -1288,7 +1288,7 @@@ # The point of the method is to work also with primitive types. fun class_info(value: RuntimeVariable): String do - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then if can_be_primitive(value) and not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then var tag = extract_tag(value) return "({tag}?class_info[{tag}]:{value}->class)" @@@ -1273,7 -1305,7 +1305,7 @@@ # The point of the method is to work also with primitive types. fun type_info(value: RuntimeVariable): String do - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then if can_be_primitive(value) and not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then var tag = extract_tag(value) return "({tag}?type_info[{tag}]:{value}->type)" @@@ -1322,7 -1354,7 +1354,7 @@@ end redef fun send(mmethod, arguments) do - if arguments.first.mcasttype.ctype != "val*" then + if arguments.first.mcasttype.is_c_primitive then # In order to shortcut the primitive, we need to find the most specific method # Howverr, because of performance (no flattening), we always work on the realmainmodule var m = self.compiler.mainmodule @@@ -1529,7 -1561,7 +1561,7 @@@ redef fun supercall(m: MMethodDef, recvtype: MClassType, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do - if arguments.first.mcasttype.ctype != "val*" then + if arguments.first.mcasttype.is_c_primitive then # In order to shortcut the primitive, we need to find the most specific method # However, because of performance (no flattening), we always work on the realmainmodule var main = self.compiler.mainmodule @@@ -1580,7 -1612,7 +1612,7 @@@ self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/") else - if mtype.ctype == "val*" then + if not mtype.is_c_primitive and not mtype.is_tagged 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} */") @@@ -1632,7 -1664,7 +1664,7 @@@ 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_attr_isset.value then + if not ret.is_c_primitive and not ret isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_attr_isset.value then self.add("if (unlikely({res} == NULL)) \{") self.add_abort("Uninitialized attribute {a.name}") self.add("\}") @@@ -1661,11 -1693,7 +1693,11 @@@ self.require_declaration(a.const_color) if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then var attr = "{recv}->attrs[{a.const_color}]" - if mtype.ctype != "val*" then + if mtype.is_tagged then + # The attribute is not primitive, thus store it as tagged + var tv = autobox(value, compiler.mainmodule.object_type) + self.add("{attr} = {tv}; /* {a} on {recv.inspect} */") + else if mtype.is_c_primitive 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 @@@ -1817,15 -1845,15 +1849,15 @@@ do var res = self.new_var(bool_type) # Swap values to be symetric - if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then + if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then var tmp = value1 value1 = value2 value2 = tmp end - if value1.mtype.ctype != "val*" then + if value1.mtype.is_c_primitive 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 + else if value2.mtype.is_c_primitive then self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/") else var mtype1 = value1.mtype.as(MClassType) @@@ -1842,7 -1870,7 +1874,7 @@@ do var res = self.get_name("var_class_name") self.add_decl("const char* {res};") - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then self.add "{res} = {value} == NULL ? \"null\" : {type_info(value)}->name;" else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind and value.mtype.as(MClassType).name != "NativeString" then @@@ -1857,15 -1885,15 +1889,15 @@@ redef fun equal_test(value1, value2) do var res = self.new_var(bool_type) - if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then + if value2.mtype.is_c_primitive and not value1.mtype.is_c_primitive then var tmp = value1 value1 = value2 value2 = tmp end - if value1.mtype.ctype != "val*" then + if value1.mtype.is_c_primitive then if value2.mtype == value1.mtype then self.add("{res} = {value1} == {value2};") - else if value2.mtype.ctype != "val*" then + else if value2.mtype.is_c_primitive then self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/") else if value1.mtype.is_tagged then self.add("{res} = ({value2} != NULL) && ({self.autobox(value2, value1.mtype)} == {value1});") @@@ -1898,11 -1926,11 +1930,11 @@@ var incompatible = false var primitive - if t1.ctype != "val*" then + if t1.is_c_primitive then primitive = t1 if t1 == t2 then # No need to compare class - else if t2.ctype != "val*" then + else if t2.is_c_primitive then incompatible = true else if can_be_primitive(value2) then if t1.is_tagged then @@@ -1916,7 -1944,7 +1948,7 @@@ else incompatible = true end - else if t2.ctype != "val*" then + else if t2.is_c_primitive then primitive = t2 if can_be_primitive(value1) then if t2.is_tagged then @@@ -1977,7 -2005,7 +2009,7 @@@ 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 k == interface_kind or t.is_c_primitive end fun maybe_null(value: RuntimeVariable): Bool @@@ -1988,8 -2016,8 +2020,8 @@@ redef fun array_instance(array, elttype) do - var nclass = self.get_class("NativeArray") - var arrayclass = self.get_class("Array") + var nclass = mmodule.native_array_class + var arrayclass = mmodule.array_class var arraytype = arrayclass.get_mtype([elttype]) var res = self.init_instance(arraytype) self.add("\{ /* {res} = array_instance Array[{elttype}] */") @@@ -2006,7 -2034,7 +2038,7 @@@ redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable do - var mtype = self.get_class("NativeArray").get_mtype([elttype]) + var mtype = mmodule.native_array_type(elttype) self.require_declaration("NEW_{mtype.mclass.c_name}") assert mtype isa MGenericType var compiler = self.compiler @@@ -2026,7 -2054,7 +2058,7 @@@ redef fun native_array_def(pname, ret_type, arguments) do var elttype = arguments.first.mtype - var nclass = self.get_class("NativeArray") + var nclass = mmodule.native_array_class var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values" if pname == "[]" then # Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing @@@ -2047,20 -2075,12 +2079,20 @@@ end end - redef fun calloc_array(ret_type, arguments) + redef fun native_array_get(nat, i) + do + var nclass = mmodule.native_array_class + var recv = "((struct instance_{nclass.c_name}*){nat})->values" + # Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing + var res = self.new_expr("{recv}[{i}]", compiler.mainmodule.object_type) + return res + end + + redef fun native_array_set(nat, i, val) do - var mclass = self.get_class("ArrayCapable") - var ft = mclass.mparameters.first - var res = self.native_array_instance(ft, arguments[1]) - self.ret(res) + var nclass = mmodule.native_array_class + var recv = "((struct instance_{nclass.c_name}*){nat})->values" + self.add("{recv}[{i}]={val};") end fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do @@@ -2173,7 -2193,7 +2205,7 @@@ class SeparateRuntimeFunctio for i in [0..called_signature.arity[ do var mtype = called_signature.mparameters[i].mtype if i == called_signature.vararg_rank then - mtype = mmethoddef.mclassdef.mmodule.get_primitive_class("Array").get_mtype([mtype]) + mtype = mmethoddef.mclassdef.mmodule.array_type(mtype) end sig.append(", {mtype.ctype} p{i}") end @@@ -2212,7 -2232,7 +2244,7 @@@ for i in [0..msignature.arity[ do var mtype = msignature.mparameters[i].mtype if i == msignature.vararg_rank then - mtype = v.get_class("Array").get_mtype([mtype]) + mtype = v.mmodule.array_type(mtype) end comment.append(", {mtype}") var argvar = new RuntimeVariable("p{i}", mtype, mtype) @@@ -2259,14 -2279,14 +2291,14 @@@ var selfvar = arguments.first var ret = called_signature.return_mtype - if mmethoddef.is_intro and recv.ctype == "val*" then + if mmethoddef.is_intro and not recv.is_c_primitive then var m = mmethoddef.mproperty var n2 = "CALL_" + m.const_color compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};") var v2 = compiler.new_visitor v2.add "{c_ret} {n2}{c_sig} \{" v2.require_declaration(m.const_color) - var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});" + var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});" if ret != null then v2.add "return {call}" else @@@ -2276,14 -2296,14 +2308,14 @@@ v2.add "\}" end - if mmethoddef.has_supercall and recv.ctype == "val*" then + if mmethoddef.has_supercall and not recv.is_c_primitive then var m = mmethoddef var n2 = "CALL_" + m.const_color compiler.provide_declaration(n2, "{c_ret} {n2}{c_sig};") var v2 = compiler.new_visitor v2.add "{c_ret} {n2}{c_sig} \{" v2.require_declaration(m.const_color) - var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});" + var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});" if ret != null then v2.add "return {call}" else @@@ -2324,14 -2344,3 +2356,14 @@@ redef class AMethPropde return super end end + +redef class AAttrPropdef + redef fun init_expr(v, recv) + do + super + if is_lazy and v.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then + var guard = self.mlazypropdef.mproperty + v.write_attribute(guard, recv, v.bool_instance(false)) + end + end +end diff --combined src/compiler/separate_erasure_compiler.nit index 2a7f0fa,d1c67e5..b8b2c0a --- a/src/compiler/separate_erasure_compiler.nit +++ b/src/compiler/separate_erasure_compiler.nit @@@ -199,14 -199,12 +199,12 @@@ class SeparateErasureCompile var mtype = mclass.intro.bound_mtype var c_name = mclass.c_name - var vft = self.method_tables[mclass] - var attrs = self.attr_tables[mclass] var class_table = self.class_tables[mclass] var v = self.new_visitor var rta = runtime_type_analysis var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind - if not is_dead and rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" then + if not is_dead and rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" then is_dead = true end @@@ -230,7 -228,8 +228,8 @@@ end v.add_decl("&type_table_{c_name},") v.add_decl("\{") - for i in [0 .. vft.length[ do + var vft = self.method_tables.get_or_null(mclass) + if vft != null then for i in [0 .. vft.length[ do var mpropdef = vft[i] if mpropdef == null then v.add_decl("NULL, /* empty */") @@@ -264,7 -263,7 +263,7 @@@ v.add_decl("\}") v.add_decl("\};") - if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then + if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then #Build instance struct self.header.add_decl("struct instance_{c_name} \{") self.header.add_decl("const struct class *class;") @@@ -355,11 -354,18 +354,18 @@@ var res = v.new_named_var(mtype, "self") res.is_exact = true - v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));") + var attrs = self.attr_tables.get_or_null(mclass) + if attrs == null then + v.add("{res} = nit_alloc(sizeof(struct instance));") + else + v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));") + end v.require_declaration("class_{c_name}") v.add("{res}->class = &class_{c_name};") - self.generate_init_attr(v, res, mtype) - v.set_finalizer res + if attrs != null then + self.generate_init_attr(v, res, mtype) + v.set_finalizer res + end v.add("return {res};") end v.add("\}") @@@ -529,7 -535,7 +535,7 @@@ class SeparateErasureCompilerVisito end var class_ptr - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then class_ptr = "{value}->class->" else var mclass = value.mtype.as(MClassType).mclass @@@ -548,7 -554,7 +554,7 @@@ else if mtype isa MVirtualType then var recv = self.frame.arguments.first var recv_ptr - if recv.mtype.ctype == "val*" then + if not recv.mtype.is_c_primitive then recv_ptr = "{recv}->class->" else var mclass = recv.mtype.as(MClassType).mclass @@@ -632,7 -638,7 +638,7 @@@ do var res = self.get_name("var_class_name") self.add_decl("const char* {res};") - if value.mtype.ctype == "val*" then + if not value.mtype.is_c_primitive then self.add "{res} = {value} == NULL ? \"null\" : {value}->class->name;" else self.require_declaration("class_{value.mtype.c_name}") @@@ -643,7 -649,7 +649,7 @@@ redef fun native_array_instance(elttype, length) do - var nclass = self.get_class("NativeArray") + var nclass = mmodule.native_array_class var mtype = nclass.get_mtype([elttype]) var res = self.new_var(mtype) res.is_exact = true diff --combined src/model/model.nit index 3a64638,b9b484a..76a3839 --- a/src/model/model.nit +++ b/src/model/model.nit @@@ -195,40 -195,31 +195,40 @@@ redef class MModul private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null # The primitive type `Object`, the root of the class hierarchy - fun object_type: MClassType - do - var res = self.object_type_cache - if res != null then return res - res = self.get_primitive_class("Object").mclass_type - self.object_type_cache = res - return res - end - - private var object_type_cache: nullable MClassType + var object_type: MClassType = self.get_primitive_class("Object").mclass_type is lazy # The type `Pointer`, super class to all extern classes var pointer_type: MClassType = self.get_primitive_class("Pointer").mclass_type is lazy # The primitive type `Bool` - fun bool_type: MClassType - do - var res = self.bool_type_cache - if res != null then return res - res = self.get_primitive_class("Bool").mclass_type - self.bool_type_cache = res - return res - end + var bool_type: MClassType = self.get_primitive_class("Bool").mclass_type is lazy + + # The primitive type `Int` + var int_type: MClassType = self.get_primitive_class("Int").mclass_type is lazy + + # The primitive type `Char` + var char_type: MClassType = self.get_primitive_class("Char").mclass_type is lazy + + # The primitive type `Float` + var float_type: MClassType = self.get_primitive_class("Float").mclass_type is lazy + + # The primitive type `String` + var string_type: MClassType = self.get_primitive_class("String").mclass_type is lazy + + # The primitive type `NativeString` + var native_string_type: MClassType = self.get_primitive_class("NativeString").mclass_type is lazy + + # A primitive type of `Array` + fun array_type(elt_type: MType): MClassType do return array_class.get_mtype([elt_type]) + + # The primitive class `Array` + var array_class: MClass = self.get_primitive_class("Array") is lazy + + # A primitive type of `NativeArray` + fun native_array_type(elt_type: MType): MClassType do return native_array_class.get_mtype([elt_type]) - private var bool_type_cache: nullable MClassType + # The primitive class `NativeArray` + var native_array_class: MClass = self.get_primitive_class("NativeArray") is lazy # The primitive type `Sys`, the main type of the program, if any fun sys_type: nullable MClassType @@@ -477,6 -468,9 +477,9 @@@ class MClas end private var get_mtype_cache = new HashMap[Array[MType], MGenericType] + + # Is there a `new` factory to allow the pseudo instantiation? + var has_new_factory = false is writable end