struct stack_frame_t *frame = stack_frame_head;
GC_static_object *staticObject = staticObjects.top;
val_t object;
+ struct nitni_ref *global_ref;
struct nitni_ref_array_link *local_ref_array_link; /* for native interface */
gc_allocation_pointer = gc_heap_pointer;
staticObject = staticObject->next;
}
+ /* Process global reference to Nit objects from C code */
+ global_ref = nitni_global_ref_list->head;
+ while (global_ref != NULL) {
+ object = global_ref->val;
+ if (!ISNULL(object) && ISOBJ(object)) {
+ global_ref->val = GC_evacuation((obj_t)object);
+ }
+ global_ref = global_ref->next;
+ }
+
/* Process function frames (local variables) */
while (frame != NULL) {
for (j = 0; j < frame->REG_size; j++) {
/* 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 */
+ struct nitni_ref *next, *prev; /* adjacent global references in global list */
+ int count; /* number of time this global reference has been marked */
};
/* This structure is used by extern methods to keep track of local references to Nit objects */
/* Clean all references associated to the current (but returning) extern method. */
extern void nitni_local_ref_clean( void );
+/* List of global references from C code to Nit objects */
+/* Instanciated empty at init of Nit system and filled explicitly by user in C code */
+struct nitni_global_ref_list_t {
+ struct nitni_ref *head, *tail;
+};
+extern struct nitni_global_ref_list_t *nitni_global_ref_list;
+
+/* Initializer of global reference list */
+extern void nitni_global_ref_list_init();
+
+/* Intern function to add a global reference to the list */
+extern void nitni_global_ref_add( struct nitni_ref *ref );
+
+/* Intern function to remove a global reference from the list */
+extern void nitni_global_ref_remove( struct nitni_ref *ref );
+
+/* Increase count on an existing global reference */
+extern void nitni_global_ref_incr( struct nitni_ref *ref );
+
+/* Decrease count on an existing global reference */
+extern void nitni_global_ref_decr( struct nitni_ref *ref );
+
/* Stack frames.
* Are used to:
* - store local variables (REGS) of functions
case nitgc: Nit_gc_init(); break;
default: break; /* Nothing */
}
+
+ /* Initialize global references list */
+ nitni_global_ref_list_init();
}
void prepare_signals(void) {
initialize_gc_option();
while ( link != NULL )
{
for ( i = 0; i < link->count; i ++ ) {
- free( link->reg[ i ] );
+ if ( link->reg[i]->count == 0 ) { /* not registered globally */
+ free( link->reg[ i ] );
+ }
}
last_link = link;
stack_frame_head->nitni_local_ref_head = NULL;
}
+
+struct nitni_global_ref_list_t *nitni_global_ref_list;
+void nitni_global_ref_list_init() {
+ nitni_global_ref_list = (struct nitni_global_ref_list_t*)malloc(sizeof(struct nitni_global_ref_list_t));
+ nitni_global_ref_list->head = NULL;
+ nitni_global_ref_list->tail = NULL;
+}
+
+void nitni_global_ref_add( struct nitni_ref *ref ) {
+ if ( nitni_global_ref_list->head == NULL ) {
+ nitni_global_ref_list->head = ref;
+ nitni_global_ref_list->tail = ref;
+
+ ref->prev = NULL;
+ } else {
+ nitni_global_ref_list->tail->next = ref;
+ ref->prev = nitni_global_ref_list->tail;
+ }
+
+ ref->next = NULL;
+}
+
+void nitni_global_ref_remove( struct nitni_ref *ref ) {
+ if ( ref->prev == NULL ) {
+ nitni_global_ref_list->head = ref->next;
+ } else {
+ ref->prev->next = ref->next;
+ }
+
+ if ( ref->next == NULL ) {
+ nitni_global_ref_list->tail = ref->prev;
+ } else {
+ ref->next->prev = ref->prev;
+ }
+}
+
+extern void nitni_global_ref_incr( struct nitni_ref *ref ) {
+ if ( ref->count == 0 ) /* not registered */
+ {
+ /* add to list */
+ nitni_global_ref_add( ref );
+ }
+
+ ref->count ++;
+}
+
+extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
+ if ( ref->count == 1 ) /* was last reference */
+ {
+ /* remove from list */
+ nitni_global_ref_remove( ref );
+ }
+
+ ref->count --;
+}
v.body.append( fc.to_writer )
end
+ # 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" )
+
+ # 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.header_top.add( "#endif\n" )
end
end
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