X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/compiler_ffi.nit b/src/compiler/compiler_ffi/compiler_ffi.nit similarity index 63% rename from src/compiler/compiler_ffi.nit rename to src/compiler/compiler_ffi/compiler_ffi.nit index 42423f9..9b0dc27 100644 --- a/src/compiler/compiler_ffi.nit +++ b/src/compiler/compiler_ffi/compiler_ffi.nit @@ -17,70 +17,22 @@ # FFI support for the compilers module compiler_ffi -intrude import abstract_compiler -intrude import ffi +intrude import light import nitni redef class MModule private var foreign_callbacks = new ForeignCallbackSet - var nitni_ccu: nullable CCompilationUnit = null - - private fun nmodule(v: AbstractCompilerVisitor): nullable AModule - do - return v.compiler.modelbuilder.mmodule2node(self) - end redef fun finalize_ffi(compiler: AbstractCompiler) do if not uses_ffi then return - var v = compiler.new_visitor - var n = nmodule(v) - if n == null then return - n.ensure_compile_ffi_wrapper - finalize_ffi_wrapper(v.compiler.modelbuilder.compile_dir, v.compiler.mainmodule) - for file in ffi_files do v.compiler.extern_bodies.add(file) - - ensure_compile_nitni_base(v) - - 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 - var f = new ExternCFile(file, cflags) - f.pkgconfigs.add_all pkgconfigs - v.compiler.extern_bodies.add(f) - end + super - # reset FFI things so the next compilation job, if any, starts with a clean context - # FIXME clean and rationalize this - nitni_ccu = null - compiled_ffi_methods.clear - ffi_ccu = null - ffi_files.clear compiled_callbacks.clear #Do not reset `foreign_callbacks` and `ffi_callbacks` because they are computed in previous phases end - private fun ensure_compile_nitni_base(v: AbstractCompilerVisitor) - do - if nitni_ccu != null then return - - nitni_ccu = new CCompilationUnit - end - - redef fun collect_linker_libs - do - if not self.ldflags.keys.has("") then return null - return self.ldflags[""] - end - private var compiled_callbacks = new Array[NitniCallback] # Returns true if callbacks has yet to be generated and register it as being generated @@ -93,23 +45,12 @@ extern void nitni_global_ref_decr(void*); end redef class AMethPropdef - private fun compile_ffi_support_to_c(v: AbstractCompilerVisitor) + redef fun compile_ffi_support_to_c(v) do + super + var mmodule = mpropdef.mclassdef.mmodule var mainmodule = v.compiler.mainmodule - var amodule = v.compiler.modelbuilder.mmodule2node(mmodule) - var mclass_type = mpropdef.mclassdef.bound_mtype - - # Declare as extern - var csignature = mpropdef.mproperty.build_csignature(mclass_type, mmodule, "___impl", long_signature, internal_call_context) - v.declare_once("{csignature};") - - # FFI part - amodule.ensure_compile_ffi_wrapper - compile_ffi_method(mmodule) - - # nitni - Compile missing callbacks - mmodule.ensure_compile_nitni_base(v) var ccu = mmodule.nitni_ccu.as(not null) for mtype in foreign_callbacks.types do @@ -137,178 +78,71 @@ redef class AMethPropdef # manage nitni callback set mmodule.foreign_callbacks.join(foreign_callbacks) end +end - redef fun compile_externmeth_to_c(v, mpropdef, arguments) +redef class MExplicitCall + private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool) do - # if using the old native interface fallback on previous implementation - if n_extern_code_block == null then return super + var mproperty = mproperty + assert mproperty isa MMethod - var mmodule = mpropdef.mclassdef.mmodule - mmodule.uses_ffi = true + # In nitni files, declare internal function as extern + 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") - var mclass_type = mpropdef.mclassdef.bound_mtype + if not compile_implementation_too then return - # Outgoing code in compiler - var externname = mpropdef.mproperty.build_cname(mpropdef.mclassdef.bound_mtype, mmodule, "___impl", long_signature) - var recv_var: nullable RuntimeVariable = null - var return_mtype = mpropdef.msignature.return_mtype - if return_mtype != null then - return_mtype = return_mtype.anchor_to(mmodule, mclass_type) - recv_var = v.new_var(return_mtype) - end + # Internally, implement internal function + var nitni_visitor = v.compiler.new_visitor + nitni_visitor.frame = v.frame + var msignature = mproperty.lookup_first_definition(v.compiler.mainmodule, recv_mtype).msignature + var csignature_blind = mproperty.build_csignature(recv_mtype, v.compiler.mainmodule, null, long_signature, internal_call_context) - 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 - var arg = arguments[a] - var param_mtype: MType - if a == 0 then - param_mtype = mpropdef.mclassdef.mclass.mclass_type - else param_mtype = mpropdef.msignature.mparameters[a-1].mtype - - param_mtype = param_mtype.anchor_to(mmodule, mclass_type) - - if param_mtype.is_cprimitive then - arguments_for_c.add(arg.name) - else - v.add("struct nitni_instance* var_for_c_{a};") - v.add("var_for_c_{a} = nit_alloc(sizeof(struct nitni_instance));") - v.add("var_for_c_{a}->value = {arg.name};") - arguments_for_c.add("var_for_c_{a}") - end - end + nitni_visitor.add_decl("/* nitni callback for {mproperty.full_name} */") + nitni_visitor.add_decl("{csignature_blind} \{") - if recv_var == null then - v.add("{externname}({arguments_for_c.join(", ")});") + var vars = new Array[RuntimeVariable] + var mtype: MType = recv_mtype + var recv_var = null + if mproperty.is_init then + 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 - assert return_mtype != null - if return_mtype.is_cprimitive then - v.add("{recv_var} = {externname}({arguments_for_c.join(", ")});") - else - v.add("struct nitni_instance* ret_var;") - 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) + 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 - compile_ffi_support_to_c(v) - return true - end - - redef fun compile_externinit_to_c(v, mpropdef, arguments) - do - # if using the old native interface fallback on previous implementation - if n_extern_code_block == null then return super - - var mmodule = mpropdef.mclassdef.mmodule - mmodule.uses_ffi = true - - var mclass_type = mpropdef.mclassdef.bound_mtype - - var externname = mpropdef.mproperty.build_cname(mpropdef.mclassdef.bound_mtype, mmodule, "___impl", long_signature) - var return_mtype = arguments.first.mtype - var recv_var = v.new_var(return_mtype) - - v.adapt_signature(mpropdef, arguments) - v.unbox_signature_extern(mpropdef, arguments) - - arguments.shift - - var arguments_for_c = new Array[String] - for a in [0..arguments.length[ do - var arg = arguments[a] - var param_mtype: MType - param_mtype = mpropdef.msignature.mparameters[a].mtype - param_mtype = param_mtype.anchor_to(mmodule, mclass_type) - - if param_mtype.is_cprimitive then - arguments_for_c.add(arg.name) - else - v.add("struct nitni_instance* var_for_c_{a};") - v.add("var_for_c_{a} = nit_alloc(sizeof(struct nitni_instance));") - v.add("var_for_c_{a}->value = {arg.name};") - arguments_for_c.add("var_for_c_{a}") - end - end + vars.add(recv_var) - if return_mtype.is_cprimitive then - v.add("{recv_var} = {externname}({arguments_for_c.join(", ")});") - else - v.add("struct nitni_instance* ret_var;") - v.add("ret_var = {externname}({arguments_for_c.join(", ")});") - v.add("{recv_var} = ret_var->value;") + 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 - recv_var = v.box_extern(recv_var, return_mtype) - v.ret(recv_var) - compile_ffi_support_to_c(v) - return true - end -end - -redef class CCompilationUnit - fun write_as_nitni(mmodule: MModule, compdir: String) - do - 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.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}\""] ) - - files.add( "{compdir}/{c_file}" ) - end -end - -redef class AbstractCompiler - # Cache to avoid multiple compilation of NULL values - # see FIXME in `MNullableType#compile_extern_helper_functions` - private var compiled_null_types = new Array[MNullableType] -end + var ret_var = nitni_visitor.send(mproperty, vars) -redef class AbstractCompilerVisitor - # Create a `RuntimeVariable` for this C variable originating from C user code - private fun var_from_c(name: String, mtype: MType): RuntimeVariable - do - if mtype.is_cprimitive then - return new RuntimeVariable(name, mtype, mtype) - else - return new RuntimeVariable("{name}->value", mtype, mtype) + var return_mtype = msignature.return_mtype + if mproperty.is_init then + if recv_mtype.mclass.kind != extern_kind then ret_var = recv_var + return_mtype = recv_mtype end - end - - # Return a `RuntimeVarible` to C user code - private fun ret_to_c(src: RuntimeVariable, mtype: MType) - do - if mtype.is_cprimitive then - add("return {src};") - else - add("struct nitni_instance* ret_for_c;") - add("ret_for_c = nit_alloc(sizeof(struct nitni_instance));") - add("ret_for_c->value = {src};") - add("return ret_for_c;") + if return_mtype != null then + 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 end redef class MType - private fun compile_extern_type(v: AbstractCompilerVisitor, ccu: CCompilationUnit) - do - assert not is_cprimitive - - # define friendly type - ccu.header_c_types.add("#ifndef NIT_TYPE_{cname}\n") - ccu.header_c_types.add("#define NIT_TYPE_{cname} 1\n") - ccu.header_c_types.add("typedef struct nitni_instance *{cname};\n") - ccu.header_c_types.add("#endif\n") - end - 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 @@ -362,68 +196,6 @@ redef class MNullableType end end -redef class MExplicitCall - private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool) - do - var mproperty = mproperty - assert mproperty isa MMethod - - # In nitni files, declare internal function as extern - 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 msignature = mproperty.lookup_first_definition(v.compiler.mainmodule, recv_mtype).msignature - var csignature_blind = mproperty.build_csignature(recv_mtype, v.compiler.mainmodule, null, long_signature, internal_call_context) - - nitni_visitor.add_decl("/* nitni callback for {mproperty.full_name} */") - nitni_visitor.add_decl("{csignature_blind} \{") - - var vars = new Array[RuntimeVariable] - var mtype: MType = recv_mtype - var recv_var = null - if mproperty.is_init then - 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) - - 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 - - var ret_var = nitni_visitor.send(mproperty, vars) - - var return_mtype = msignature.return_mtype - if mproperty.is_init then - if recv_mtype.mclass.kind != extern_kind then ret_var = recv_var - return_mtype = recv_mtype - end - if return_mtype != null then - 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 -end - redef class MExplicitSuper private fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit, compile_implementation_too: Bool) do