Browse Source

added gc track api

Nicolas Cannasse 8 years ago
parent
commit
4a5b0fa1a6
1 changed files with 118 additions and 1 deletions
  1. 118 1
      src/alloc.c

+ 118 - 1
src/alloc.c

@@ -122,6 +122,7 @@ static const int GC_SIZES[GC_PARTITIONS] = {4,8,12,16,20,	8,64,1<<14,1<<22};
 
 #define GC_PROFILE		1
 #define GC_DUMP_MEM		2
+#define GC_TRACK		4
 
 static int gc_flags = 0;
 static gc_pheader *gc_pages[GC_ALL_PAGES] = {NULL};
@@ -550,6 +551,8 @@ static unsigned char *alloc_all = NULL;
 static unsigned char *alloc_end = NULL;
 #endif
 
+static void hl_gc_check_track();
+
 void *hl_gc_alloc_gen( int size, int flags ) {
 	void *ptr;
 	int time = 0;
@@ -577,6 +580,7 @@ void *hl_gc_alloc_gen( int size, int flags ) {
 		MZERO(ptr,allocated);
 	else if( MEM_HAS_PTR(flags) && allocated != size )
 		MZERO((char*)ptr+size,allocated-size); // erase possible pointers after data
+	if( gc_flags & GC_TRACK ) hl_gc_check_track();
 	return ptr;
 }
 
@@ -798,6 +802,8 @@ HL_API bool hl_is_gc_ptr( void *ptr ) {
 	bid = (int)((unsigned char*)ptr - (unsigned char*)page) / page->block_size;
 	if( bid < page->first_block || bid >= page->max_blocks ) return false;
 	if( page->sizes && page->sizes[bid] == 0 ) return false;
+	// not live (only available if we haven't allocate since then)
+	if( page->bmp && page->next_block == page->first_block && (page->bmp[bid>>3]&(1<<(bid&7))) == 0 ) return false; 
 	return true;
 }
 
@@ -1090,4 +1096,115 @@ DEFINE_PRIM(_VOID, gc_profile, _BOOL);
 DEFINE_PRIM(_VOID, gc_stats, _REF(_F64) _REF(_F64) _REF(_F64));
 DEFINE_PRIM(_VOID, gc_dump_memory, _BYTES);
 DEFINE_PRIM(_I32, gc_get_flags, _NO_ARG);
-DEFINE_PRIM(_VOID, gc_set_flags, _I32);
+DEFINE_PRIM(_VOID, gc_set_flags, _I32);
+
+// ------- TRACKING ------------------------
+
+typedef struct {
+	int_val obj;
+	int_val old_value;
+	void **value;
+	vclosure *callb;
+} hl_track;
+
+static hl_track *tracked = NULL;
+static int tracked_count = 0;
+static int tracked_max = 0;
+
+#define hide_ptr(v)		(((int_val)(v))^1)
+
+static void hl_gc_check_track() {
+	int i;
+	for(i=0;i<tracked_count;i++) {
+		hl_track *tr = tracked + i;
+		if( !tr->value ) continue;
+		if( !hl_is_gc_ptr((void*)hide_ptr(tr->obj)) /*GC'ed!*/ ) {
+			hl_is_gc_ptr((void*)hide_ptr(tr->obj));
+			tr->value = NULL;
+		} else {
+			int_val v = hide_ptr(*tr->value);
+			if( v == tr->old_value ) continue;
+			tr->old_value = v;
+		}
+		hl_dyn_call(tr->callb,NULL,0);
+	}
+}
+
+HL_API bool hl_gc_track( vdynamic *dobj, int fid, vclosure *callb ) {
+	void *obj = NULL, **value = NULL;
+	hl_track *tr;
+	if( dobj == NULL )
+		return false;
+	switch( dobj->t->kind ) {
+	case HENUM:
+		{
+			int cid = *(int*)dobj->v.ptr;
+			hl_enum_construct *c = dobj->t->tenum->constructs + cid;
+			if( fid >= c->nparams ) return false;
+			obj = (void*)dobj->v.ptr;
+			value = (void**)((char*)obj + c->offsets[fid]);
+		}
+		break;
+	default:
+		return false;
+	}
+	if( value == NULL )
+		return false;
+
+	if( !hl_is_gc_ptr(obj) )
+		return false;
+
+	if( tracked_count == tracked_max ) {
+		hl_track *newt;
+		tracked_max = tracked_max ? tracked_max << 1 : 16;
+		newt = hl_gc_alloc_raw(sizeof(hl_track)*tracked_max);
+		if( tracked ) {
+			memcpy(newt,tracked,tracked_count*sizeof(hl_track));
+		} else {
+			hl_add_root(&tracked);
+		}
+		tracked = newt;
+	}
+	tr = tracked + tracked_count++;
+	tr->callb = callb;
+	tr->value = value;
+	tr->old_value = hide_ptr(*value);
+	tr->obj = hide_ptr(obj);
+	return true;
+}
+
+HL_API bool hl_gc_untrack( vdynamic *obj ) {
+	int_val oval;
+	int i;
+	if( obj == NULL )
+		return false;
+	if( obj->t->kind == HENUM )
+		obj = (vdynamic*)obj->v.ptr;
+	oval = hide_ptr(obj);
+	for(i=0;i<tracked_count;i++) {
+		hl_track *tr = tracked + i;
+		if( tr->obj == oval ) {
+			tracked_count--;
+			memmove(tracked + i, tracked + i + 1, (tracked_count - i) * sizeof(hl_track));
+			memset(tracked + tracked_count, 0, sizeof(hl_track));
+			return true;
+		}
+	}
+	return false;
+}
+
+HL_API void hl_gc_untrack_all() {
+	if( tracked_count == 0 ) return;
+	memset(tracked, 0, sizeof(hl_track) * tracked_count);
+	tracked_count = 0;
+}
+
+HL_API int hl_gc_track_count() {
+	return tracked_count;
+}
+
+DEFINE_PRIM(_BOOL, gc_track, _DYN _I32 _FUN(_VOID, _NO_ARG));
+DEFINE_PRIM(_BOOL, gc_untrack, _DYN);
+DEFINE_PRIM(_VOID, gc_untrack_all, _NO_ARG);
+DEFINE_PRIM(_I32, gc_track_count, _NO_ARG);
+