# Generate a super call from a method definition
fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
+ # Adapt the arguments of a method according to targetted `MMethodDef`
fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
+ # Unbox all the arguments of a method when implemented `extern` or `intern`
+ fun unbox_signature_extern(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
+
# Box or unbox a value to another type iff a C type conversion is needed
# ENSURE: `result.mtype.ctype == mtype.ctype`
fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
+ # Box extern classes to be used in the generated code
+ fun box_extern(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
+
+ # Unbox extern classes to be used in extern code (legacy NI and FFI)
+ fun unbox_extern(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
+
# Generate a polymorphic subtype test
fun type_test(value: RuntimeVariable, mtype: MType, tag: String): RuntimeVariable is abstract
return res
end
+ # The difference with `new_var` is the C static type of the local variable
+ fun new_var_extern(mtype: MType): RuntimeVariable
+ do
+ mtype = self.anchor(mtype)
+ var name = self.get_name("var")
+ var res = new RuntimeVariable(name, mtype, mtype)
+ self.add_decl("{mtype.ctype_extern} {name} /* : {mtype} for extern */;")
+ return res
+ end
+
# Return a new uninitialized named runtime_variable
fun new_named_var(mtype: MType, name: String): RuntimeVariable
do
# Return the C type associated to a given Nit static type
fun ctype: String do return "val*"
+ # C type outside of the compiler code and in boxes
+ fun ctype_extern: String do return "val*"
+
+ # Short name of the `ctype` to use in unions
fun ctypename: String do return "val"
# Return the name of the C structure associated to a Nit live type
return "char*"
else if mclass.name == "NativeArray" then
return "val*"
- else if mclass.kind == extern_kind then
- return "void*"
else
return "val*"
end
end
+ redef fun ctype_extern: String
+ do
+ if mclass.kind == extern_kind then
+ return "void*"
+ else
+ return ctype
+ end
+ end
+
redef fun ctypename: String
do
if mclass.name == "Int" then
else if mclass.name == "NativeArray" then
#return "{self.arguments.first.ctype}*"
return "val"
- else if mclass.kind == extern_kind then
- return "ptr"
else
return "val"
end
end
if pname != "==" and pname != "!=" then
v.adapt_signature(mpropdef, arguments)
+ v.unbox_signature_extern(mpropdef, arguments)
end
if cname == "Int" then
if pname == "output" then
var ret = mpropdef.msignature.return_mtype
if ret != null then
ret = v.resolve_for(ret, arguments.first)
- res = v.new_var(ret)
+ res = v.new_var_extern(ret)
end
v.adapt_signature(mpropdef, arguments)
+ v.unbox_signature_extern(mpropdef, arguments)
if res == null then
v.add("{externname}({arguments.join(", ")});")
else
v.add("{res} = {externname}({arguments.join(", ")});")
+ res = v.box_extern(res, ret.as(not null))
v.ret(res)
end
end
v.add_extern(file)
end
v.adapt_signature(mpropdef, arguments)
+ v.unbox_signature_extern(mpropdef, arguments)
var ret = arguments.first.mtype
- var res = v.new_var(ret)
+ var res = v.new_var_extern(ret)
arguments.shift
v.add("{res} = {externname}({arguments.join(", ")});")
+ res = v.box_extern(res, ret)
v.ret(res)
end
end
return v.native_array_instance(elttype, l)
else if ctype == "val*" then
recv = v.init_instance(mtype)
- else if ctype == "void*" then
+ else if ctype == "char*" then
recv = v.new_expr("NULL/*special!*/", mtype)
else
recv = v.new_expr("({ctype})0/*special!*/", mtype)
end
v.adapt_signature(mpropdef, arguments)
+ v.unbox_signature_extern(mpropdef, arguments)
var arguments_for_c = new Array[String]
for a in [0..arguments.length[ do
v.add("ret_var = {externname}({arguments_for_c.join(", ")});")
v.add("{recv_var} = ret_var->value;")
end
+ recv_var = v.box_extern(recv_var, return_mtype)
v.ret(recv_var)
end
var recv_var = v.new_var(return_mtype)
v.adapt_signature(mpropdef, arguments)
+ v.unbox_signature_extern(mpropdef, arguments)
arguments.shift
v.add("ret_var = {externname}({arguments_for_c.join(", ")});")
v.add("{recv_var} = ret_var->value;")
end
+ recv_var = v.box_extern(recv_var, return_mtype)
v.ret(recv_var)
compile_ffi_support_to_c(v)
var mtype: MType = recv_mtype
var recv_var = null
if mproperty.is_init then
- if recv_mtype.mclass.kind == extern_kind then
- recv_var = nitni_visitor.new_var(mtype)
- else
- var recv_mtype = recv_mtype
- recv_var = nitni_visitor.init_instance(recv_mtype)
- nitni_visitor.add("{mtype.ctype} recv /* var self: {mtype} */;")
- nitni_visitor.add("recv = {recv_var};")
- end
+ var recv_mtype = recv_mtype
+ recv_var = nitni_visitor.init_instance(recv_mtype)
+ nitni_visitor.add("{mtype.ctype} recv /* var self: {mtype} */;")
+ nitni_visitor.add("recv = {recv_var};")
else
mtype = mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
recv_var = nitni_visitor.var_from_c("recv", mtype)
+ recv_var = nitni_visitor.box_extern(recv_var, mtype)
end
vars.add(recv_var)
for p in msignature.mparameters do
var arg_mtype = p.mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
var arg = nitni_visitor.var_from_c(p.name, arg_mtype)
+ arg = nitni_visitor.box_extern(arg, arg_mtype)
vars.add(arg)
end
assert ret_var != null
return_mtype = return_mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
ret_var = nitni_visitor.autobox(ret_var, return_mtype)
+ ret_var = nitni_visitor.unbox_extern(ret_var, return_mtype)
nitni_visitor.ret_to_c(ret_var, return_mtype)
end
nitni_visitor.add("\}")
var vars = new Array[RuntimeVariable]
var recv_var = nitni_visitor.var_from_c("recv", mclass_type)
+ recv_var = nitni_visitor.box_extern(recv_var, mclass_type)
vars.add(recv_var)
for p in msignature.mparameters do
var arg_mtype = v.anchor(p.mtype)
var arg = nitni_visitor.var_from_c(p.name, arg_mtype)
+ arg = nitni_visitor.box_extern(arg, arg_mtype)
vars.add(arg)
end
if return_mtype != null then
assert ret_var != null
return_mtype = v.anchor(return_mtype)
+ ret_var = nitni_visitor.autobox(ret_var, return_mtype)
+ ret_var = nitni_visitor.unbox_extern(ret_var, return_mtype)
nitni_visitor.ret_to_c(ret_var, return_mtype)
end
nitni_visitor.add("\}")
var nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
- var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({from.cname_blind} from)"
+ var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
+
nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
nitni_visitor.add_decl("{full_internal_csignature} \{")
- var from_var = new RuntimeVariable("from->value", from, from)
+ #var from_var = new RuntimeVariable("from->value", from, from)
+ var from_var = nitni_visitor.var_from_c("from", from)
+ from_var = nitni_visitor.box_extern(from_var, from)
var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
nitni_visitor.add("return {recv_var};")
nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
- full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({from.cname_blind} from)"
+ full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
nitni_visitor.add_decl("/* nitni cast for {from} to {to} */")
nitni_visitor.add_decl("{full_internal_csignature} \{")
from_var = nitni_visitor.var_from_c("from", from)
+ from_var = nitni_visitor.box_extern(from_var, from)
## test type
var check = nitni_visitor.type_test(from_var, to, "FFI cast")
## internal cast
recv_var = nitni_visitor.autobox(from_var, to)
+ recv_var = nitni_visitor.unbox_extern(recv_var, to)
nitni_visitor.ret_to_c(recv_var, to)
var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
compiler.compile_header
+ if mainmodule.model.get_mclasses_by_name("Pointer") != null then
+ runtime_type_analysis.live_types.add(mainmodule.pointer_type)
+ end
for t in runtime_type_analysis.live_types do
compiler.declare_runtimeclass(t)
end
for t in runtime_type_analysis.live_types do
if t.ctype == "val*" then
compiler.generate_init_instance(t)
+ if t.mclass.kind == extern_kind then
+ compiler.generate_box_instance(t)
+ end
else
compiler.generate_box_instance(t)
end
self.runtime_type_analysis = runtime_type_analysis
self.live_primitive_types = new Array[MClassType]
for t in runtime_type_analysis.live_types do
- if t.ctype != "val*" then
+ if t.ctype != "val*" or t.mclass.name == "Pointer" then
self.live_primitive_types.add(t)
end
end
v.add_decl("{mtype.arguments.first.ctype} values[1];")
end
- if mtype.ctype != "val*" then
+ if mtype.ctype_extern != "val*" then
# Is the Nit type is native then the struct is a box with two fields:
# * the `classid` to be polymorph
# * the `value` that contains the native value.
- v.add_decl("{mtype.ctype} value;")
+ v.add_decl("{mtype.ctype_extern} value;")
end
# Collect all attributes and associate them a field in the structure.
fun generate_box_instance(mtype: MClassType)
do
assert self.runtime_type_analysis.live_types.has(mtype)
- assert mtype.ctype != "val*"
var v = self.new_visitor
self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
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 res = self.new_var_extern(mtype)
+ self.add "{res} = ((struct {mtype.c_name}*){value})->value; /* unboxing {value.mtype} */"
+ return res
+ else
+ return value
+ end
+ end
+
+ redef fun box_extern(value, mtype)
+ do
+ if not mtype isa MClassType or mtype.mclass.kind != extern_kind or
+ mtype.mclass.name == "NativeString" then return value
+
+ var valtype = value.mtype.as(MClassType)
+ 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.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
+ return res
+ end
+
# The runtime types that are acceptable for a given receiver.
fun collect_types(recv: RuntimeVariable): Array[MClassType]
do
do
var recv_type = get_recvtype(m, recvtype, args)
var recv = get_recv(recv_type, args)
+ if m.is_extern then recv = unbox_extern(recv, recv_type)
var new_args = args.to_a
self.varargize(m, m.msignature.as(not null), new_args)
new_args.first = recv
do
var recv_type = get_recvtype(m, recvtype, args)
var recv = get_recv(recv_type, args)
+ if m.is_extern then recv = unbox_extern(recv, recv_type)
var new_args = args.to_a
new_args.first = recv
return finalize_call(m, recv_type, new_args)
end
end
+ redef fun unbox_signature_extern(m, args)
+ do
+ var recv = args.first
+ for i in [0..m.msignature.arity[ do
+ var t = m.msignature.mparameters[i].mtype
+ if i == m.msignature.vararg_rank then
+ t = args[i+1].mtype
+ end
+ t = self.resolve_for(t, recv)
+ if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t)
+ end
+ end
+
# FIXME: this is currently buggy since recv is not exact
redef fun vararg_instance(mpropdef, recv, varargs, elttype)
do
if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
end
+
+ if self.compiler.mainmodule.model.get_mclasses_by_name("Pointer") != null then
+ var pointer_type = self.compiler.mainmodule.pointer_type
+ if value1.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) or
+ value2.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) then
+ s.add "(((struct {pointer_type.c_name}*){value1})->value == ((struct {pointer_type.c_name}*){value2})->value)"
+ end
+ end
+
if s.is_empty then
self.add("{res} = {value1} == {value2};")
else
private var object_type_cache: nullable MClassType
# The type `Pointer`, super class to all extern classes
- fun pointer_type: MClassType
- is cached do return self.get_primitive_class("Pointer").mclass_type
+ var pointer_type: MClassType = self.get_primitive_class("Pointer").mclass_type is lazy
# The primitive type `Bool`
fun bool_type: MClassType
force_alive("Int")
force_alive("Float")
force_alive("Char")
+ force_alive("Pointer")
while not todo.is_empty do
var mmethoddef = todo.shift
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]
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)
+ var recv = args.first
+ if not m.mproperty.is_init and m.is_extern then
+ args.first = self.unbox_extern(args.first, m.mclassdef.mclass.mclass_type)
+ end
+ for i in [0..msignature.arity[ do
+ var t = msignature.mparameters[i].mtype
+ if i == msignature.vararg_rank then
+ t = args[i+1].mtype
+ end
+ if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t)
+ end
+ end
+
redef fun autobox(value, mtype)
do
if value.mtype == mtype then
else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
return value
else if value.mtype.ctype == "val*" then
- return self.new_expr("((struct instance_{mtype.c_instance_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
+ return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
else if mtype.ctype == "val*" then
var valtype = value.mtype.as(MClassType)
+ if mtype isa MClassType and mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
+ valtype = compiler.mainmodule.pointer_type
+ end
var res = self.new_var(mtype)
if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(valtype) then
self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
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
# 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 class MType
fun const_color: String do return "COLOR_{c_name}"
-
- # C name of the instance type to use
- fun c_instance_name: String do return c_name
-end
-
-redef class MClassType
- redef fun c_instance_name do return mclass.c_instance_name
-end
-
-redef class MClass
- # Extern classes use the C instance of kernel::Pointer
- fun c_instance_name: String
- do
- if kind == extern_kind then
- return "kernel__Pointer"
- else return c_name
- end
end
interface PropertyLayoutElement end
super PropertyLayoutElement
fun const_color: String do return "COLOR_{c_name}"
end
+
+redef class AExternInitPropdef
+ # The semi-global compilation does not support inlining calls to extern news
+ redef fun can_inline do return false
+end
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]
v.add_decl("\}")
v.add_decl("\};")
- 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 class *class;")
- self.header.add_decl("{mtype.ctype} value;")
- self.header.add_decl("\};")
- end
+ if mtype.ctype != "val*" 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;")
+ self.header.add_decl("{mtype.ctype} value;")
+ self.header.add_decl("\};")
#Build BOX
self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
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("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
v.require_declaration("class_{c_name}")
v.add("res->class = &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}();")
+ v.add_decl("/* allocate {mtype} */")
+ v.add_decl("{mtype.ctype} NEW_{c_name}() \{")
+ 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.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
v.add("return (val*){res};")
v.add("\}")
return
+ else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
+ var pointer_type = mainmodule.pointer_type
+
+ self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}();")
+ v.add_decl("/* allocate {mtype} */")
+ v.add_decl("{mtype.ctype} NEW_{c_name}() \{")
+ 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;")
+ 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
return res
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("class_{mtype.c_name}")
+ self.add("{res}->class = &class_{mtype.c_name};")
+ return res
+ else
+ return value
+ end
+ end
+
redef fun class_name_string(value)
do
var res = self.get_name("var_class_name")