X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/compiler_ffi.nit b/src/compiler/compiler_ffi.nit index 76e1044..42423f9 100644 --- a/src/compiler/compiler_ffi.nit +++ b/src/compiler/compiler_ffi.nit @@ -18,7 +18,7 @@ module compiler_ffi intrude import abstract_compiler -intrude import common_ffi +intrude import ffi import nitni redef class MModule @@ -27,8 +27,7 @@ redef class MModule private fun nmodule(v: AbstractCompilerVisitor): nullable AModule do - var m2n = v.compiler.modelbuilder.mmodule2nmodule - return m2n.get_or_null(self) + return v.compiler.modelbuilder.mmodule2node(self) end redef fun finalize_ffi(compiler: AbstractCompiler) @@ -44,16 +43,19 @@ redef class MModule ensure_compile_nitni_base(v) - nitni_ccu.header_c_types.add("#include \"{name}._ffi.h\"\n") + nitni_ccu.header_c_types.add("#include \"{c_name}._ffi.h\"\n") nitni_ccu.header_c_types.add """ extern void nitni_global_ref_incr(void*); extern void nitni_global_ref_decr(void*); """ + var cflags = self.cflags[""].join(" ") 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, cflags) + 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 @@ -75,14 +77,11 @@ extern void nitni_global_ref_decr(void*); redef fun collect_linker_libs do - var s = c_linker_options - if s.is_empty then return null - var res = new ArraySet[String] - res.add s - return res + if not self.ldflags.keys.has("") then return null + return self.ldflags[""] 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 @@ -98,8 +97,7 @@ redef class AMethPropdef 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 amodule = v.compiler.modelbuilder.mmodule2node(mmodule) var mclass_type = mpropdef.mclassdef.bound_mtype # Declare as extern @@ -119,21 +117,21 @@ redef class AMethPropdef 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 @@ -160,6 +158,7 @@ redef class AMethPropdef 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 @@ -192,6 +191,7 @@ redef class AMethPropdef 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 @@ -214,6 +214,7 @@ redef class AMethPropdef var recv_var = v.new_var(return_mtype) v.adapt_signature(mpropdef, arguments) + v.unbox_signature_extern(mpropdef, arguments) arguments.shift @@ -241,6 +242,7 @@ redef class AMethPropdef 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) @@ -251,11 +253,11 @@ end redef class CCompilationUnit fun write_as_nitni(mmodule: MModule, compdir: String) do - var base_name = "{mmodule.name}._nitni" + var base_name = "{mmodule.c_name}._nitni" var h_file = "{base_name}.h" write_header_to_file( mmodule, "{compdir}/{h_file}", new Array[String], - "{mmodule.cname.to_s.to_upper}_NITG_NITNI_H") + "{mmodule.c_name.to_s.to_upper}_NITG_NITNI_H") var c_file = "{base_name}.c" write_body_to_file( mmodule, "{compdir}/{c_file}", ["\"{h_file}\""] ) @@ -307,7 +309,7 @@ redef class MType 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 @@ -325,7 +327,7 @@ redef class MType 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 @@ -339,6 +341,8 @@ redef class MNullableType # 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) @@ -359,7 +363,7 @@ redef class MNullableType 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 @@ -368,6 +372,8 @@ redef class MExplicitCall 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 @@ -381,17 +387,14 @@ redef class MExplicitCall 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_or_extern(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) @@ -399,6 +402,7 @@ redef class MExplicitCall 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 @@ -413,6 +417,7 @@ redef class MExplicitCall 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("\}") @@ -420,12 +425,11 @@ redef class MExplicitCall 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) @@ -436,6 +440,8 @@ redef class MExplicitSuper 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 @@ -449,11 +455,13 @@ redef class MExplicitSuper 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 @@ -463,6 +471,8 @@ redef class MExplicitSuper 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("\}") @@ -470,7 +480,7 @@ redef class MExplicitSuper 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 @@ -486,19 +496,23 @@ redef class MExplicitCast # 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 @@ -517,28 +531,32 @@ redef class MExplicitCast # 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