Browse Source

Improved garbage collector for bind methods.

Marco Bambini 7 years ago
parent
commit
0e47f8f3df
4 changed files with 29 additions and 26 deletions
  1. 7 6
      src/runtime/gravity_core.c
  2. 3 3
      src/runtime/gravity_vm.c
  3. 16 14
      src/shared/gravity_value.c
  4. 3 3
      src/shared/gravity_value.h

+ 7 - 6
src/runtime/gravity_core.c

@@ -720,15 +720,16 @@ static bool object_bind (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 	if (!gravity_class_is_anon(c)) {
 		// no super anonymous class found so create a new one, set its super as c, and add it to the hierarchy
 		char *name = gravity_vm_anonymous(vm);
-		gravity_class_t *anon = gravity_class_new_pair(NULL, name, c, 0, 0);
-		gravity_class_t *anon_meta = gravity_class_get_meta(anon);
+        
+        // cg needs to be disabled here because it could run inside class allocation triggering a free for the meta class
+        gravity_gc_setenabled(vm, false);
+		gravity_class_t *anon = gravity_class_new_pair(vm, name, c, 0, 0);
+        gravity_gc_setenabled(vm, true);
 		object->objclass = anon;
 		c = anon;
 
-		// store anonymous class (and its meta) into VM special GC stack
-		// manually retains anonymous class that will retain its bound functions
-		gravity_gc_push(vm, (gravity_object_t *)anon);
-		gravity_gc_push(vm, (gravity_object_t *)anon_meta);
+		// store anonymous class (and its meta) into VM context
+        gravity_vm_setvalue(vm, name, VALUE_FROM_OBJECT(anon));
 	}
 
 	// add closure to anonymous class

+ 3 - 3
src/runtime/gravity_vm.c

@@ -1892,7 +1892,7 @@ void gravity_gray_object (gravity_vm *vm, gravity_object_t *obj) {
 	// avoid recursion if object has already been visited
 	if (obj->gc.isdark) return;
 
-	DEBUG_GC("GRAY %s", gravity_object_debug(obj));
+	DEBUG_GC("GRAY %s", gravity_object_debug(obj, false));
 
 	// object has been reached
 	obj->gc.isdark = true;
@@ -1969,7 +1969,7 @@ void gravity_vm_initmodule (gravity_vm *vm, gravity_function_t *f) {
 }
 
 static void gravity_gc_transfer_object (gravity_vm *vm, gravity_object_t *obj) {
-	DEBUG_GC("GC TRANSFER %s", gravity_object_debug(obj));
+	DEBUG_GC("GC TRANSFER %s", gravity_object_debug(obj, false));
 	++vm->gccount;
 	obj->gc.next = vm->gchead;
 	vm->gchead = obj;
@@ -1982,7 +1982,7 @@ static void gravity_gc_transfer (gravity_vm *vm, gravity_object_t *obj) {
 		gravity_object_t **ptr = &vm->gchead;
 		while (*ptr) {
 			if (obj == *ptr) {
-				printf("Object %s already GC!\n", gravity_object_debug(obj));
+				printf("Object %s already GC!\n", gravity_object_debug(obj, false));
 				assert(0);
 			}
 			ptr = &(*ptr)->gc.next;

+ 16 - 14
src/shared/gravity_value.c

@@ -375,7 +375,7 @@ abort_load:
 static void gravity_class_free_internal (gravity_vm *vm, gravity_class_t *c, bool skip_base) {
 	if (skip_base && (gravity_iscore_class(c) || gravity_isopt_class(c))) return;
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)c));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)c, true));
 
 	// check if bridged data needs to be freed too
 	if (c->xdata && vm) {
@@ -952,7 +952,7 @@ abort_load:
 void gravity_function_free (gravity_vm *vm, gravity_function_t *f) {
 	if (!f) return;
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)f));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)f, true));
 
 	// check if bridged data needs to be freed too
 	if (f->xdata && vm) {
@@ -1032,7 +1032,7 @@ gravity_closure_t *gravity_closure_new (gravity_vm *vm, gravity_function_t *f) {
 void gravity_closure_free (gravity_vm *vm, gravity_closure_t *closure) {
 	#pragma unused(vm)
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)closure));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)closure, true));
 
 	if (closure->upvalue) mem_free(closure->upvalue);
 	mem_free(closure);
@@ -1093,7 +1093,7 @@ void gravity_upvalue_blacken (gravity_vm *vm, gravity_upvalue_t *upvalue) {
 void gravity_upvalue_free(gravity_vm *vm, gravity_upvalue_t *upvalue) {
 	#pragma unused(vm)
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)upvalue));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)upvalue, true));
 	mem_free(upvalue);
 }
 
@@ -1134,7 +1134,7 @@ gravity_fiber_t *gravity_fiber_new (gravity_vm *vm, gravity_closure_t *closure,
 void gravity_fiber_free (gravity_vm *vm, gravity_fiber_t *fiber) {
 	#pragma unused(vm)
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)fiber));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)fiber, true));
 	if (fiber->error) mem_free(fiber->error);
 	mem_free(fiber->stack);
 	mem_free(fiber->frames);
