import typing
import auto_super_init
import frontend
+import common_ffi
# Add compiling options
redef class ToolContext
cc_paths.append(path_env.split_with(':'))
end
+ var compile_dir = toolcontext.opt_compile_dir.value
+ if compile_dir == null then compile_dir = ".nit_compile"
+ self.compile_dir = compile_dir
end
+ # The compilation directory
+ var compile_dir: String
+
protected fun write_and_make(compiler: AbstractCompiler)
do
var mainmodule = compiler.mainmodule
var time0 = get_time
self.toolcontext.info("*** WRITING C ***", 1)
- var compile_dir = toolcontext.opt_compile_dir.value
- if compile_dir == null then compile_dir = ".nit_compile"
-
compile_dir.mkdir
if self.toolcontext.opt_stacktrace.value then compiler.build_c_to_nit_bindings
self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
+ # FFI
+ for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
+ var amodule = mmodule2nmodule[m]
+ if m.uses_ffi or amodule.uses_legacy_ni then
+ compiler.finalize_ffi_for_module(amodule)
+ end
+ end
+
# Generate the Makefile
var makename = "{mainmodule.name}.mk"
p = orig_dir.join_path(p).simplify_path
cc_includes += " -I \"" + p + "\""
end
- if toolcontext.opt_no_stacktrace.value then
- makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n")
- else
- makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lunwind -lm -lgc\n\n")
+
+ var linker_options = new HashSet[String]
+ for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
+ var amod = mmodule2nmodule[m]
+ linker_options.add(amod.c_linker_options)
end
+
+ if not toolcontext.opt_no_stacktrace.value then
+ linker_options.add("-lunwind")
+ end
+
+ makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc {linker_options.join(" ")}\n\n")
makefile.write("all: {outpath}\n\n")
var ofiles = new Array[String]
# Compile each required extern body into a specific .o
for f in compiler.extern_bodies do
- var basename = f.filename.basename(".c")
- var o = "{basename}.extern.o"
- var ff = orig_dir.join_path(f.filename).simplify_path
- makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
- ofiles.add(o)
+ if f isa ExternCFile then
+ var basename = f.filename.basename(".c")
+ var o = "{basename}.extern.o"
+ var ff = orig_dir.join_path(f.filename).simplify_path
+ makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
+ ofiles.add(o)
+ end
end
# Link edition
# Binds the generated C function names to Nit function names
fun build_c_to_nit_bindings
do
- var compile_dir = modelbuilder.toolcontext.opt_compile_dir.value
- if compile_dir == null then compile_dir = ".nit_compile"
+ var compile_dir = modelbuilder.compile_dir
var stream = new OFStream.open("{compile_dir}/C_fun_names")
stream.write("%\{\n#include \"c_functions_hash.h\"\n%\}\n")
fun compile_header do
var v = self.header
var toolctx = modelbuilder.toolcontext
- if not toolctx.opt_no_stacktrace.value then self.header.add_decl("#define UNW_LOCAL_ONLY")
self.header.add_decl("#include <stdlib.h>")
self.header.add_decl("#include <stdio.h>")
self.header.add_decl("#include <string.h>")
- if toolctx.opt_stacktrace.value then
- self.header.add_decl("#include \"c_functions_hash.h\"")
- end
- self.header.add_decl("#include <signal.h>")
- if not toolctx.opt_no_stacktrace.value then
- self.header.add_decl("#include <libunwind.h>")
- end
self.header.add_decl("#include <gc_chooser.h>")
compile_header_structs
+ compile_nitni_structs
# Signal handler function prototype
- if not toolctx.opt_no_stacktrace.value then self.header.add_decl("void show_backtrace(int);")
+ self.header.add_decl("void show_backtrace(int);")
- # Global variable used by the legacy native interface
+ # Global variable used by intern methods
self.header.add_decl("extern int glob_argc;")
self.header.add_decl("extern char **glob_argv;")
self.header.add_decl("extern val *glob_sys;")
end
- # Declaration of structures the live Nit types
+ # Declaration of structures for live Nit types
protected fun compile_header_structs is abstract
+ # Declaration of structures for nitni undelying the FFI
+ protected fun compile_nitni_structs is abstract
+
# Generate the main C function.
# This function:
# * allocate the Sys object if it exists
fun compile_main_function
do
var v = self.new_visitor
+ if modelbuilder.toolcontext.opt_stacktrace.value then
+ v.add_decl("#include \"c_functions_hash.h\"")
+ end
+ v.add_decl("#include <signal.h>")
+ if not modelbuilder.toolcontext.opt_no_stacktrace.value then
+ v.add_decl("#define UNW_LOCAL_ONLY")
+ v.add_decl("#include <libunwind.h>")
+ end
v.add_decl("int glob_argc;")
v.add_decl("char **glob_argv;")
v.add_decl("val *glob_sys;")
v.add("\}")
end
- # List of additional .c files required to compile (native interface)
- var extern_bodies = new Array[ExternCFile]
+ # List of additional files required to compile (FFI)
+ var extern_bodies = new Array[ExternFile]
# This is used to avoid adding an extern file more than once
private var seen_extern = new ArraySet[String]
- # Generate code that check if an instance is correctly initialized
- fun generate_check_init_instance(mtype: MClassType) is abstract
-
# Generate code that initialize the attributes on a new instance
fun generate_init_attr(v: VISITOR, recv: RuntimeVariable, mtype: MClassType)
do
if b == 0 then return "n/a"
return ((a*10000/b).to_f / 100.0).to_precision(2)
end
+
+ fun finalize_ffi_for_module(nmodule: AModule)
+ do
+ var visitor = new_visitor
+ nmodule.finalize_ffi(visitor, modelbuilder)
+ nmodule.finalize_nitni(visitor)
+ end
+
+ # Does this compiler support the FFI?
+ fun supports_ffi: Bool do return false
end
# A file unit (may be more than one file if
return self.call(propdef, t, args)
end
+ # Generate a monomorphic super send from the method `m`, the type `t` and the arguments `args`
+ fun monomorphic_super_send(m: MMethodDef, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
+ do
+ assert t isa MClassType
+ m = m.lookup_next_definition(self.compiler.mainmodule, t)
+ return self.call(m, t, args)
+ end
+
# Attributes handling
# Generate a polymorphic attribute is_set test
end
end
- # Generate a check-init-instance
- fun check_init_instance(recv: RuntimeVariable, mtype: MClassType) is abstract
-
# Names handling
private var names: HashSet[String] = new HashSet[String]
var returnlabel: nullable String writable = null
end
-# An extern C file to compile
-class ExternCFile
- # The filename of the file
- var filename: String
- # Additionnal specific CC compiler -c flags
- var cflags: String
-end
-
redef class MType
# Return the C type associated to a given Nit static type
fun ctype: String do return "val*"
var mtype = self.mtype.as(MClassType)
var res = v.init_instance(mtype)
var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
- v.check_init_instance(res, mtype)
return res
end
end
var mtype = self.mtype.as(MClassType)
var res = v.init_instance(mtype)
var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
- v.check_init_instance(res, mtype)
return res
end
end
args = v.frame.arguments
end
- var mproperty = self.mproperty
- if mproperty != null then
- if mproperty.intro.msignature.arity == 0 then
+ var callsite = self.callsite
+ if callsite != null then
+ if callsite.mproperty.intro.msignature.arity == 0 then
args = [recv]
end
# Super init call
- var res = v.send(mproperty, args)
+ var res = v.compile_callsite(callsite, args)
return res
end
#self.debug("got {res2} from {mproperty}. drop {recv}")
return res2
end
- v.check_init_instance(recv, mtype)
return recv
end
end
end
private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
end
+
+redef class AModule
+ # Does this module use the legacy native interface?
+ fun uses_legacy_ni: Bool is abstract
+
+ # Write FFI results to file
+ fun finalize_ffi(v: AbstractCompilerVisitor, modelbuilder: ModelBuilder) is abstract
+
+ # Write nitni results to file
+ fun finalize_nitni(v: AbstractCompilerVisitor) is abstract
+end