import syntax # FIXME: to remove since it breaks modularity
+# Transitive variable through the frontier file
+# Represents a variable going from Nit to C or from C to Nit
+abstract class NiVariable
+ fun ni_from_name : String is abstract
+ fun ni_to_name : String is abstract
+ fun ni_type : MMType is abstract
+
+ # needs to be boxed or unboxed
+ # anything using the GC
+ fun needs_preparation : Bool
+ do
+ return ni_type.local_class.primitive_info == null or
+ ni_type.local_class.primitive_info.tagged or
+ ni_type.is_nullable
+ end
+
+ # prepare variable to callback to Nit
+ fun prepare_for_nit( fc : FunctionCompiler )
+ do
+ if needs_preparation then
+ fc.decls.add( "val_t {ni_to_name};\n" )
+ fc.exprs.add( "{ni_type.assign_from_friendly( ni_to_name, ni_from_name )};\n" )
+ end
+ end
+
+ fun prepare_for_c( fc : FunctionCompiler )
+ do
+ if needs_preparation then
+ ni_type.compile_new_local_ref( ni_to_name, fc, not self isa ReturnVariable ) # TODO
+ fc.exprs.add( "{ni_type.assign_to_friendly( ni_to_name, ni_from_name )};\n" )
+ end
+ end
+
+ # format of the variable to callback to Nit
+ fun as_arg_to_nit : String
+ do
+ if needs_preparation then
+ return ni_to_name
+ else if ( ni_type.local_class.primitive_info != null or ni_type.local_class.global.is_extern ) and
+ not ni_type.is_nullable then # int, float, point/void* ...
+ return ni_type.boxtype(ni_from_name)
+ else
+ return "{ni_from_name}->ref.val"
+ end
+ end
+
+ # format of the variable to call C implementation functions
+ fun as_arg_to_c : String
+ do
+ if needs_preparation then
+ return ni_to_name
+ else
+ return ni_type.unboxtype( ni_from_name )
+ end
+ end
+end
+
+redef class MMParam
+ super NiVariable
+
+ redef fun ni_from_name do return name.to_s
+ redef fun ni_to_name do return "trans___{name}"
+ redef fun ni_type do return mmtype
+end
+
+class ReceiverVariable
+ super NiVariable
+
+ redef fun ni_from_name do return "recv"
+ redef fun ni_to_name do return "trans_recv"
+
+ redef var ni_type : MMType
+ init ( t : MMType ) do ni_type = t
+end
+
+class ReturnVariable
+ super NiVariable
+
+ redef fun ni_from_name do return "orig_return"
+ redef fun ni_to_name do return "trans_return"
+
+ redef var ni_type : MMType
+ init ( t : MMType ) do ni_type = t
+
+ # used only by friendly callbacks to Nit
+ redef fun prepare_for_c( fc )
+ do
+ fc.decls.add( "val_t {ni_from_name};\n" )
+ ni_type.compile_new_local_ref( ni_to_name, fc, true )
+ end
+ redef fun prepare_for_nit( fc )
+ do
+ ni_type.compile_new_local_ref( ni_from_name, fc, false )
+ fc.decls.add( "val_t {ni_to_name};\n" )
+ end
+end
+
redef class MMSrcModule
fun compile_frontier( v : FrontierVisitor )
do
native_header = "{directory.path}/{name}_nit.h"
end
if native_header.file_exists then
- v.body.add( "#include \"{native_header.path_from_parent}\"\n" )
- v.header.add( "#include \"{native_header.path_from_parent}\"\n" )
+ var path = "..".join_path(native_header).simplify_path
+ v.body.add( "#include \"{path}\"\n" )
+ v.header.add( "#include \"{path}\"\n" )
end
for local_class in local_classes do
for cast in explicit_casts do
v.casts.add( cast )
- v.types.add( cast.from )
- v.types.add( cast.to )
+ v.types.add( cast.from.direct_type )
+ v.types.add( cast.to.direct_type )
end
# adds super
var fc = new FunctionCompiler( friendly_super_csignature )
# params
- var params = new Array[String]
+ var params = new Array[NiVariable]
+ params.add( signature.recv_ni_variable )
+ params.add_all( signature.params )
- # receiver
- var name_for_sub = "recv___nit"
- fc.decls.add( "val_t {name_for_sub};\n" )
- fc.exprs.add( "{signature.recv.assign_from_friendly( name_for_sub, "recv" )};\n" )
- params.add( name_for_sub )
+ # prepare transition
+ for p in params do p.prepare_for_nit( fc )
- # other params
- for p in signature.params do
- name_for_sub = "{p.name}___nit"
- fc.decls.add( "val_t {name_for_sub};\n" )
- fc.exprs.add( "{p.mmtype.assign_from_friendly( name_for_sub, p.name.to_s )};\n" )
- params.add( name_for_sub )
- end
+ # extract strings
+ var args = new Array[String]
+ for p in params do args.add( p.as_arg_to_nit )
# hook to generated C
- var return_type : nullable MMType = null
-
- if signature.return_type != null then
- return_type = signature.return_type
- end
-
+ var rnv = signature.return_ni_variable
var s = new Buffer
- if return_type != null then
- fc.decls.add( "{return_type.friendly_extern_name} return___nitni;\n" )
- fc.decls.add( "val_t return___nit;\n" )
- s.append( "return___nit = " )
+ if rnv != null then
+ rnv.prepare_for_c( fc )
+ s.append( "{rnv.ni_from_name} = " )
end
- s.append( "{super_meth_call}( recv___nit )" )
-
- s.append( "( {params.join( ", " )} );\n" )
+ s.append( "{super_meth_call}( {signature.recv_ni_variable.as_arg_to_nit} )" )
+ s.append( "( {args.join( ", " )} );\n" )
fc.exprs.add( s.to_s )
- # verify and return
- if return_type != null
- then
- fc.exprs.add( "{return_type.assign_to_friendly( "return___nitni", "return___nit" )};\n" )
- fc.exprs.add( "return return___nitni;\n" )
+ # return
+ if rnv != null then
+ fc.exprs.add( "{rnv.ni_type.assign_to_friendly( rnv.ni_to_name, rnv.ni_from_name )};\n" )
+ fc.exprs.add( "return {rnv.ni_to_name};\n" )
end
v.body.append( fc.to_writer )
# It handles variables conversions and verification
fun compile_out_to_frontier( v : FrontierVisitor )
do
+ # a simple out method can be optimized
+ # To qualify as simple this method must:
+ # - have no explicit imports (including super and casts)
+ # - return nothing or return a primitive to C
+ var is_simple = explicit_imports.is_empty and not need_super and
+ explicit_casts.is_empty and (signature.return_type == null or
+ signature.return_type.local_class.primitive_info != null )
+
# header
v.header.add( "\n/* out/indirect function for {full_name} */\n" )
v.header.add( "{out_csignature};\n" ) # incoming types boxed
var fc = new FunctionCompiler( out_csignature )
# params
- var params = new List[String]
+ var params = new List[NiVariable]
+ if not is_init then params.add( signature.recv_ni_variable )
+ params.add_all( signature.params )
- if not is_init then
- var name_for_impl = "recv___nitni"
- fc.decls.add( "{signature.recv.friendly_extern_name} {name_for_impl};\n" )
- fc.exprs.add( "{signature.recv.assign_to_friendly( name_for_impl, "recv" )};\n" )
- params.add( name_for_impl )
- end
+ var args = new List[String]
- for p in signature.params do
- var name_for_impl = "{p.name}___nitni"
- fc.decls.add( "{p.mmtype.friendly_extern_name} {name_for_impl};\n" )
- fc.exprs.add( "{p.mmtype.assign_to_friendly( name_for_impl, p.name.to_s )};\n" )
- params.add( name_for_impl )
+ for nv in params do
+ if not is_simple or nv.ni_type.local_class.primitive_info != null then
+ nv.prepare_for_c( fc )
+ args.add( nv.as_arg_to_c )
+ else
+ args.add( "NULL" )
+ end
end
# call to impl
- var return_type : nullable MMType = null
-
- if signature.return_type != null then
- return_type = signature.return_type
- else if is_init then
- return_type = local_class.get_type
+ var rnv = signature.return_ni_variable
+ if rnv == null and is_init then
+ rnv = new ReturnVariable( signature.recv )
end
var s = new Buffer
- if return_type != null then
- fc.decls.add( "{return_type.friendly_extern_name} return___nitni;\n" )
- fc.decls.add( "val_t return___nit;\n" )
- s.append( "return___nitni = " )
+ if rnv != null then
+ rnv.prepare_for_nit( fc )
+ s.append( "{rnv.ni_from_name} = " )
end
- s.append( "{extern_name.as(not null)}( {params.join( ", " )} );\n" )
+ s.append( "{extern_name.as(not null)}( {args.join( ", " )} );\n" )
fc.exprs.add( s.to_s )
+ if rnv != null then
+ fc.exprs.add( "{rnv.ni_type.assign_from_friendly( rnv.ni_to_name, rnv.ni_from_name )};\n" )
+ end
+
+ fc.exprs.add( "nitni_local_ref_clean( );\n" )
+
# return
- if return_type != null then
- fc.exprs.add( "{return_type.assign_from_friendly( "return___nit", "return___nitni" )};\n" )
- fc.exprs.add( "return return___nit;\n" )
+ if rnv != null then
+ fc.exprs.add( "return {rnv.ni_to_name};\n" )
end
v.body.append( fc.to_writer )
end
redef class MMSignature
+ var recv_ni_variable : ReceiverVariable
+ var return_ni_variable : nullable ReturnVariable
+ redef init( params, return_type, recv_type )
+ do
+ super
+
+ if return_type != null then
+ return_ni_variable = new ReturnVariable( return_type )
+ else
+ return_ni_variable = null
+ end
+ recv_ni_variable = new ReceiverVariable( recv_type )
+ end
+
fun compile_frontier( v : FrontierVisitor )
do
# receiver
- v.types.add( recv )
+ v.types.add( recv.direct_type )
# params
- for p in params do v.types.add( p.mmtype )
+ for p in params do v.types.add( p.mmtype.direct_type )
# return
var rt = return_type
if rt != null then
- v.types.add( rt )
+ v.types.add( rt.direct_type )
end
end
end
end
end
-redef class String
- # return path from one level deeper
- # could be moved to stdlib.file
- fun path_from_parent : String
- do
- if self[0] == '/' # is_absolute
- then
- return self
- else
- return "../{self}"
- end
-
- end
-end
-
redef class MMImportedCast
# Defines functions to cast types and verify the type of an object.
fun compile_to_frontier( v : FrontierVisitor )
var temp_name = "temp"
fc.decls.add( "val_t {temp_name};\n" )
- fc.decls.add( "{to.friendly_extern_name} {out_name};\n" )
+ to.compile_new_local_ref( out_name, fc, true )
fc.exprs.add( "{from.assign_from_friendly(temp_name, in_name)};\n" )
# Is to be nested within another function.
fun compile_check_isa( fc : FunctionCompiler, name : String )
do
- fc.exprs.add( "if ( ! {compile_condition_isa( name )} )\{" )
+ fc.exprs.add( "if ( ! {compile_condition_isa( name )} )\{\n" )
fc.exprs.add( "\tfprintf( stderr, \"Casting to {self} failed because value is not a {self}.\" );\n" )
fc.exprs.add( "\tabort();\n" )
- fc.exprs.add( "\}" )
+ fc.exprs.add( "\}\n" )
end
# Compiles an expression to verify if an object is of the given type.
# defines struct
v.header_top.add( "#ifndef {guard}\n" )
v.header_top.add( "#define {guard}\n" )
- v.header_top.add( "typedef struct s_{name}\{\n" )
- v.header_top.add( "\tval_t v;\n" )
- v.header_top.add( "\} {name};\n" )
- v.header_top.add( "#endif\n\n" )
+ v.header_top.add( "struct s_{name}\{\n" )
+ v.header_top.add( "\t\tstruct nitni_ref ref; /* real ref struct, must be first */\n" )
+ v.header_top.add( "\};\n" )
+ v.header_top.add( "typedef struct s_{name} *{name};\n" )
# add null version, as a struct
if is_nullable then
- var null_getter = "null_{as_notnull.friendly_extern_name}"
- var null_getter_local = "{mmmodule.to_s}_{null_getter}"
+ var local_null_getter = local_friendly_null_getter_from( mmmodule )
+
+ v.header_top.add( "#ifndef {friendly_null_getter}\n" )
+ v.header_top.add( "#define {friendly_null_getter} {local_null_getter}\n" )
+ v.header_top.add( "#endif\n" )
+
+ v.header_top.add( "{name} {local_null_getter}();\n" )
+
+ var fc = new FunctionCompiler( "{name} {local_null_getter}()" )
+ compile_new_local_ref( "n", fc, true )
+ fc.exprs.add( "return n;\n" )
+ v.body.append( fc.to_writer )
+ end
- v.header.add( "{name} {null_getter_local}();\n" )
+ # reference incr
+ var incr_name = "{as_notnull.mangled_name}_incr_ref"
+ v.header_top.add( "#define {incr_name}( x ) nitni_global_ref_incr( (struct nitni_ref*)(x) )\n" )
- v.header.add( "#ifndef {null_getter}\n" )
- v.header.add( "#define {null_getter} {null_getter_local}\n" )
- v.header.add( "#endif\n\n" )
+ # reference decr
+ var decr_name = "{as_notnull.mangled_name}_decr_ref"
+ v.header_top.add( "#define {decr_name}( x ) nitni_global_ref_decr( (struct nitni_ref*)(x) )\n" )
- v.body.add( "{name} {null_getter_local}()\n" )
- v.body.add( "\{\n" )
- v.body.add( "\t{name} n;\n" )
- v.body.add( "\tn.v = NIT_NULL;\n" )
- v.body.add( "\treturn n;\n" )
- v.body.add( "\}\n\n" )
+ v.header_top.add( "#endif\n" )
+ end
+ end
+
+ fun compile_new_local_ref( var_name : String, fc : FunctionCompiler, stack_it : Bool )
+ do
+ var type_name = friendly_extern_name
+
+ fc.decls.add( "{type_name} {var_name};\n" )
+ if uses_nitni_ref then
+ fc.exprs.add( "{var_name} = malloc( sizeof( struct s_{type_name} ) );\n" )
+ fc.exprs.add( "{var_name}->ref.val = NIT_NULL;\n" )
+ fc.exprs.add( "{var_name}->ref.count = 0;\n" )
+ if stack_it then
+ fc.exprs.add( "nitni_local_ref_add( (struct nitni_ref *){var_name} );\n" )
end
end
end
+
+ # compiles a stub local reference for unused references
+ # allows to maintain static typing but avoids malloc and free
+ fun compile_stub_local_ref( var_name : String, fc : FunctionCompiler )
+ do
+ var type_name = friendly_extern_name
+ fc.decls.add( "{type_name} {var_name};\n" )
+ if uses_nitni_ref then
+ fc.exprs.add( "{var_name} = ({type_name})NULL;\n" )
+ end
+ end
end
redef class MMExplicitImport
var fc = new FunctionCompiler( method.frontier_csignature_from( v.mmmodule, local_class ) )
# params
- var params = new Array[String]
-
- # if not init, add receiver
- if not method.is_init then
- var name_for_sub = "recv___nit"
- fc.decls.add( "val_t {name_for_sub};\n" )
- fc.exprs.add( "{signature.recv.assign_from_friendly( name_for_sub, "recv" )};\n" )
- params.add( name_for_sub )
- end
-
- for p in signature.params do
- var name_for_sub = "{p.name}___nit"
- fc.decls.add( "val_t {name_for_sub};\n" )
- fc.exprs.add( "{p.mmtype.assign_from_friendly( name_for_sub, p.name.to_s )};\n" )
- params.add( name_for_sub )
- end
+ var params = new Array[NiVariable]
+ if not method.is_init then params.add( signature.recv_ni_variable )
+ params.add_all( signature.params )
- # call to nit
- var return_type : nullable MMType = null
+ for nv in params do nv.prepare_for_nit( fc )
# handles return of method or constructor
- if method.signature.return_type != null then
- return_type = method.signature.return_type
- else if method.is_init then
- return_type = method.local_class.get_type
+ var rnv = signature.return_ni_variable
+ if rnv == null and method.is_init then
+ rnv = new ReturnVariable( signature.recv )
end
-
var s = new Buffer
- if return_type != null then
- fc.decls.add( "{return_type.friendly_extern_name} result___nitni;\n" )
- fc.decls.add( "val_t result___nit;\n" )
- s.append( "result___nit = " )
+ if rnv != null then
+ rnv.prepare_for_c( fc )
+ s.append( "{rnv.ni_from_name} = " )
end
# hook to generated C code
if method.is_init then
s.append( "NEW_{local_class}_{method.global.intro.cname}" )
else
- s.append( "{method.global.meth_call}( recv___nit )" )
+ s.append( "{method.global.meth_call}( {signature.recv_ni_variable.as_arg_to_nit} )" )
end
- s.append( "( {params.join( ", " )} );\n" )
+ var args = new Array[String]
+ for p in params do args.add( p.as_arg_to_nit )
+
+ s.append( "( {args.join( ", " )} );\n" )
fc.exprs.add( s.to_s )
# return
- if return_type != null then
- var result_name_nitni = "result___nitni"
- var result_name_nit = "result___nit"
-
- fc.exprs.add( "{return_type.assign_to_friendly( result_name_nitni, result_name_nit )};\n" )
- fc.exprs.add( "return {result_name_nitni};\n" )
+ if rnv != null then
+ fc.exprs.add( "{rnv.ni_type.assign_to_friendly( rnv.ni_to_name, rnv.ni_from_name )};\n" )
+ fc.exprs.add( "return {rnv.ni_to_name};\n" )
end
v.body.append( fc.to_writer )