Finish basic implementation of garbage collection.

This commit is contained in:
Danila Fedorin 2018-08-11 20:01:43 -07:00
parent f4ecb82c46
commit 76ea606099
5 changed files with 68 additions and 16 deletions

View File

@ -33,6 +33,10 @@ void libab_gc_list_init(libab_gc_list* list);
* @param data the data to pass to the visitor. * @param data the data to pass to the visitor.
*/ */
void libab_gc_visit_children(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data); void libab_gc_visit_children(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
/**
* Applies the given visitor function to this reference.
*/
void libab_gc_visit(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
/** /**
* Adds the given reference to the given garbage collection list, * Adds the given reference to the given garbage collection list,
* and specifies a function used to reach its children. * and specifies a function used to reach its children.

View File

@ -0,0 +1,8 @@
#ifndef LIBABACUS_REFCOUNT_INTERNAL_H
#define LIBABACUS_REFCOUNT_INTERNAL_H
#include "refcount.h"
void libab_ref_count_changed(libab_ref_count* count);
#endif

View File

@ -1,7 +1,9 @@
#include "gc.h" #include "gc.h"
#include "refcount.h" #include "refcount.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <memory.h> #include <memory.h>
#include "refcount_internal.h"
void libab_gc_list_init(libab_gc_list* list) { void libab_gc_list_init(libab_gc_list* list) {
memset(&list->head_sentinel, 0, sizeof(list->head_sentinel)); memset(&list->head_sentinel, 0, sizeof(list->head_sentinel));
@ -17,6 +19,12 @@ void libab_gc_visit_children(libab_ref* ref, libab_visitor_function_ptr func, vo
if(!ref->null) _gc_count_visit_children(ref->count, func, data); if(!ref->null) _gc_count_visit_children(ref->count, func, data);
} }
void libab_gc_visit(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data) {
if(!ref->null) {
visitor(ref->count, data);
}
}
void _libab_gc_list_append(libab_gc_list* list, void _libab_gc_list_append(libab_gc_list* list,
libab_ref_count* node) { libab_ref_count* node) {
libab_ref_count* before; libab_ref_count* before;
@ -36,11 +44,11 @@ void libab_gc_add(libab_ref* ref,
} }
void _gc_decrement(libab_ref_count* count, void* data) { void _gc_decrement(libab_ref_count* count, void* data) {
count->gc--; if(count->visit_children) count->gc--;
} }
void _gc_save(libab_ref_count* count, void* data) { void _gc_save(libab_ref_count* count, void* data) {
libab_gc_list* list = data; libab_gc_list* list = data;
if(count->visit_children && count->gc != -1) { if(count->visit_children && count->gc >= 0) {
count->gc = -1; count->gc = -1;
_libab_gc_list_append(list, count); _libab_gc_list_append(list, count);
_gc_count_visit_children(count, _gc_save, data); _gc_count_visit_children(count, _gc_save, data);
@ -50,31 +58,45 @@ void _gc_save(libab_ref_count* count, void* data) {
void libab_gc_run(libab_gc_list* list) { void libab_gc_run(libab_gc_list* list) {
libab_gc_list safe; libab_gc_list safe;
libab_ref_count* head; libab_ref_count* head;
size_t count = 0;
#define ITERATE(CODE) head = list->head_sentinel.next; \ #define ITERATE(CODE) head = list->head_sentinel.next; \
while(head != &list->tail_sentinel) { \ while(head != &list->tail_sentinel) { \
libab_ref_count* node = head; \
CODE;\ CODE;\
head = head->next; \ head = head->next; \
} }
libab_gc_list_init(&safe); libab_gc_list_init(&safe);
ITERATE(head->gc = head->weak); ITERATE(node->gc = node->weak);
ITERATE(_gc_count_visit_children(head, _gc_decrement, NULL)); ITERATE(_gc_count_visit_children(node, _gc_decrement, NULL));
ITERATE(printf("%d outside references\n", head->gc));
ITERATE(_gc_count_visit_children(head, _gc_save, &safe));
ITERATE(count++);
printf("Can free %d\n", count); head = list->head_sentinel.next;
while(head != &list->tail_sentinel) {
if(head->gc > 0) {
_gc_save(head, &safe);
head = &list->head_sentinel;
}
head = head->next;
}
ITERATE(
node->weak = -1;
node->strong = -1;
if(node->free_func) node->free_func(node->data);
);
while ((head = list->head_sentinel.next) != &list->tail_sentinel) {
head->prev->next = head->next;
head->next->prev = head->prev;
free(head);
}
if(safe.head_sentinel.next != &safe.tail_sentinel) { if(safe.head_sentinel.next != &safe.tail_sentinel) {
printf("Safe isn't empty!\n");
list->head_sentinel.next = safe.head_sentinel.next; list->head_sentinel.next = safe.head_sentinel.next;
list->head_sentinel.next->prev = &list->head_sentinel; list->head_sentinel.next->prev = &list->head_sentinel;
list->tail_sentinel.prev = safe.tail_sentinel.prev; list->tail_sentinel.prev = safe.tail_sentinel.prev;
list->tail_sentinel.prev->next = &list->tail_sentinel; list->tail_sentinel.prev->next = &list->tail_sentinel;
} else { } else {
printf("Safe is empty!\n");
list->head_sentinel.next = &list->tail_sentinel; list->head_sentinel.next = &list->tail_sentinel;
list->tail_sentinel.prev = &list->head_sentinel; list->tail_sentinel.prev = &list->head_sentinel;
} }

16
src/refcount_internal.c Normal file
View File

@ -0,0 +1,16 @@
#include "refcount_internal.h"
#include <stdlib.h>
void libab_ref_count_changed(libab_ref_count* count) {
if (count->strong == 0) {
count->strong--;
if (count->free_func) {
count->free_func(count->data);
}
}
if (count->weak == 0) {
if(count->prev) count->prev->next = count->next;
if(count->next) count->next->prev = count->prev;
free(count);
}
}

View File

@ -189,13 +189,14 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
void _gc_visit_table_entry(libab_table_entry* entry, libab_visitor_function_ptr visitor, void* data) { void _gc_visit_table_entry(libab_table_entry* entry, libab_visitor_function_ptr visitor, void* data) {
if (entry->variant == ENTRY_VALUE) { if (entry->variant == ENTRY_VALUE) {
libab_gc_visit_children(&entry->data_u.value, visitor, data); libab_gc_visit(&entry->data_u.value, visitor, data);
} }
} }
void _gc_visit_table_trie(libab_trie_node* parent, libab_visitor_function_ptr visitor, void* data) { void _gc_visit_table_trie(libab_trie_node* parent, libab_visitor_function_ptr visitor, void* data) {
ll_node* head = parent->values.head; ll_node* head;
if(parent == NULL) return; if(parent == NULL) return;
head = parent->values.head;
_gc_visit_table_trie(parent->child, visitor, data); _gc_visit_table_trie(parent->child, visitor, data);
_gc_visit_table_trie(parent->next, visitor, data); _gc_visit_table_trie(parent->next, visitor, data);
while(head != NULL) { while(head != NULL) {
@ -206,7 +207,8 @@ void _gc_visit_table_trie(libab_trie_node* parent, libab_visitor_function_ptr vi
void _gc_visit_table_children(void* parent, libab_visitor_function_ptr visitor, void* data) { void _gc_visit_table_children(void* parent, libab_visitor_function_ptr visitor, void* data) {
libab_table* table = parent; libab_table* table = parent;
libab_gc_visit_children(&table->parent, visitor, data); libab_gc_visit(&table->parent, visitor, data);
_gc_visit_table_trie(table->trie.head, visitor, data);
} }
libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent) { libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent) {
@ -234,7 +236,7 @@ libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent) {
void _gc_visit_value_children(void* val, libab_visitor_function_ptr visitor, void* data) { void _gc_visit_value_children(void* val, libab_visitor_function_ptr visitor, void* data) {
libab_value* value = val; libab_value* value = val;
libab_gc_visit_children(&value->data, visitor, data); libab_gc_visit(&value->data, visitor, data);
} }
libab_result libab_create_value_ref(libab* ab, libab_ref* into, libab_result libab_create_value_ref(libab* ab, libab_ref* into,
@ -290,7 +292,7 @@ libab_result libab_create_value_raw(libab* ab, libab_ref* into,
void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) { void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) {
libab_function* func = function; libab_function* func = function;
libab_gc_visit_children(&func->scope, visitor, data); libab_gc_visit(&func->scope, visitor, data);
} }
libab_result libab_create_function_internal(libab* ab, libab_ref* into, libab_result libab_create_function_internal(libab* ab, libab_ref* into,