Author: Nicolas Truessel <[email protected]>
Branch: quad-color-gc
Changeset: r86636:041e0b606934
Date: 2016-08-27 16:36 +0200
http://bitbucket.org/pypy/pypy/changeset/041e0b606934/

Log:    Update qcgc codebase

diff --git a/rpython/translator/c/src/qcgc/allocator.c 
b/rpython/translator/c/src/qcgc/allocator.c
--- a/rpython/translator/c/src/qcgc/allocator.c
+++ b/rpython/translator/c/src/qcgc/allocator.c
@@ -2,12 +2,14 @@
 
 #include <assert.h>
 #include <stdbool.h>
+#include <stdlib.h>
 #include <string.h>
 
+#include "hugeblocktable.h"
+
 QCGC_STATIC size_t bytes_to_cells(size_t bytes);
 
 QCGC_STATIC void bump_allocator_assign(cell_t *ptr, size_t cells);
-QCGC_STATIC cell_t *bump_allocator_allocate(size_t cells);
 QCGC_STATIC void bump_allocator_advance(size_t cells);
 
 QCGC_STATIC bool is_small(size_t cells);
@@ -15,7 +17,6 @@
 QCGC_STATIC size_t large_index(size_t cells);
 QCGC_STATIC size_t small_index_to_cells(size_t index);
 
-QCGC_STATIC cell_t *fit_allocator_allocate(size_t cells);
 QCGC_STATIC cell_t *fit_allocator_small_first_fit(size_t index, size_t cells);
 QCGC_STATIC cell_t *fit_allocator_large_fit(size_t index, size_t cells);
 QCGC_STATIC cell_t *fit_allocator_large_first_fit(size_t index, size_t cells);
@@ -61,28 +62,6 @@
        free(qcgc_allocator_state.arenas);
 }
 
