module compiler_ffi
intrude import abstract_compiler
-intrude import common_ffi
+intrude import ffi
import nitni
redef class MModule
nitni_ccu.write_as_nitni(self, v.compiler.modelbuilder.compile_dir)
for file in nitni_ccu.files do
- v.compiler.extern_bodies.add(new ExternCFile(file, c_compiler_options))
+ var f = new ExternCFile(file, c_compiler_options)
+ f.pkgconfigs.add_all pkgconfigs
+ v.compiler.extern_bodies.add(f)
end
# reset FFI things so the next compilation job, if any, starts with a clean context
return res
end
- private var compiled_callbacks: Array[NitniCallback] = new Array[NitniCallback]
+ private var compiled_callbacks = new Array[NitniCallback]
# Returns true if callbacks has yet to be generated and register it as being generated
private fun check_callback_compilation(cb: NitniCallback): Bool
do
var mmodule = mpropdef.mclassdef.mmodule
var mainmodule = v.compiler.mainmodule
- var amainmodule = v.compiler.modelbuilder.mmodule2nmodule[mainmodule]
var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
var mclass_type = mpropdef.mclassdef.bound_mtype
amodule.ensure_compile_ffi_wrapper
compile_ffi_method(mmodule)
- assert self isa AExternPropdef
-
# nitni - Compile missing callbacks
mmodule.ensure_compile_nitni_base(v)
var ccu = mmodule.nitni_ccu.as(not null)
mtype.compile_extern_type(v, ccu)
# has callbacks already been compiled? (this may very well happen with global compilation)
- if mmodule.check_callback_compilation(mtype) then mtype.compile_extern_helper_functions(v, ccu)
+ mtype.compile_extern_helper_functions(v, ccu, mmodule.check_callback_compilation(mtype))
end
end
# compile callbacks
- for cb in foreign_callbacks.callbacks do if mainmodule.check_callback_compilation(cb) then
- cb.compile_extern_callback(v, ccu)
+ for cb in foreign_callbacks.callbacks do
+ cb.compile_extern_callback(v, ccu, mainmodule.check_callback_compilation(cb))
end
- for cb in foreign_callbacks.supers do if mainmodule.check_callback_compilation(cb) then
- cb.compile_extern_callback(v, ccu)
+ for cb in foreign_callbacks.supers do
+ cb.compile_extern_callback(v, ccu, mainmodule.check_callback_compilation(cb))
end
- for cb in foreign_callbacks.casts do if mainmodule.check_callback_compilation(cb) then
- cb.compile_extern_callbacks(v, ccu)
+ for cb in foreign_callbacks.casts do
+ cb.compile_extern_callbacks(v, ccu, mainmodule.check_callback_compilation(cb))
end
# manage nitni callback set
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)
ccu.header_c_types.add("#endif\n")
end
- private fun compile_extern_helper_functions(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_helper_functions(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
# actually, we do not need to do anything when using the bohem garbage collector
var call_context = from_c_call_context
end
redef class MNullableType
- redef fun compile_extern_helper_functions(v, ccu)
+ redef fun compile_extern_helper_functions(v, ccu, compile_implementation_too)
do
super
# In nitni files, #define friendly as extern
ccu.header_decl.add("#define {base_cname} {full_cname}\n")
+ if not compile_implementation_too then return
+
# FIXME: This is ugly an broke the separate compilation principle
# The real function MUST be compiled only once, #define pragma only protect the compiler, not the loader
# However, I am not sure of the right approach here (eg. week refs are ugly)
end
redef class MExplicitCall
- private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
var mproperty = mproperty
assert mproperty isa MMethod
var full_friendly_csignature = mproperty.build_csignature(recv_mtype, v.compiler.mainmodule, null, long_signature, internal_call_context)
ccu.header_decl.add("extern {full_friendly_csignature};\n")
+ if not compile_implementation_too then return
+
# Internally, implement internal function
var nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
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("\}")
end
redef class MExplicitSuper
- private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
var mproperty = from.mproperty
assert mproperty isa MMethod
var mclass_type = from.mclassdef.mclass.mclass_type
- var mmodule = from.mclassdef.mmodule
# In nitni files, declare internal function as extern
var internal_csignature = mproperty.build_csignature(mclass_type, v.compiler.mainmodule, "___super", long_signature, internal_call_context)
var internal_cname = mproperty.build_cname(mclass_type, v.compiler.mainmodule, "___super", long_signature)
ccu.header_decl.add("#define {friendly_cname} {internal_cname}\n")
+ if not compile_implementation_too then return
+
# Internally, implement internal function
var nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
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("\}")
end
redef class MExplicitCast
- private fun compile_extern_callbacks(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ private fun compile_extern_callbacks(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool)
do
var from = from
var to = to
# In nitni files, #define friendly as extern
ccu.header_decl.add("#define {check_cname} {v.compiler.mainmodule.name}___{check_cname}\n")
- # Internally, implement internal function
- var nitni_visitor = v.compiler.new_visitor
- nitni_visitor.frame = v.frame
+ if compile_implementation_too then
+ # Internally, implement internal function
+ 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)"
- nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
- nitni_visitor.add_decl("{full_internal_csignature} \{")
+ var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
- var from_var = new RuntimeVariable("from->value", from, from)
- var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
- nitni_visitor.add("return {recv_var};")
+ nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
+ nitni_visitor.add_decl("{full_internal_csignature} \{")
- nitni_visitor.add("\}")
+ 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.add("\}")
+ end
# special checks
if from == to.as_nullable then
# In nitni files, #define friendly as extern
ccu.header_decl.add("#define {cast_cname} {v.compiler.mainmodule.name}___{cast_cname}\n")
- # Internally, implement internal function
- nitni_visitor = v.compiler.new_visitor
- nitni_visitor.frame = v.frame
+ if compile_implementation_too then
+ # Internally, implement internal function
+ 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)"
- nitni_visitor.add_decl("/* nitni cast for {from} to {to} */")
- nitni_visitor.add_decl("{full_internal_csignature} \{")
+ var 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)
+ var 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")
- nitni_visitor.add("if (!{check}) \{")
- nitni_visitor.add_abort("FFI cast failed")
- nitni_visitor.add("\}")
+ ## test type
+ var check = nitni_visitor.type_test(from_var, to, "FFI cast")
+ nitni_visitor.add("if (!{check}) \{")
+ nitni_visitor.add_abort("FFI cast failed")
+ nitni_visitor.add("\}")
- ## internal cast
- recv_var = nitni_visitor.autobox(from_var, to)
+ ## internal cast
+ var 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)
+ nitni_visitor.ret_to_c(recv_var, to)
- nitni_visitor.add("\}")
+ nitni_visitor.add("\}")
+ end
# special casts
if from.as_nullable == to then