# Add separate compiler specific options
redef class ToolContext
# --separate
- var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
+ var opt_separate = new OptionBool("Use separate compilation", "--separate")
# --no-inline-intern
- var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
+ var opt_no_inline_intern = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
# --no-union-attribute
- var opt_no_union_attribute: OptionBool = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
+ var opt_no_union_attribute = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
# --no-shortcut-equate
- var opt_no_shortcut_equate: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
+ var opt_no_shortcut_equate = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
+ # --colors-are-symbols
+ var opt_colors_are_symbols = new OptionBool("Store colors as symbols (faster)", "--colors-are-symbols")
+
# --inline-coloring-numbers
- var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
+ var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
# --inline-some-methods
- var opt_inline_some_methods: OptionBool = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
+ var opt_inline_some_methods = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
# --direct-call-monomorph
- var opt_direct_call_monomorph: OptionBool = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
+ var opt_direct_call_monomorph = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
# --skip-dead-methods
var opt_skip_dead_methods = new OptionBool("Do not compile dead methods (semi-global)", "--skip-dead-methods")
# --semi-global
# --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")
+ var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
redef init
do
self.option_context.add_option(self.opt_separate)
self.option_context.add_option(self.opt_no_inline_intern)
self.option_context.add_option(self.opt_no_union_attribute)
- self.option_context.add_option(self.opt_no_shortcut_equate)
+ self.option_context.add_option(self.opt_no_shortcut_equate, opt_colors_are_symbols)
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.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
- compiler.compile_header
-
- # compile class structures
- self.toolcontext.info("Property coloring", 2)
- compiler.new_file("{mainmodule.name}.classes")
- compiler.do_property_coloring
- for m in mainmodule.in_importation.greaters do
- for mclass in m.intro_mclasses do
- if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
- compiler.compile_class_to_c(mclass)
- end
- 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
- self.toolcontext.info("Generate C for module {m}", 2)
- compiler.new_file("{m.name}.sep")
- compiler.compile_module_to_c(m)
- end
-
- # compile live & cast type structures
- self.toolcontext.info("Type coloring", 2)
- compiler.new_file("{mainmodule.name}.types")
- var mtypes = compiler.do_type_coloring
- for t in mtypes do
- compiler.compile_type_to_c(t)
- end
- # compile remaining types structures (useless but needed for the symbol resolution at link-time)
- for t in compiler.undead_types do
- if mtypes.has(t) then continue
- compiler.compile_type_to_c(t)
- end
-
+ compiler.do_compilation
compiler.display_stats
var time1 = get_time
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_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]
+ 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(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
- super(mainmodule, mmbuilder)
+ init do
var file = new_file("nit.common")
self.header = new CodeWriter(file)
- self.runtime_type_analysis = runtime_type_analysis
self.compile_box_kinds
end
+ redef fun do_compilation
+ do
+ var compiler = self
+ compiler.compile_header
+
+ var c_name = mainmodule.c_name
+
+ # compile class structures
+ modelbuilder.toolcontext.info("Property coloring", 2)
+ compiler.new_file("{c_name}.classes")
+ compiler.do_property_coloring
+ for m in mainmodule.in_importation.greaters do
+ for mclass in m.intro_mclasses do
+ #if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
+ compiler.compile_class_to_c(mclass)
+ end
+ end
+
+ # The main function of the C
+ compiler.new_file("{c_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
+ modelbuilder.toolcontext.info("Generate C for module {m.full_name}", 2)
+ compiler.new_file("{m.c_name}.sep")
+ compiler.compile_module_to_c(m)
+ end
+
+ # compile live & cast type structures
+ modelbuilder.toolcontext.info("Type coloring", 2)
+ compiler.new_file("{c_name}.types")
+ compiler.compile_types
+ end
+
+ # Color and compile type structures and cast information
+ fun compile_types
+ do
+ var compiler = self
+
+ var mtypes = compiler.do_type_coloring
+ for t in mtypes do
+ compiler.compile_type_to_c(t)
+ end
+ # compile remaining types structures (useless but needed for the symbol resolution at link-time)
+ for t in compiler.undead_types do
+ if mtypes.has(t) then continue
+ compiler.compile_type_to_c(t)
+ end
+
+ end
+
redef fun compile_header_structs do
self.header.add_decl("typedef void(*nitmethod_t)(void); /* general C type representing a Nit method. */")
self.compile_header_attribute_structs
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]
fun compile_color_const(v: SeparateCompilerVisitor, m: Object, color: Int) do
if color_consts_done.has(m) then return
- if m isa MProperty then
+ if m isa MEntity then
if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
- else
+ else if not modelbuilder.toolcontext.opt_colors_are_symbols.value or not v.compiler.target_platform.supports_linker_script then
self.provide_declaration(m.const_color, "extern const int {m.const_color};")
v.add("const int {m.const_color} = {color};")
- end
- else if m isa MPropDef then
- if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
- self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
else
- self.provide_declaration(m.const_color, "extern const int {m.const_color};")
- v.add("const int {m.const_color} = {color};")
- end
- else if m isa MType then
- if modelbuilder.toolcontext.opt_inline_coloring_numbers.value then
- self.provide_declaration(m.const_color, "#define {m.const_color} {color}")
- else
- self.provide_declaration(m.const_color, "extern const int {m.const_color};")
- v.add("const int {m.const_color} = {color};")
+ # The color 'C' is the ``address'' of a false static variable 'XC'
+ self.provide_declaration(m.const_color, "#define {m.const_color} ((long)&X{m.const_color})\nextern const void X{m.const_color};")
+ if color == -1 then color = 0 # Symbols cannot be negative, so just use 0 for dead things
+ # Teach the linker that the address of 'XC' is `color`.
+ linker_script.add("X{m.const_color} = {color};")
end
+ else
+ abort
end
color_consts_done.add(m)
end
var live_cast_types = runtime_type_analysis.live_cast_types
var mtypes = new HashSet[MType]
mtypes.add_all(live_types)
- mtypes.add_all(live_cast_types)
for c in self.box_kinds.keys do
mtypes.add(c.mclass_type)
end
# Compute colors
- var poset = poset_from_mtypes(mtypes)
+ var poset = poset_from_mtypes(mtypes, live_cast_types)
var colorer = new POSetColorer[MType]
colorer.colorize(poset)
type_ids = colorer.ids
return poset
end
- private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do
+ private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
var poset = new POSet[MType]
for e in mtypes do
poset.add_node(e)
- for o in mtypes do
+ for o in cast_types do
if e == o then continue
+ poset.add_node(o)
if e.is_subtype(mainmodule, null, o) then
poset.add_edge(e, o)
end
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
+
+ #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) then return
+ 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
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)
+ 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! */")
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
+
# Return a C expression returning the runtime type structure of the value
# The point of the method is to works also with primitives types.
fun type_info(value: RuntimeVariable): String
redef fun compile_callsite(callsite, args)
do
var rta = compiler.runtime_type_analysis
- var recv = args.first.mtype
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
+ # TODO: Inlining of new-style constructors with initializers
+ if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and callsite.mpropdef.initializers.is_empty then
var tgs = rta.live_targets(callsite)
if tgs.length == 1 then
# DIRECT CALL
- 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)
if res0 != null then
end
redef fun send(mmethod, arguments)
do
- self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
-
if arguments.first.mcasttype.ctype != "val*" 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
return table_send(mmethod, arguments, mmethod.const_color)
end
- # Handel common special cases before doing the effective method invocation
+ # Handle common special cases before doing the effective method invocation
# This methods handle the `==` and `!=` methods and the case of the null receiver.
# Note: a { is open in the generated C, that enclose and protect the effective method invocation.
# Client must not forget to close the } after them.
#
# The value returned is the result of the common special cases.
- # If not null, client must compine it with the result of their own effective method invocation.
+ # If not null, client must compile it with the result of their own effective method invocation.
#
# If `before_send` can shortcut the whole message sending, a dummy `if(0){`
# is generated to cancel the effective method invocation that will follow
var res: nullable RuntimeVariable = null
var recv = arguments.first
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
+ var maybenull = (recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType) and consider_null
if maybenull then
self.add("if ({recv} == NULL) \{")
- if mmethod.name == "==" then
+ if mmethod.name == "==" or mmethod.name == "is_same_instance" then
res = self.new_var(bool_type)
var arg = arguments[1]
if arg.mcasttype isa MNullableType then
else
self.add("\{")
end
- if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
- if res == null then res = self.new_var(bool_type)
- # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
+ if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=" or mmethod.name == "is_same_instance") then
+ # Recv is not null, thus if arg is, it is easy to conclude (and respect the invariants)
var arg = arguments[1]
if arg.mcasttype isa MNullType then
- if mmethod.name == "==" then
- self.add("{res} = 0; /* arg is null but recv is not */")
- else
+ if res == null then res = self.new_var(bool_type)
+ if mmethod.name == "!=" then
self.add("{res} = 1; /* arg is null and recv is not */")
+ else # `==` and `is_same_instance`
+ self.add("{res} = 0; /* arg is null but recv is not */")
end
self.add("\}") # closes the null case
self.add("if (0) \{") # what follow is useless, CC will drop it
var res: nullable RuntimeVariable
var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
var ret = msignature.return_mtype
- if mmethod.is_new then
- ret = arguments.first.mtype
- res = self.new_var(ret)
- else if ret == null then
+ if ret == null then
res = null
else
res = self.new_var(ret)
var res: nullable RuntimeVariable
var ret = mmethoddef.msignature.return_mtype
- if mmethoddef.mproperty.is_new then
- ret = arguments.first.mtype
- res = self.new_var(ret)
- else if ret == null then
+ if ret == null then
res = null
else
ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
(compiler.modelbuilder.toolcontext.opt_inline_some_methods.value and mmethoddef.can_inline(self)) then
compiler.modelbuilder.nb_invok_by_inline += 1
if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_inline++;")
- var frame = new Frame(self, mmethoddef, recvtype, arguments)
+ var frame = new StaticFrame(self, mmethoddef, recvtype, arguments)
frame.returnlabel = self.get_name("RET_LABEL")
frame.returnvar = res
var old_frame = self.frame
# of the method (ie recv) if the static type is unresolved
# This is more complex than usual because the unresolved type must not be resolved
# with the current receiver (ie self).
- # Therefore to isolate the resolution from self, a local Frame is created.
+ # Therefore to isolate the resolution from self, a local StaticFrame is created.
# One can see this implementation as an inlined method of the receiver whose only
# job is to allocate the array
var old_frame = self.frame
- var frame = new Frame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
+ var frame = new StaticFrame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
self.frame = frame
#print "required Array[{elttype}] for recv {recv.inspect}. bound=Array[{self.resolve_for(elttype, recv)}]. selfvar={frame.arguments.first.inspect}"
var res = self.array_instance(varargs, elttype)
# 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.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
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"
+ var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
self.add("memmove({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
return
end
redef fun calloc_array(ret_type, arguments)
do
var mclass = self.get_class("ArrayCapable")
- var ft = mclass.mclass_type.arguments.first.as(MParameterType)
+ var ft = mclass.mparameters.first
var res = self.native_array_instance(ft, arguments[1])
self.ret(res)
end
var v = compiler.new_visitor
var selfvar = new RuntimeVariable("self", recv, recv)
var arguments = new Array[RuntimeVariable]
- var frame = new Frame(v, mmethoddef, recv, arguments)
+ var frame = new StaticFrame(v, mmethoddef, recv, arguments)
v.frame = frame
var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
var ret = msignature.return_mtype
if ret != null then
sig.append("{ret.ctype} ")
- else if mmethoddef.mproperty.is_new then
- ret = recv
- sig.append("{ret.ctype} ")
else
sig.append("void ")
end
var v = compiler.new_visitor
var selfvar = new RuntimeVariable("self", v.object_type, recv)
var arguments = new Array[RuntimeVariable]
- var frame = new Frame(v, mmethoddef, recv, arguments)
+ var frame = new StaticFrame(v, mmethoddef, recv, arguments)
v.frame = frame
var sig = new FlatBuffer
var ret = msignature.return_mtype
if ret != null then
sig.append("{ret.ctype} ")
- else if mmethoddef.mproperty.is_new then
- ret = recv
- sig.append("{ret.ctype} ")
else
sig.append("void ")
end
redef fun call(v, arguments) do abort
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
+redef class MEntity
+ var const_color: String is lazy do return "COLOR_{c_name}"
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 AMethPropdef
+ # The semi-global compilation does not support inlining calls to extern news
+ redef fun can_inline
+ do
+ var m = mpropdef
+ if m != null and m.mproperty.is_init and m.is_extern then return false
+ return super
+ end
end