@@ -1250,7 +1250,7 @@ gravity_object_t *gravity_object_deserialize (gravity_vm *vm, json_value *entry)
 }
 #undef REPORT_JSON_ERROR
 
-const char *gravity_object_debug (gravity_object_t *obj) {
+const char *gravity_object_debug (gravity_object_t *obj, bool is_free) {
 	if ((!obj) || (!OBJECT_IS_VALID(obj))) return "";
 
 	if (OBJECT_ISA_INT(obj)) return "INT";
@@ -1267,7 +1267,8 @@ const char *gravity_object_debug (gravity_object_t *obj) {
 	}
 
 	if (OBJECT_ISA_CLOSURE(obj)) {
-		const char *name = ((gravity_closure_t*)obj)->f->identifier;
+        // cannot guarantee ptr validity during a free
+        const char *name = (is_free) ? NULL : ((gravity_closure_t*)obj)->f->identifier;
 		if (!name) name = "ANONYMOUS";
 		snprintf(buffer, sizeof(buffer), "CLOSURE %p %s", obj, name);
 		return buffer;
@@ -1286,8 +1287,9 @@ const char *gravity_object_debug (gravity_object_t *obj) {
 	}
 
 	if (OBJECT_ISA_INSTANCE(obj)) {
-		gravity_class_t *c = ((gravity_instance_t*)obj)->objclass;
-		const char *name = (c->identifier) ? c->identifier : "ANONYMOUS";
+        // cannot guarantee ptr validity during a free
+        gravity_class_t *c = (is_free) ? NULL : ((gravity_instance_t*)obj)->objclass;
+		const char *name = (c && c->identifier) ? c->identifier : "ANONYMOUS";
 		snprintf(buffer, sizeof(buffer), "INSTANCE %p OF %s", obj, name);
 		return buffer;
 	}
@@ -1404,7 +1406,7 @@ void gravity_instance_setxdata (gravity_instance_t *i, void *xdata) {
 }
 
 void gravity_instance_free (gravity_vm *vm, gravity_instance_t *i) {
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)i));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)i, true));
 
 	// check if bridged data needs to be freed too
 	if (i->xdata && vm) {
@@ -1810,7 +1812,7 @@ gravity_list_t *gravity_list_from_array (gravity_vm *vm, uint32_t n, gravity_val
 void gravity_list_free (gravity_vm *vm, gravity_list_t *list) {
 	#pragma unused(vm)
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)list));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)list, true));
 	marray_destroy(list->array);
 	mem_free((void *)list);
 }
@@ -1856,7 +1858,7 @@ gravity_map_t *gravity_map_new (gravity_vm *vm, uint32_t n) {
 void gravity_map_free (gravity_vm *vm, gravity_map_t *map) {
 	#pragma unused(vm)
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)map));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)map, true));
 	gravity_hash_free(map->hash);
 	mem_free((void *)map);
 }
@@ -1930,7 +1932,7 @@ gravity_range_t *gravity_range_new (gravity_vm *vm, gravity_int_t from_range, gr
 void gravity_range_free (gravity_vm *vm, gravity_range_t *range) {
 	#pragma unused(vm)
 
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)range));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)range, true));
 	mem_free((void *)range);
 }
 
@@ -1989,7 +1991,7 @@ inline void gravity_string_set (gravity_string_t *obj, char *s, uint32_t len) {
 
 inline void gravity_string_free (gravity_vm *vm, gravity_string_t *value) {
 	#pragma unused(vm)
-	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)value));
+	DEBUG_FREE("FREE %s", gravity_object_debug((gravity_object_t *)value, true));
 	if (value->alloc) mem_free(value->s);
 	mem_free(value);
 }

+ 3 - 3
src/shared/gravity_value.h

@@ -66,8 +66,8 @@
 extern "C" {
 #endif
 
-#define GRAVITY_VERSION						"0.3.9"     // git tag 0.3.8
-#define GRAVITY_VERSION_NUMBER				0x000309    // git push --tags
+#define GRAVITY_VERSION						"0.4.0"     // git tag 0.4.0
+#define GRAVITY_VERSION_NUMBER				0x000400    // git push --tags
 #define GRAVITY_BUILD_DATE					__DATE__
 
 #ifndef GRAVITY_ENABLE_DOUBLE
@@ -490,7 +490,7 @@ GRAVITY_API gravity_object_t	*gravity_object_deserialize (gravity_vm *vm, json_v
 GRAVITY_API void				gravity_object_free (gravity_vm *vm, gravity_object_t *obj);
 GRAVITY_API void				gravity_object_blacken (gravity_vm *vm, gravity_object_t *obj);
 GRAVITY_API uint32_t			gravity_object_size (gravity_vm *vm, gravity_object_t *obj);
-GRAVITY_API const char			*gravity_object_debug (gravity_object_t *obj);
+GRAVITY_API const char			*gravity_object_debug (gravity_object_t *obj, bool is_free);
 
 // MARK: - LIST -
 GRAVITY_API gravity_list_t		*gravity_list_new (gravity_vm *vm, uint32_t n);