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")
self.header.add_decl("#include <gc_chooser.h>")
compile_header_structs
+ compile_nitni_structs
# Signal handler function prototype
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
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]
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
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*"
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
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
if arg1 >= recvval.length or arg1 < 0 then
debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
end
- return v.char_instance(recvval[arg1])
+ return v.char_instance(recvval.chars[arg1])
else if pname == "[]=" then
var arg1 = args[1].to_i
if arg1 >= recvval.length or arg1 < 0 then
debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
end
- recvval[arg1] = args[2].val.as(Char)
+ recvval.chars[arg1] = args[2].val.as(Char)
return null
else if pname == "copy_to" then
# sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
var vari = v.frame.map[self.variable.as(not null)]
var value = v.expr(self.n_value)
if value == null then return
- var res = v.send(reassign_property.mproperty, [vari, value])
+ var res = v.send(reassign_callsite.mproperty, [vari, value])
assert res != null
v.frame.map[self.variable.as(not null)] = res
end
if i == null then return null
args.add(i)
end
- var mproperty = self.mproperty.as(not null)
- var res = v.send(mproperty, args)
+ var res = v.send(callsite.mproperty, args)
return res
end
end
var value = v.expr(self.n_value)
if value == null then return
- var mproperty = self.mproperty.as(not null)
- var read = v.send(mproperty, args)
+ var read = v.send(callsite.mproperty, args)
assert read != null
- var write = v.send(self.reassign_property.mproperty, [read, value])
+ var write = v.send(reassign_callsite.mproperty, [read, value])
assert write != null
args.add(write)
- v.send(self.write_mproperty.as(not null), args)
+ v.send(write_callsite.mproperty, args)
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.send(callsite.mproperty, args)
return res
end
if i == null then return null
args.add(i)
end
- var mproperty = self.mproperty.as(not null)
- var res2 = v.send(mproperty, args)
+ var res2 = v.send(callsite.mproperty, args)
if res2 != null then
#self.debug("got {res2} from {mproperty}. drop {recv}")
return res2
if value == null then return
var mproperty = self.mproperty.as(not null)
var attr = v.read_attribute(mproperty, recv)
- var res = v.send(reassign_property.mproperty, [attr, value])
+ var res = v.send(reassign_callsite.mproperty, [attr, value])
assert res != null
assert recv isa MutableInstance
recv.attributes[mproperty] = res
end
redef class AReassignFormExpr
- # @depreciated use `reassign_callsite`
- fun reassign_property: nullable MMethodDef do return self.reassign_callsite.mpropdef
-
# The method designed by the reassign operator.
var reassign_callsite: nullable CallSite
## MESSAGE SENDING AND PROPERTY
redef class ASendExpr
- # @depreciated: use `callsite`
- fun mproperty: nullable MMethod do return callsite.mproperty
-
# The property invoked by the send.
var callsite: nullable CallSite
end
redef class ASendReassignFormExpr
- # @depreciated use `write_callsite`
- fun write_mproperty: nullable MMethod do return write_callsite.mproperty
-
# The property invoked for the writing
var write_callsite: nullable CallSite
redef class ASuperExpr
# The method to call if the super is in fact a 'super init call'
# Note: if the super is a normal call-next-method, then this attribute is null
- var mproperty: nullable MMethod
+ var callsite: nullable CallSite
redef fun accept_typing(v)
do
end
# FIXME: covariance of return type in linear extension?
var superprop = superprops.first
- assert superprop isa MMethodDef
var msignature = v.resolve_signature_for(superprop, recvtype, true)
var args = self.n_args.to_a
v.error(self, "Error: No super method to call for {mproperty}.")
return
end
- self.mproperty = superprop.mproperty
- var args = self.n_args.to_a
var msignature = v.resolve_signature_for(superprop, recvtype, true)
+ var callsite = new CallSite(self, recvtype, true, superprop.mproperty, superprop, msignature, false)
+ self.callsite = callsite
+
+ var args = self.n_args.to_a
if args.length > 0 then
- v.check_signature(self, args, mproperty.name, msignature)
+ callsite.check_signature(v, args)
else
# TODO: Check signature
end
####
redef class ANewExpr
- # @depreciated use `callsite`
- fun mproperty: nullable MMethod do return self.callsite.mproperty
-
# The constructor invoked by the new.
var callsite: nullable CallSite