extern int glob_argc;
extern char ** glob_argv;
+/* Native reference to Nit objects */
+/* This structure is used to represent every Nit type in extern methods and custom C code. */
+struct nitni_ref {
+ val_t val; /* reference to the real Nit object, is kept up-to-date by GC */
+};
+
+/* This structure is used by extern methods to keep track of local references to Nit objects */
+/* These references make sure an object is not collected by the GC while
+ * this extern methods is on the call stack. */
+/* This takes the form of an array link, each link of size 8 to avoid multiple mallocs. */
+#define NITNI_REF_ARRAY_LINK_SIZE 8
+struct nitni_ref_array_link {
+ struct nitni_ref *reg[ NITNI_REF_ARRAY_LINK_SIZE ];
+ int count; /* nubmer of elements in this link */
+ struct nitni_ref_array_link *next; /* next link in the list */
+};
+
+/* Register reference to Nit object with the latest extern method called. */
+extern void nitni_local_ref_add( struct nitni_ref *ref );
+
+/* Clean all references associated to the current (but returning) extern method. */
+extern void nitni_local_ref_clean( void );
+
/* Stack frames.
* Are used to:
* - store local variables (REGS) of functions
struct stack_frame_t *closure_ctx; /* closure context (for functions that have closure parameters) */
fun_t *closure_funs; /* closure functions (for functions that have closure parameters) */
int has_broke; /* has an escape occured? 0 if false, label_idx (>0) if true */
+ struct nitni_ref_array_link *nitni_local_ref_head; /* points to head of array link contaning local variables used via nitni */
int REG_size; /* number of local variables */
- val_t REG[1]; /* local variables (flexible array) */
+ val_t REG[1]; /* local variables (flexible array, this must be the last variable is extended in fra struct */
};
extern struct stack_frame_t *stack_frame_head;
fprintf(stderr, ")\n");
nit_exit(1);
}
+
+/* Register reference to Nit object with the latest extern method called. */
+void nitni_local_ref_add( struct nitni_ref *ref ) {
+ struct nitni_ref_array_link **link_p;
+ struct nitni_ref_array_link * link = NULL;
+
+ /* find usable link or link to create */
+ link_p = &( stack_frame_head->nitni_local_ref_head );
+ while ( (*link_p) != NULL &&
+ (*link_p)->count >= NITNI_REF_ARRAY_LINK_SIZE ) {
+ link_p = &((*link_p)->next);
+ }
+
+ /* create link if needed */
+ if ( *link_p == NULL ) {
+ link = malloc( sizeof(struct nitni_ref_array_link) );
+ link->count = 0;
+ link->next = NULL;
+
+ (*link_p) = link;
+ } else {
+ link = *link_p;
+ }
+
+ /* add to link */
+ link->reg[ link->count ] = ref;
+ link->count ++;
+}
+
+/* Clean all references associated to the current (but returning) extern method. */
+void nitni_local_ref_clean( void ) {
+ struct nitni_ref_array_link * link,
+ * last_link;
+ int i;
+
+ link = stack_frame_head->nitni_local_ref_head;
+ while ( link != NULL )
+ {
+ for ( i = 0; i < link->count; i ++ ) {
+ free( link->reg[ i ] );
+ }
+
+ last_link = link;
+ if ( link->count == NITNI_REF_ARRAY_LINK_SIZE )
+ link = link->next;
+ else
+ link = NULL;
+
+ free(last_link);
+ }
+
+ stack_frame_head->nitni_local_ref_head = NULL;
+}
var s = new Buffer
if return_type != null then
- fc.decls.add( "{return_type.friendly_extern_name} return___nitni;\n" )
+ return_type.compile_new_local_ref( "return___nitni", fc, true )
fc.decls.add( "val_t return___nit;\n" )
s.append( "return___nit = " )
end
if not is_init then
var name_for_impl = "recv___nitni"
- fc.decls.add( "{signature.recv.friendly_extern_name} {name_for_impl};\n" )
+ signature.recv.compile_new_local_ref( name_for_impl, fc, true )
fc.exprs.add( "{signature.recv.assign_to_friendly( name_for_impl, "recv" )};\n" )
params.add( name_for_impl )
end
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" )
+ p.mmtype.compile_new_local_ref( name_for_impl, fc, true )
fc.exprs.add( "{p.mmtype.assign_to_friendly( name_for_impl, p.name.to_s )};\n" )
params.add( name_for_impl )
end
var s = new Buffer
if return_type != null then
- fc.decls.add( "{return_type.friendly_extern_name} return___nitni;\n" )
+ # prepare to receive return but do not stack it here
+ return_type.compile_new_local_ref( "return___nitni", fc, false )
fc.decls.add( "val_t return___nit;\n" )
s.append( "return___nitni = " )
end
fc.exprs.add( s.to_s )
- # return
if return_type != null then
fc.exprs.add( "{return_type.assign_from_friendly( "return___nit", "return___nitni" )};\n" )
+ end
+
+ fc.exprs.add( "nitni_local_ref_clean( );\n" )
+
+ # return
+ if return_type != null then
fc.exprs.add( "return return___nit;\n" )
end
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.mangled_name}"
- var null_getter_local = "{mmmodule.to_s}_{null_getter}"
-
- v.header.add( "{name} {null_getter_local}();\n" )
+ var fc = new FunctionCompiler( "{name} {null_getter}()" )
+ v.header_top.add( "{name} {null_getter}();\n" )
+ compile_new_local_ref( "n", fc, true )
+ fc.exprs.add( "return n;\n" )
+ v.body.append( fc.to_writer )
+ end
- v.header.add( "#ifndef {null_getter}\n" )
- v.header.add( "#define {null_getter} {null_getter_local}\n" )
- v.header.add( "#endif\n\n" )
+ v.header_top.add( "#endif\n" )
+ end
+ end
- 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" )
+ 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" )
+ if stack_it then
+ fc.exprs.add( "nitni_local_ref_add( (struct nitni_ref *){var_name} );\n" )
end
end
end
var s = new Buffer
if return_type != null then
- fc.decls.add( "{return_type.friendly_extern_name} result___nitni;\n" )
+ return_type.compile_new_local_ref( "result___nitni", fc, true )
fc.decls.add( "val_t result___nit;\n" )
s.append( "result___nit = " )
end