-cell_t *qcgc_allocator_allocate(size_t bytes) {
-       size_t size_in_cells = bytes_to_cells(bytes);
-#if CHECKED
-       assert(size_in_cells > 0);
-       assert(size_in_cells <= QCGC_ARENA_CELLS_COUNT - 
QCGC_ARENA_FIRST_CELL_INDEX);
-#endif
-       cell_t *result;
-
-       // TODO: Implement switch for bump/fit allocator
-       if (true) {
-               result = bump_allocator_allocate(size_in_cells);
-       } else {
-               result = fit_allocator_allocate(size_in_cells);
-       }
-
-       qcgc_arena_mark_allocated(result, size_in_cells);
-#if QCGC_INIT_ZERO
-       memset(result, 0, bytes);
-#endif
-       return result;
-}
-
 void qcgc_fit_allocator_add(cell_t *ptr, size_t cells) {
        if (cells > 0) {
                if (is_small(cells)) {
@@ -111,36 +90,75 @@
        qcgc_allocator_state.bump_state.remaining_cells -= cells;
 }
 
-QCGC_STATIC cell_t *bump_allocator_allocate(size_t cells) {
+/*******************************************************************************
+ * Allocators                                                                  
*
+ 
******************************************************************************/
+
+object_t *qcgc_bump_allocate(size_t bytes) {
+       size_t cells = bytes_to_cells(bytes);
        if (cells > qcgc_allocator_state.bump_state.remaining_cells) {
                // Grab a new arena
+               // FIXME: Add remaining memory to fit allocator
                arena_t *arena = qcgc_arena_create();
                
bump_allocator_assign(&(arena->cells[QCGC_ARENA_FIRST_CELL_INDEX]),
                                QCGC_ARENA_CELLS_COUNT - 
QCGC_ARENA_FIRST_CELL_INDEX);
                qcgc_allocator_state.arenas =
                        qcgc_arena_bag_add(qcgc_allocator_state.arenas, arena);
        }
-       cell_t *result = qcgc_allocator_state.bump_state.bump_ptr;
+       cell_t *mem = qcgc_allocator_state.bump_state.bump_ptr;
        bump_allocator_advance(cells);
+
+       qcgc_arena_mark_allocated(mem, cells);
+       object_t *result = (object_t *) mem;
+
+#if QCGC_INIT_ZERO
+       memset(result, 0, cells * sizeof(cell_t));
+#endif
+
+       result->flags |= QCGC_GRAY_FLAG;
        return result;
 }
 
-QCGC_STATIC cell_t *fit_allocator_allocate(size_t cells) {
-       cell_t *result;
+object_t *qcgc_fit_allocate(size_t bytes) {
+       size_t cells = bytes_to_cells(bytes);
+       cell_t *mem;
 
        if (is_small(cells)) {
                size_t index = small_index(cells);
-               result = fit_allocator_small_first_fit(index, cells);
+               mem = fit_allocator_small_first_fit(index, cells);
        } else {
                size_t index = large_index(cells);
-               result = fit_allocator_large_fit(index, cells);
+               mem = fit_allocator_large_fit(index, cells);
        }
 
-       if (result == NULL) {
-               // No valid block found
-               result = bump_allocator_allocate(cells);
+       if (mem == NULL) {
+               return NULL;
        }
 
+       qcgc_arena_mark_allocated(mem, cells);
+       object_t *result = (object_t *) mem;
+
+#if QCGC_INIT_ZERO
+       memset(result, 0, cells * sizeof(cell_t));
+#endif
+
+       result->flags |= QCGC_GRAY_FLAG;
+       return result;
+}
+
+/**
+ * Constraints:
+ * - Zero initialized
+ * - Aligned to arena size
+ * - Multiple of arena size
+ * - No header, metadata stored in hash-map
+ */
+object_t *qcgc_large_allocate(size_t bytes) {
+       object_t *result = aligned_alloc(QCGC_ARENA_SIZE, bytes);
+#if QCGC_INIT_ZERO
+       memset(result, 0, bytes);
+#endif
+       qcgc_hbtable_insert(result);
        return result;
 }
 
diff --git a/rpython/translator/c/src/qcgc/allocator.h 
b/rpython/translator/c/src/qcgc/allocator.h
--- a/rpython/translator/c/src/qcgc/allocator.h
+++ b/rpython/translator/c/src/qcgc/allocator.h
@@ -57,13 +57,32 @@
 void qcgc_allocator_destroy(void);
 
 /**
- * Allocate new memory region
+ * Allocate new memory region using fit allocator
+ *
+ * @param      bytes   Desired size of the memory region in bytes
+ * @return     Pointer to memory large enough to hold size bytes, NULL in case 
of
+ *                     errors or if there is no block sufficently large block, 
already zero
+ *                     initialized if QCGC_INIT_ZERO is set
+ */
+object_t *qcgc_fit_allocate(size_t bytes);
+
+/**
+ * Allocate new memory region using bump allocator
  *
  * @param      bytes   Desired size of the memory region in bytes
  * @return     Pointer to memory large enough to hold size bytes, NULL in case 
of
  *                     errors, already zero initialized if QCGC_INIT_ZERO is 
set
  */
-cell_t *qcgc_allocator_allocate(size_t bytes);
+object_t *qcgc_bump_allocate(size_t bytes);
+
+/**
+ * Allocate new memory region using huge block allocator
+ *
+ * @param      bytes   Desired size of the memory region in bytes
+ * @return     Pointer to memory large enough to hold size bytes, NULL in case 
of
+ *                     errors, already zero initialized if QCGC_INIT_ZERO is 
set
+ */
+object_t *qcgc_large_allocate(size_t bytes);
 
 
 /**
diff --git a/rpython/translator/c/src/qcgc/bag.c 
b/rpython/translator/c/src/qcgc/bag.c
--- a/rpython/translator/c/src/qcgc/bag.c
+++ b/rpython/translator/c/src/qcgc/bag.c
@@ -5,3 +5,4 @@
 DEFINE_BAG(arena_bag, arena_t *);
 DEFINE_BAG(linear_free_list, cell_t *);
 DEFINE_BAG(exp_free_list, struct exp_free_list_item_s);
+DEFINE_BAG(hbbucket, struct hbtable_entry_s);
diff --git a/rpython/translator/c/src/qcgc/bag.h 
b/rpython/translator/c/src/qcgc/bag.h
--- a/rpython/translator/c/src/qcgc/bag.h
+++ b/rpython/translator/c/src/qcgc/bag.h
@@ -14,13 +14,23 @@
        type items[];                                                           
                                                        \
 } name##_t;                                                                    
                                                                \
                                                                                
                                                                        \
+__attribute__ ((warn_unused_result))                                           
                                \
 name##_t *qcgc_##name##_create(size_t size);                                   
                        \
+                                                                               
                                                                        \
+__attribute__ ((warn_unused_result))                                           
                                \
 name##_t *qcgc_##name##_add(name##_t *self, type item);                        
                        \
+                                                                               
                                                                        \
+__attribute__ ((warn_unused_result))                                           
                                \
 name##_t *qcgc_##name##_remove_index(name##_t *self, size_t index);
 
 #define DEFINE_BAG(name, type)                                                 
                                        \
+                                                                               
                                                                        \
 QCGC_STATIC size_t name##_size(size_t size);                                   
                        \
+                                                                               
                                                                        \
+__attribute__ ((warn_unused_result))                                           
                                \
 QCGC_STATIC name##_t *name##_grow(name##_t *self);                             
                        \
+                                                                               
                                                                        \
+__attribute__ ((warn_unused_result))                                           
                                \
 QCGC_STATIC name##_t *name##_shrink(name##_t *self);                           
                \
                                                                                
                                                                        \
 name##_t *qcgc_##name##_create(size_t size) {                                  
                        \
@@ -77,6 +87,12 @@
        size_t size;
 };
 
+struct hbtable_entry_s {
+       object_t *object;
+       bool mark_flag;
+};
+
 DECLARE_BAG(arena_bag, arena_t *);
 DECLARE_BAG(linear_free_list, cell_t *);
 DECLARE_BAG(exp_free_list, struct exp_free_list_item_s);
+DECLARE_BAG(hbbucket, struct hbtable_entry_s);
diff --git a/rpython/translator/c/src/qcgc/gc_state.h 
b/rpython/translator/c/src/qcgc/gc_state.h
--- a/rpython/translator/c/src/qcgc/gc_state.h
+++ b/rpython/translator/c/src/qcgc/gc_state.h
@@ -25,6 +25,7 @@
 struct qcgc_state {
        shadow_stack_t *shadow_stack;
        shadow_stack_t *prebuilt_objects;
+       gray_stack_t *gp_gray_stack;
        size_t gray_stack_size;
        gc_phase_t phase;
 } qcgc_state;
diff --git a/rpython/translator/c/src/qcgc/gray_stack.h 
b/rpython/translator/c/src/qcgc/gray_stack.h
--- a/rpython/translator/c/src/qcgc/gray_stack.h
+++ b/rpython/translator/c/src/qcgc/gray_stack.h
@@ -12,8 +12,13 @@
        object_t *items[];
 } gray_stack_t;
 
+__attribute__ ((warn_unused_result))
 gray_stack_t *qcgc_gray_stack_create(size_t size);
 
+__attribute__ ((warn_unused_result))
 gray_stack_t *qcgc_gray_stack_push(gray_stack_t *stack, object_t *item);
+
 object_t *qcgc_gray_stack_top(gray_stack_t *stack);
+
+__attribute__ ((warn_unused_result))
 gray_stack_t *qcgc_gray_stack_pop(gray_stack_t *stack);
diff --git a/rpython/translator/c/src/qcgc/hugeblocktable.c 
b/rpython/translator/c/src/qcgc/hugeblocktable.c
new file mode 100644
--- /dev/null
+++ b/rpython/translator/c/src/qcgc/hugeblocktable.c
@@ -0,0 +1,80 @@
+#include "hugeblocktable.h"
+
+#include <assert.h>
+
+#include "gc_state.h"
+
+QCGC_STATIC size_t bucket(object_t *object);
+
+void qcgc_hbtable_initialize(void) {
+       qcgc_hbtable.mark_flag_ref = false;
+       for (size_t i = 0; i < QCGC_HBTABLE_BUCKETS; i++) {
+               qcgc_hbtable.bucket[i] = qcgc_hbbucket_create(4);
+       }
+}
+
+void qcgc_hbtable_destroy(void) {
+       for (size_t i = 0; i < QCGC_HBTABLE_BUCKETS; i++) {
+               free(qcgc_hbtable.bucket[i]);
+       }
+}
+
+void qcgc_hbtable_insert(object_t *object) {
+       size_t i = bucket(object);
+       qcgc_hbtable.bucket[i] = qcgc_hbbucket_add(qcgc_hbtable.bucket[i],
+                       (struct hbtable_entry_s) {
+                               .object = object,
+                               .mark_flag = !qcgc_hbtable.mark_flag_ref});
+}
+
+bool qcgc_hbtable_mark(object_t *object) {
+       hbbucket_t *b = qcgc_hbtable.bucket[bucket(object)];
+       size_t count = b->count;
+       for (size_t i = 0; i < count; i++) {
+               if (b->items[i].object == object) {
+                       if (b->items[i].mark_flag != 
qcgc_hbtable.mark_flag_ref) {
+                               b->items[i].mark_flag = 
qcgc_hbtable.mark_flag_ref;
+                               return true;
+                       }
+                       return false;
+               }
+       }
+#if CHECKED
+       assert(false);
+#endif
+       return false;
+}
+
+bool qcgc_hbtable_is_marked(object_t *object) {
+       hbbucket_t *b = qcgc_hbtable.bucket[bucket(object)];
+       size_t count = b->count;
+       for (size_t i = 0; i < count; i++) {
+               if (b->items[i].object == object) {
+                       return b->items[i].mark_flag == 
qcgc_hbtable.mark_flag_ref;
+               }
+       }
+       return false;
+}
+
+void qcgc_hbtable_sweep(void) {
+       for (size_t i = 0; i < QCGC_HBTABLE_BUCKETS; i++) {
+               hbbucket_t *b = qcgc_hbtable.bucket[i];
+               size_t j = 0;
+               while(j < b->count) {
+                       if (b->items[j].mark_flag != 
qcgc_hbtable.mark_flag_ref) {
+                               // White object
+                               free(b->items[j].object);
+                               b = qcgc_hbbucket_remove_index(b, j);
+                       } else {
+                               // Black object
+                               j++;
+                       }
+               }
+               qcgc_hbtable.bucket[i] = b;
+       }
+       qcgc_hbtable.mark_flag_ref = !qcgc_hbtable.mark_flag_ref;
+}
+
+QCGC_STATIC size_t bucket(object_t *object) {
+       return ((uintptr_t) object >> (QCGC_ARENA_SIZE_EXP)) % 
QCGC_HBTABLE_BUCKETS;
+}
diff --git a/rpython/translator/c/src/qcgc/hugeblocktable.h 
b/rpython/translator/c/src/qcgc/hugeblocktable.h
new file mode 100644
--- /dev/null
+++ b/rpython/translator/c/src/qcgc/hugeblocktable.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "config.h"
+
+#include <stdbool.h>
+
+#include "bag.h"
+#include "object.h"
+#include "gray_stack.h"
+
+// Choosing a prime number, hoping for good results
+#define QCGC_HBTABLE_BUCKETS 61
+
+struct hbtable_s {
+       bool mark_flag_ref;
+       hbbucket_t *bucket[QCGC_HBTABLE_BUCKETS];
+} qcgc_hbtable;
+
+void qcgc_hbtable_initialize(void);
+void qcgc_hbtable_destroy(void);
+void qcgc_hbtable_insert(object_t *object);
+bool qcgc_hbtable_mark(object_t *object);
+bool qcgc_hbtable_is_marked(object_t *object);
+void qcgc_hbtable_sweep(void);
diff --git a/rpython/translator/c/src/qcgc/mark_list.c 
b/rpython/translator/c/src/qcgc/mark_list.c
deleted file mode 100644
--- a/rpython/translator/c/src/qcgc/mark_list.c
+++ /dev/null
@@ -1,180 +0,0 @@
-#include "mark_list.h"
-
-#include <assert.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-QCGC_STATIC mark_list_t *qcgc_mark_list_grow(mark_list_t *list);
-QCGC_STATIC void qcgc_mark_list_check_invariant(mark_list_t *list);
-
-mark_list_t *qcgc_mark_list_create(size_t initial_size) {
-       size_t length = (initial_size + QCGC_MARK_LIST_SEGMENT_SIZE - 1) / 
QCGC_MARK_LIST_SEGMENT_SIZE;
-       length += (size_t) length == 0;
-       mark_list_t *result = (mark_list_t *)
-               malloc(sizeof(mark_list_t) + length * sizeof(object_t **));
-       result->head = 0;
-       result->tail = 0;
-       result->length = length;
-       result->insert_index = 0;
-       result->count = 0;
-       result->segments[result->head] = (object_t **)
-               calloc(QCGC_MARK_LIST_SEGMENT_SIZE, sizeof(object_t *));
-#if CHECKED
-       qcgc_mark_list_check_invariant(result);
-#endif
-       return result;
-}
-
-void qcgc_mark_list_destroy(mark_list_t *list) {
-#if CHECKED
-       qcgc_mark_list_check_invariant(list);
-#endif
-
-       size_t i = list->head;
-       while (i != list->tail) {
-               free(list->segments[i]);
-               i = (i + 1) % list->length;
-       }
-       free(list->segments[list->tail]);
-       free(list);
-}
-
-mark_list_t *qcgc_mark_list_push(mark_list_t *list, object_t *object) {
-#if CHECKED
-       assert(list != NULL);
-       assert(object != NULL);
-
-       qcgc_mark_list_check_invariant(list);
-       size_t old_count = list->count;
-#endif
-       if (list->insert_index >= QCGC_MARK_LIST_SEGMENT_SIZE) {
-               if ((list->tail + 1) % list->length == list->head) {
-                       list = qcgc_mark_list_grow(list);
-               }
-               list->insert_index = 0;
-               list->tail = (list->tail + 1) % list->length;
-               list->segments[list->tail] = (object_t **)
-                       calloc(QCGC_MARK_LIST_SEGMENT_SIZE, sizeof(object_t *));
-       }
-       list->segments[list->tail][list->insert_index] = object;
-       list->insert_index++;
-       list->count++;
-#if CHECKED
-       assert(list->count == old_count + 1);
-       assert(list->segments[list->tail][list->insert_index - 1] == object);
-       qcgc_mark_list_check_invariant(list);
-#endif
-       return list;
-}
-
-mark_list_t *qcgc_mark_list_push_all(mark_list_t *list,
-               object_t **objects, size_t count) {
-#if CHECKED
-       assert(list != NULL);
-       assert(objects != NULL);
-
-       qcgc_mark_list_check_invariant(list);
-
-       size_t old_count = list->count;
-       for (size_t i = 0; i < count; i++) {
-               assert(objects[i] != NULL);
-       }
-#endif
-       // FIXME: Optimize or remove
-       for (size_t i = 0; i < count; i++) {
-               list = qcgc_mark_list_push(list, objects[i]);
-       }
-#if CHECKED
-       assert(list->count == old_count + count);
-       qcgc_mark_list_check_invariant(list);
-#endif
-       return list;
-}
-
-object_t **qcgc_mark_list_get_head_segment(mark_list_t *list) {
-#if CHECKED
-       assert(list != NULL);
-       assert(list->segments[list->head] != NULL);
-       qcgc_mark_list_check_invariant(list);
-#endif
-       return list->segments[list->head];
-}
-
-mark_list_t *qcgc_mark_list_drop_head_segment(mark_list_t *list) {
-#if CHECKED
-       assert(list != NULL);
-       size_t old_head = list->head;
-       size_t old_tail = list->tail;
-       qcgc_mark_list_check_invariant(list);
-#endif
-       if (list->head != list->tail) {
-               free(list->segments[list->head]);
-               list->segments[list->head] = NULL;
-               list->head = (list->head + 1) % list->length;
-               list->count -= QCGC_MARK_LIST_SEGMENT_SIZE;
-       } else {
-               memset(list->segments[list->head], 0,
-                               sizeof(object_t *) * 
QCGC_MARK_LIST_SEGMENT_SIZE);
-               list->insert_index = 0;
-               list->count = 0;
-       }
-#if CHECKED
-       assert(old_tail == list->tail);
-       if (old_head == old_tail) {
-               assert(old_head == list->head);
-       } else {
-               assert((old_head + 1) % list->length == list->head);
-       }
-       qcgc_mark_list_check_invariant(list);
-#endif
-       return list;
-}
-
-QCGC_STATIC mark_list_t *qcgc_mark_list_grow(mark_list_t *list) {
-#if CHECKED
-       assert(list != NULL);
-       size_t old_length = list->length;
-       size_t old_tail = list->tail;
-       qcgc_mark_list_check_invariant(list);
-#endif
-       mark_list_t *new_list = (mark_list_t *) realloc(list,
-                       sizeof(mark_list_t) + 2 * list->length * 
sizeof(object_t **));
-       if (new_list->tail < new_list->head) {
-               memcpy(new_list->segments + new_list->length,
-                               new_list->segments, (new_list->tail + 1) * 
sizeof(object_t **));
-               new_list->tail = new_list->length + new_list->tail;
-       }
-       new_list->length = 2 * new_list->length;
-#if CHECKED
-       assert(new_list->length == 2 * old_length);
-       if (old_tail < new_list->head) {
-               assert(new_list->tail == old_tail + old_length);
-               for (size_t i = 0; i < old_tail; i++) {
-                       assert(new_list->segments[i] == new_list->segments[i + 
old_length]);
-               }
-       } else {
-               assert(new_list->tail == old_tail);
-       }
-       qcgc_mark_list_check_invariant(new_list);
-#endif
-       return new_list;
-}
-
-QCGC_STATIC void qcgc_mark_list_check_invariant(mark_list_t *list) {
-       assert(list->head < list->length);
-       assert(list->tail < list->length);
-       assert(list->count == (list->tail - list->head + list->length) % 
list->length * QCGC_MARK_LIST_SEGMENT_SIZE + list->insert_index);
-       for (size_t i = 0; i < list->length; i++) {
-               if ((list->head <= i && i <= list->tail) || (list->tail < 
list->head &&
-                               (i <= list->tail || i >= list->head))) {
-                       for (size_t j = 0; j < QCGC_MARK_LIST_SEGMENT_SIZE; 
j++) {
-                               if (i != list->tail || j < list->insert_index) {
-                                       assert(list->segments[i][j] != NULL);
-                               } else {
-                                       assert(list->segments[i][j] == NULL);
-                               }
-                       }
-               }
-       }
-}
diff --git a/rpython/translator/c/src/qcgc/mark_list.h 
b/rpython/translator/c/src/qcgc/mark_list.h
deleted file mode 100644
--- a/rpython/translator/c/src/qcgc/mark_list.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @file       mark_list.h
- *
- * Object list for marking step
- */
-
-#pragma once
-
-#include "config.h"
-
-#include <stddef.h>
-
-#include "object.h"
-
-/**
- * Mark list - circular buffer.
- */
-typedef struct mark_list_s {
-       size_t head;
-       size_t tail;
-       size_t length;
-       size_t count;
-       size_t insert_index;
-       object_t **segments[];
-} mark_list_t;
-
-mark_list_t *qcgc_mark_list_create(size_t initial_size);
-void qcgc_mark_list_destroy(mark_list_t *list);
-
-mark_list_t *qcgc_mark_list_push(mark_list_t *list, object_t *object);
-mark_list_t *qcgc_mark_list_push_all(mark_list_t *list,
-               object_t **objects, size_t count);
-
-object_t **qcgc_mark_list_get_head_segment(mark_list_t *list);
-mark_list_t *qcgc_mark_list_drop_head_segment(mark_list_t *list);
diff --git a/rpython/translator/c/src/qcgc/object.h 
b/rpython/translator/c/src/qcgc/object.h
--- a/rpython/translator/c/src/qcgc/object.h
+++ b/rpython/translator/c/src/qcgc/object.h
@@ -4,8 +4,9 @@
 #include "config.h"
 #include <stdint.h>
 
-#define QCGC_GRAY_FLAG 0x01
-#define QCGC_PREBUILT_OBJECT 0x02
+#define QCGC_GRAY_FLAG (1<<0)
+#define QCGC_PREBUILT_OBJECT (1<<1)
+#define QCGC_PREBUILT_REGISTERED (1<<2)
 
 typedef struct object_s {
        uint32_t flags;
diff --git a/rpython/translator/c/src/qcgc/qcgc.c 
b/rpython/translator/c/src/qcgc/qcgc.c
--- a/rpython/translator/c/src/qcgc/qcgc.c
+++ b/rpython/translator/c/src/qcgc/qcgc.c
@@ -7,15 +7,14 @@
 #include <string.h>
 
 #include "allocator.h"
+#include "hugeblocktable.h"
 #include "event_logger.h"
 
 // TODO: Eventually move to own header?
 #define MAX(a,b) (((a)>(b))?(a):(b))
 #define MIN(a,b) (((a)<(b))?(a):(b))
 
-void qcgc_mark(void);
-void qcgc_mark_all(void);
-void qcgc_mark_incremental(void);
+void qcgc_mark(bool incremental);
 void qcgc_pop_object(object_t *object);
 void qcgc_push_object(object_t *object);
 void qcgc_sweep(void);
@@ -23,22 +22,34 @@
 void qcgc_initialize(void) {
        qcgc_state.shadow_stack = 
qcgc_shadow_stack_create(QCGC_SHADOWSTACK_SIZE);
        qcgc_state.prebuilt_objects = qcgc_shadow_stack_create(16); //XXX
+       qcgc_state.gp_gray_stack = qcgc_gray_stack_create(16); // XXX
        qcgc_state.gray_stack_size = 0;
        qcgc_state.phase = GC_PAUSE;
        qcgc_allocator_initialize();
+       qcgc_hbtable_initialize();
        qcgc_event_logger_initialize();
 }
 
 void qcgc_destroy(void) {
        qcgc_event_logger_destroy();
+       qcgc_hbtable_destroy();
        qcgc_allocator_destroy();
        free(qcgc_state.shadow_stack);
+       free(qcgc_state.prebuilt_objects);
+       free(qcgc_state.gp_gray_stack);
 }
 
 /**
  * Shadow stack
  */
 void qcgc_shadowstack_push(object_t *object) {
+#if CHECKED
+       assert((object->flags & QCGC_PREBUILT_OBJECT) == 0);
+#endif
+       if (qcgc_state.phase != GC_PAUSE) {
+               qcgc_state.phase = GC_MARK;
+               qcgc_push_object(object);
+       }
        qcgc_state.shadow_stack =
                qcgc_shadow_stack_push(qcgc_state.shadow_stack, object);
 }
@@ -56,18 +67,45 @@
 #if CHECKED
        assert(object != NULL);
 #endif
-       if ((object->flags & QCGC_GRAY_FLAG) == 0) {
-               object->flags |= QCGC_GRAY_FLAG;
-               if ((object->flags & QCGC_PREBUILT_OBJECT) != 0) {
-                       // Save prebuilt object into list
-                       qcgc_shadow_stack_push(qcgc_state.prebuilt_objects, 
object);
-               } else if (qcgc_state.phase != GC_PAUSE) {
-                       if (qcgc_arena_get_blocktype((cell_t *) object) == 
BLOCK_BLACK) {
-                               // This was black before, push it to gray stack 
again
-                               arena_t *arena = qcgc_arena_addr((cell_t *) 
object);
-                               arena->gray_stack = qcgc_gray_stack_push(
-                                               arena->gray_stack, object);
-                       }
+       if ((object->flags & QCGC_GRAY_FLAG) != 0) {
+               // Already gray, skip
+               return;
+       }
+       object->flags |= QCGC_GRAY_FLAG;
+
+       // Register prebuilt object if necessary
+       if (((object->flags & QCGC_PREBUILT_OBJECT) != 0) &&
+                       ((object->flags & QCGC_PREBUILT_REGISTERED) == 0)) {
+               object->flags |= QCGC_PREBUILT_REGISTERED;
+               qcgc_state.prebuilt_objects = qcgc_shadow_stack_push(
+                               qcgc_state.prebuilt_objects, object);
+       }
+
+       if (qcgc_state.phase == GC_PAUSE) {
+               return; // We are done
+       }
+
+       // Triggered barrier, we must not collect now
+       qcgc_state.phase = GC_MARK;
+
+       // Test reachability of object and push if neccessary
+       if ((object->flags & QCGC_PREBUILT_OBJECT) != 0) {
+               // NOTE: No mark test here, as prebuilt objects are always 
reachable
+               // Push prebuilt object to general purpose gray stack
+               qcgc_state.gp_gray_stack = qcgc_gray_stack_push(
+                               qcgc_state.gp_gray_stack, object);
+       } else if ((object_t *) qcgc_arena_addr((cell_t *) object) == object) {
+               if (qcgc_hbtable_is_marked(object)) {
+                       // Push huge block to general purpose gray stack
+                       qcgc_state.gp_gray_stack = qcgc_gray_stack_push(
+                                       qcgc_state.gp_gray_stack, object);
+               }
+       } else {
+               if (qcgc_arena_get_blocktype((cell_t *) object) == BLOCK_BLACK) 
{
+                       // This was black before, push it to gray stack again
+                       arena_t *arena = qcgc_arena_addr((cell_t *) object);
+                       arena->gray_stack = qcgc_gray_stack_push(
+                                       arena->gray_stack, object);
                }
        }
 }
@@ -81,14 +119,31 @@
        qcgc_event_logger_log(EVENT_ALLOCATE_START, sizeof(size_t),
                        (uint8_t *) &size);
 #endif
+       object_t *result;
+       if (size <= QCGC_LARGE_ALLOC_THRESHOLD) {
+               // Use bump / fit allocator
+               if (true) { // FIXME: Implement reasonable switch
+                       result = qcgc_bump_allocate(size);
+               } else {
+                       result = qcgc_fit_allocate(size);
 
-       object_t *result = (object_t *) qcgc_allocator_allocate(size);
-       result->flags |= QCGC_GRAY_FLAG;
+                       // Fallback to bump allocator
+                       if (result == NULL) {
+                               result = qcgc_bump_allocate(size);
+                       }
+               }
+       } else {
+               // Use huge block allocator
+               result = qcgc_large_allocate(size);
+       }
 
 #if LOG_ALLOCATION
        qcgc_event_logger_log(EVENT_ALLOCATE_DONE, sizeof(object_t *),
                        (uint8_t *) &result);
 #endif
+#if CHECKED
+       assert(qcgc_state.phase != GC_COLLECT);
+#endif
        return result;
 }
 
@@ -121,78 +176,69 @@
        }
 }
 
-void qcgc_mark(void) {
-       qcgc_mark_all();
-}
-
-void qcgc_mark_all(void) {
+void qcgc_mark(bool incremental) {
 #if CHECKED
        assert(qcgc_state.phase == GC_PAUSE || qcgc_state.phase == GC_MARK);
 #endif
+       // FIXME: Log some more information
        qcgc_event_logger_log(EVENT_MARK_START, 0, NULL);
 
-       qcgc_state.phase = GC_MARK;
+       if (qcgc_state.phase == GC_PAUSE) {
+               qcgc_state.phase = GC_MARK;
 
-       // Push all roots
-       for (size_t i = 0; i < qcgc_state.shadow_stack->count; i++) {
-               qcgc_push_object(qcgc_state.shadow_stack->items[i]);
+               // If we do this for the first time, push all roots.
+               // All further changes to the roots (new additions) will be 
added
+               // by qcgc_shadowstack_push
+               for (size_t i = 0; i < qcgc_state.shadow_stack->count; i++) {
+                       qcgc_push_object(qcgc_state.shadow_stack->items[i]);
+               }
+
+               // If we do this for the first time, push all prebuilt objects.
+               // All further changes to prebuilt objects will go to the 
gp_gray_stack
+               // because of the write barrier
+               size_t count = qcgc_state.prebuilt_objects->count;
+               for (size_t i = 0; i < count; i++) {
+                       qcgc_state.gp_gray_stack = qcgc_gray_stack_push(
+                                       qcgc_state.gp_gray_stack,
+                                       qcgc_state.prebuilt_objects->items[i]);
+               }
        }
 
-       // Trace all prebuilt objects
-       for (size_t i = 0; i < qcgc_state.prebuilt_objects->count; i++) {
-               qcgc_trace_cb(qcgc_state.prebuilt_objects->items[i], 
&qcgc_push_object);
-       }
+       while (qcgc_state.gray_stack_size > 0) {
+               // General purpose gray stack (prebuilt objects and huge blocks)
+               size_t to_process = (incremental ?
+                       MIN(qcgc_state.gp_gray_stack->index,
+                                       MAX(qcgc_state.gp_gray_stack->index / 
2, QCGC_INC_MARK_MIN)) :
+                       (qcgc_state.gp_gray_stack->index));
 
-       while(qcgc_state.gray_stack_size > 0) {
+               while (to_process > 0) {
+                       object_t *top = 
qcgc_gray_stack_top(qcgc_state.gp_gray_stack);
+                       qcgc_state.gp_gray_stack =
+                               qcgc_gray_stack_pop(qcgc_state.gp_gray_stack);
+                       qcgc_pop_object(top);
+                       to_process--;
+               }
+
+               // Arena gray stacks
                for (size_t i = 0; i < qcgc_allocator_state.arenas->count; i++) 
{
                        arena_t *arena = qcgc_allocator_state.arenas->items[i];
-                       while (arena->gray_stack->index > 0) {
+                       to_process = (incremental ?
+                                       MIN(arena->gray_stack->index,
+                                               MAX(arena->gray_stack->index / 
2, QCGC_INC_MARK_MIN)) :
+                                       (arena->gray_stack->index));
+
+                       while (to_process > 0) {
                                object_t *top =
                                        qcgc_gray_stack_top(arena->gray_stack);
                                arena->gray_stack =
                                        qcgc_gray_stack_pop(arena->gray_stack);
                                qcgc_pop_object(top);
+                               to_process--;
                        }
                }
-       }
 
-       qcgc_state.phase = GC_COLLECT;
-
-       qcgc_event_logger_log(EVENT_MARK_DONE, 0, NULL);
-}
-
-void qcgc_mark_incremental(void) {
-#if CHECKED
-       assert(qcgc_state.phase == GC_PAUSE || qcgc_state.phase == GC_MARK);
-#endif
-       unsigned long gray_stack_size = qcgc_state.gray_stack_size;
-       qcgc_event_logger_log(EVENT_INCMARK_START, sizeof(gray_stack_size),
-                       (uint8_t *) &gray_stack_size);
-
-       qcgc_state.phase = GC_MARK;
-
-       // Push all roots
-       for (size_t i = 0; i < qcgc_state.shadow_stack->count; i++) {
-               qcgc_push_object(qcgc_state.shadow_stack->items[i]);
-       }
-
-       // Trace all prebuilt objects
-       for (size_t i = 0; i < qcgc_state.prebuilt_objects->count; i++) {
-               qcgc_trace_cb(qcgc_state.prebuilt_objects->items[i], 
&qcgc_push_object);
-       }
-
-       for (size_t i = 0; i < qcgc_allocator_state.arenas->count; i++) {
-               arena_t *arena = qcgc_allocator_state.arenas->items[i];
-               size_t initial_stack_size = arena->gray_stack->index;
-               size_t to_process = MIN(arena->gray_stack->index,
-                               MAX(initial_stack_size / 2, QCGC_INC_MARK_MIN));
-               while (to_process > 0) {
-                       object_t *top =
-                               qcgc_gray_stack_top(arena->gray_stack);
-                       arena->gray_stack =
-                               qcgc_gray_stack_pop(arena->gray_stack);
-                       qcgc_pop_object(top);
-                       to_process--;
+               if (incremental) {
+                       break; // Execute loop once for incremental collection
                }
        }
 
@@ -200,21 +246,29 @@
                qcgc_state.phase = GC_COLLECT;
        }
 
-       gray_stack_size = qcgc_state.gray_stack_size;
-       qcgc_event_logger_log(EVENT_INCMARK_START, sizeof(gray_stack_size),
-                       (uint8_t *) &gray_stack_size);
+       // FIXME: Log some more information
+       qcgc_event_logger_log(EVENT_MARK_DONE, 0, NULL);
+#if CHECKED
+       assert(incremental || (qcgc_state.phase = GC_COLLECT));
+#endif
 }
 
 void qcgc_pop_object(object_t *object) {
 #if CHECKED
        assert(object != NULL);
        assert((object->flags & QCGC_GRAY_FLAG) == QCGC_GRAY_FLAG);
-       assert(qcgc_arena_get_blocktype((cell_t *) object) == BLOCK_BLACK);
+       if (((object->flags & QCGC_PREBUILT_OBJECT) == 0) &&
+               ((object_t *) qcgc_arena_addr((cell_t *) object) != object)) {
+               assert(qcgc_arena_get_blocktype((cell_t *) object) == 
BLOCK_BLACK);
+       }
 #endif
        object->flags &= ~QCGC_GRAY_FLAG;
        qcgc_trace_cb(object, &qcgc_push_object);
 #if CHECKED
-       assert(qcgc_get_mark_color(object) == MARK_COLOR_BLACK);
+       if (((object->flags & QCGC_PREBUILT_OBJECT) == 0) &&
+               ((object_t *) qcgc_arena_addr((cell_t *) object) != object)) {
+               assert(qcgc_get_mark_color(object) == MARK_COLOR_BLACK);
+       }
 #endif
 }
 
@@ -224,8 +278,17 @@
        assert(qcgc_state.phase == GC_MARK);
 #endif
        if (object != NULL) {
+               if ((object_t *) qcgc_arena_addr((cell_t *) object) == object) {
+                       if (qcgc_hbtable_mark(object)) {
+                               // Did mark it / was white before
+                               object->flags |= QCGC_GRAY_FLAG;
+                               qcgc_state.gp_gray_stack = qcgc_gray_stack_push(
+                                               qcgc_state.gp_gray_stack, 
object);
+                       }
+                       return; // Skip tests
+               }
                if ((object->flags & QCGC_PREBUILT_OBJECT) != 0) {
-                       return;
+                       return; // Prebuilt objects are always black, no 
pushing here
                }
                if (qcgc_arena_get_blocktype((cell_t *) object) == BLOCK_WHITE) 
{
                        object->flags |= QCGC_GRAY_FLAG;
@@ -258,6 +321,7 @@
        qcgc_event_logger_log(EVENT_SWEEP_START, sizeof(arena_count),
                        (uint8_t *) &arena_count);
 
+       qcgc_hbtable_sweep();
        for (size_t i = 0; i < qcgc_allocator_state.arenas->count; i++) {
                qcgc_arena_sweep(qcgc_allocator_state.arenas->items[i]);
        }
@@ -267,6 +331,6 @@
 }
 
 void qcgc_collect(void) {
-       qcgc_mark();
+       qcgc_mark(false);
        qcgc_sweep();
 }
diff --git a/rpython/translator/c/src/qcgc/shadow_stack.h 
b/rpython/translator/c/src/qcgc/shadow_stack.h
--- a/rpython/translator/c/src/qcgc/shadow_stack.h
+++ b/rpython/translator/c/src/qcgc/shadow_stack.h
@@ -12,8 +12,13 @@
        object_t *items[];
 } shadow_stack_t;
 
+__attribute__ ((warn_unused_result))
 shadow_stack_t *qcgc_shadow_stack_create(size_t size);
 
+__attribute__ ((warn_unused_result))
 shadow_stack_t *qcgc_shadow_stack_push(shadow_stack_t *stack, object_t *item);
+
 object_t *qcgc_shadow_stack_top(shadow_stack_t *stack);
+
+__attribute__ ((warn_unused_result))
 shadow_stack_t *qcgc_shadow_stack_pop(shadow_stack_t *stack);
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to