wingo pushed a commit to branch wip-whippet in repository guile. commit b082f5f50d64edf11918f3d3bcb27e1e06bc3586 Author: Andy Wingo <wi...@igalia.com> AuthorDate: Tue Aug 16 17:54:15 2022 +0200
Separate compilation!!!!! --- Makefile | 47 +++++++++++++++-------- bdw-attrs.h | 13 ++++--- bdw.h => bdw.c | 56 ++++++++++++++++------------ conservative-roots-api.h | 12 ++++++ conservative-roots-embedder.h | 21 +++++++++++ conservative-roots-types.h | 8 ++++ conservative-roots.h | 21 ----------- gc-api.h | 8 ++-- gc-assert.h | 6 ++- gc-attrs.h | 39 +++++++++++++++++++ gc-config.h | 12 ++++++ gc-embedder-api.h | 4 ++ gc-visibility.h | 7 ++++ mt-gcbench-embedder.h | 2 +- mt-gcbench-types.h | 3 ++ mt-gcbench.c | 16 ++++---- parallel-tracer.h | 4 +- precise-roots.h => precise-roots-api.h | 16 +++----- precise-roots-embedder.h | 31 ++++++++++++++++ precise-roots-types.h | 17 +++++++++ quads-embedder.h | 2 + quads.c | 11 ++++-- semi-attrs.h | 11 +++--- semi.h => semi.c | 60 +++++++++++++++++------------- serial-tracer.h | 4 +- simple-gc-embedder.h | 31 +++------------- whippet-attrs.h | 3 +- whippet.h => whippet.c | 68 +++++++++++++++++----------------- 28 files changed, 344 insertions(+), 189 deletions(-) diff --git a/Makefile b/Makefile index 3945498c2..9244c246c 100644 --- a/Makefile +++ b/Makefile @@ -2,32 +2,49 @@ TESTS=quads mt-gcbench # MT_GCBench MT_GCBench2 COLLECTORS=bdw semi whippet parallel-whippet generational-whippet parallel-generational-whippet CC=gcc -CFLAGS=-Wall -O2 -g -fno-strict-aliasing -fvisibility=hidden -Wno-unused -DNDEBUG +CFLAGS=-Wall -O2 -g -flto -fno-strict-aliasing -fvisibility=hidden -Wno-unused -DNDEBUG INCLUDES=-I. -LDFLAGS=-lpthread -COMPILE=$(CC) $(CFLAGS) $(INCLUDES) $(LDFLAGS) +LDFLAGS=-lpthread -flto +COMPILE=$(CC) $(CFLAGS) $(INCLUDES) ALL_TESTS=$(foreach COLLECTOR,$(COLLECTORS),$(addprefix $(COLLECTOR)-,$(TESTS))) all: $(ALL_TESTS) -bdw-%: bdw.h conservative-roots.h %-types.h %.c - $(COMPILE) `pkg-config --libs --cflags bdw-gc` -DGC_BDW -o $@ $*.c +bdw-%-gc.o: semi.c %-embedder.h %.c + $(COMPILE) `pkg-config --cflags bdw-gc` -include $*-embedder.h -o $@ -c bdw.c +bdw-%.o: semi.c %.c + $(COMPILE) -include bdw-attrs.h -o $@ -c $*.c +bdw-%: bdw-%.o bdw-%-gc.o + $(CC) $(LDFLAGS) `pkg-config --libs bdw-gc` -o $@ $^ -semi-%: semi.h precise-roots.h large-object-space.h %-types.h heap-objects.h %.c - $(COMPILE) -DGC_SEMI -o $@ $*.c +semi-%-gc.o: semi.c %-embedder.h large-object-space.h assert.h debug.h %.c + $(COMPILE) -DGC_PRECISE=1 -include $*-embedder.h -o $@ -c semi.c +semi-%.o: semi.c %.c + $(COMPILE) -DGC_PRECISE=1 -include semi-attrs.h -o $@ -c $*.c -whippet-%: whippet.h precise-roots.h large-object-space.h serial-tracer.h assert.h debug.h %-types.h heap-objects.h %.c - $(COMPILE) -DGC_WHIPPET -o $@ $*.c +whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c + $(COMPILE) -DGC_PRECISE=1 -include $*-embedder.h -o $@ -c whippet.c +whippet-%.o: whippet.c %.c + $(COMPILE) -DGC_PRECISE=1 -include whippet-attrs.h -o $@ -c $*.c -parallel-whippet-%: whippet.h precise-roots.h large-object-space.h parallel-tracer.h assert.h debug.h %-types.h heap-objects.h %.c - $(COMPILE) -DGC_PARALLEL_WHIPPET -o $@ $*.c +parallel-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h parallel-tracer.h assert.h debug.h heap-objects.h %.c + $(COMPILE) -DGC_PARALLEL=1 -DGC_PRECISE=1 -include $*-embedder.h -o $@ -c whippet.c +parallel-whippet-%.o: whippet.c %.c + $(COMPILE) -DGC_PARALLEL=1 -DGC_PRECISE=1 -include whippet-attrs.h -o $@ -c $*.c -generational-whippet-%: whippet.h precise-roots.h large-object-space.h serial-tracer.h assert.h debug.h %-types.h heap-objects.h %.c - $(COMPILE) -DGC_GENERATIONAL_WHIPPET -o $@ $*.c +generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c + $(COMPILE) -DGC_GENERATIONAL=1 -DGC_PRECISE=1 -include $*-embedder.h -o $@ -c whippet.c +generational-whippet-%.o: whippet.c %.c + $(COMPILE) -DGC_GENERATIONAL=1 -DGC_PRECISE=1 -include whippet-attrs.h -o $@ -c $*.c -parallel-generational-whippet-%: whippet.h precise-roots.h large-object-space.h parallel-tracer.h assert.h debug.h %-types.h heap-objects.h %.c - $(COMPILE) -DGC_PARALLEL_GENERATIONAL_WHIPPET -o $@ $*.c +parallel-generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h parallel-tracer.h assert.h debug.h heap-objects.h %.c + $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_PRECISE=1 -include $*-embedder.h -o $@ -c whippet.c +parallel-generational-whippet-%.o: whippet.c %.c + $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_PRECISE=1 -include whippet-attrs.h -o $@ -c $*.c + +%: %.o %-gc.o + $(CC) $(LDFLAGS) $($*_LDFLAGS) -o $@ $^ check: $(addprefix test-$(TARGET),$(TARGETS)) diff --git a/bdw-attrs.h b/bdw-attrs.h index 5743cd3a2..960e543b0 100644 --- a/bdw-attrs.h +++ b/bdw-attrs.h @@ -2,6 +2,7 @@ #define BDW_ATTRS_H #include "gc-attrs.h" +#include "gc-assert.h" static inline enum gc_allocator_kind gc_allocator_kind(void) { return GC_ALLOCATOR_INLINE_FREELIST; @@ -14,10 +15,10 @@ static inline size_t gc_allocator_large_threshold(void) { } static inline size_t gc_allocator_allocation_pointer_offset(void) { - abort(); + GC_CRASH(); } static inline size_t gc_allocator_allocation_limit_offset(void) { - abort(); + GC_CRASH(); } static inline size_t gc_allocator_freelist_offset(size_t size) { @@ -29,10 +30,10 @@ static inline size_t gc_allocator_alloc_table_alignment(void) { return 0; } static inline uint8_t gc_allocator_alloc_table_begin_pattern(void) { - abort(); + GC_CRASH(); } static inline uint8_t gc_allocator_alloc_table_end_pattern(void) { - abort(); + GC_CRASH(); } static inline int gc_allocator_needs_clear(void) { @@ -43,10 +44,10 @@ static inline enum gc_write_barrier_kind gc_small_write_barrier_kind(void) { return GC_WRITE_BARRIER_NONE; } static inline size_t gc_small_write_barrier_card_table_alignment(void) { - abort(); + GC_CRASH(); } static inline size_t gc_small_write_barrier_card_size(void) { - abort(); + GC_CRASH(); } #endif // BDW_ATTRS_H diff --git a/bdw.h b/bdw.c similarity index 84% rename from bdw.h rename to bdw.c index 0af332090..7f3ec186b 100644 --- a/bdw.h +++ b/bdw.c @@ -1,8 +1,18 @@ #include <stdint.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> +#define GC_API_ +#include "gc-api.h" + #include "bdw-attrs.h" -#include "conservative-roots.h" + +#if GC_PRECISE +#error bdw-gc is a conservative collector +#else +#include "conservative-roots-embedder.h" +#endif // When pthreads are used, let `libgc' know about it and redirect // allocation calls such as `GC_MALLOC ()' to (contention-free, faster) @@ -61,10 +71,10 @@ static void* allocate_small_slow(void **freelist, size_t idx, size_t bytes = gc_inline_freelist_object_size(idx); GC_generic_malloc_many(bytes, kind, freelist); void *head = *freelist; - if (UNLIKELY (!head)) { + if (GC_UNLIKELY (!head)) { fprintf(stderr, "ran out of space, heap size %zu\n", GC_get_heap_size()); - abort(); + GC_CRASH(); } *freelist = *(void **)(head); return head; @@ -74,25 +84,25 @@ static inline void * allocate_small(void **freelist, size_t idx, enum gc_inline_kind kind) { void *head = *freelist; - if (UNLIKELY (!head)) + if (GC_UNLIKELY (!head)) return allocate_small_slow(freelist, idx, kind); *freelist = *(void **)(head); return head; } -static void* gc_allocate_large(struct mutator *mut, size_t size) { +void* gc_allocate_large(struct mutator *mut, size_t size) { return GC_malloc(size); } -static void* gc_allocate_small(struct mutator *mut, size_t size) { +void* gc_allocate_small(struct mutator *mut, size_t size) { GC_ASSERT(size != 0); GC_ASSERT(size <= gc_allocator_large_threshold()); size_t idx = gc_inline_bytes_to_freelist_index(size); return allocate_small(&mut->freelists[idx], idx, GC_INLINE_KIND_NORMAL); } -static inline void* gc_allocate_pointerless(struct mutator *mut, +void* gc_allocate_pointerless(struct mutator *mut, size_t size) { // Because the BDW API requires us to implement a custom marker so // that the pointerless freelist gets traced, even though it's in a @@ -126,7 +136,7 @@ static void dump_available_gc_options(void) { fprintf(stderr, "\n"); } -static int gc_option_from_string(const char *str) { +int gc_option_from_string(const char *str) { #define PARSE_OPTION(option, name) if (strcmp(str, name) == 0) return option; FOR_EACH_GC_OPTION(PARSE_OPTION) #undef PARSE_OPTION @@ -145,8 +155,8 @@ struct options { }; static size_t parse_size_t(double value) { - ASSERT(value >= 0); - ASSERT(value <= (size_t) -1); + GC_ASSERT(value >= 0); + GC_ASSERT(value <= (size_t) -1); return value; } @@ -163,7 +173,7 @@ static int parse_options(int argc, struct gc_option argv[], options->parallelism = parse_size_t(argv[i].value); break; default: - abort(); + GC_CRASH(); } } @@ -177,8 +187,8 @@ static int parse_options(int argc, struct gc_option argv[], return 1; } -static int gc_init(int argc, struct gc_option argv[], - struct heap **heap, struct mutator **mutator) { +int gc_init(int argc, struct gc_option argv[], + struct heap **heap, struct mutator **mutator) { GC_ASSERT_EQ(gc_allocator_small_granule_size(), GC_INLINE_GRANULE_BYTES); GC_ASSERT_EQ(gc_allocator_large_threshold(), GC_INLINE_FREELIST_COUNT * GC_INLINE_GRANULE_BYTES); @@ -208,8 +218,8 @@ static int gc_init(int argc, struct gc_option argv[], return 1; } -static struct mutator* gc_init_for_thread(uintptr_t *stack_base, - struct heap *heap) { +struct mutator* gc_init_for_thread(uintptr_t *stack_base, + struct heap *heap) { pthread_mutex_lock(&heap->lock); if (!heap->multithreaded) { GC_allow_register_threads(); @@ -221,23 +231,23 @@ static struct mutator* gc_init_for_thread(uintptr_t *stack_base, GC_register_my_thread(&base); return add_mutator(heap); } -static void gc_finish_for_thread(struct mutator *mut) { +void gc_finish_for_thread(struct mutator *mut) { GC_unregister_my_thread(); } -static void* gc_call_without_gc(struct mutator *mut, - void* (*f)(void*), - void *data) { +void* gc_call_without_gc(struct mutator *mut, + void* (*f)(void*), + void *data) { return GC_do_blocking(f, data); } -static void gc_mutator_set_roots(struct mutator *mut, - struct gc_mutator_roots *roots) { +void gc_mutator_set_roots(struct mutator *mut, + struct gc_mutator_roots *roots) { } -static void gc_heap_set_roots(struct heap *heap, struct gc_heap_roots *roots) { +void gc_heap_set_roots(struct heap *heap, struct gc_heap_roots *roots) { } -static void gc_print_stats(struct heap *heap) { +void gc_print_stats(struct heap *heap) { printf("Completed %ld collections\n", (long)GC_get_gc_no()); printf("Heap size is %ld\n", (long)GC_get_heap_size()); } diff --git a/conservative-roots-api.h b/conservative-roots-api.h new file mode 100644 index 000000000..1619cf640 --- /dev/null +++ b/conservative-roots-api.h @@ -0,0 +1,12 @@ +#ifndef CONSERVATIVE_ROOTS_API_H +#define CONSERVATIVE_ROOTS_API_H + +#include "conservative-roots-types.h" + +#define HANDLE_TO(T) union { T* v; struct handle handle; } +#define HANDLE_REF(h) h.v +#define HANDLE_SET(h,val) do { h.v = val; } while (0) +#define PUSH_HANDLE(cx, h) do { (void) &h; } while (0) +#define POP_HANDLE(cx) do { } while (0) + +#endif // CONSERVATIVE_ROOTS_API_H diff --git a/conservative-roots-embedder.h b/conservative-roots-embedder.h new file mode 100644 index 000000000..ae7120010 --- /dev/null +++ b/conservative-roots-embedder.h @@ -0,0 +1,21 @@ +#ifndef CONSERVATIVE_ROOTS_EMBEDDER_H +#define CONSERVATIVE_ROOTS_EMBEDDER_H + +#include "gc-assert.h" +#include "conservative-roots-types.h" + +static inline void gc_trace_mutator_roots(struct gc_mutator_roots *roots, + void (*trace_edge)(struct gc_edge edge, + void *trace_data), + void *trace_data) { + GC_CRASH(); +} + +static inline void gc_trace_heap_roots(struct gc_heap_roots *roots, + void (*trace_edge)(struct gc_edge edge, + void *trace_data), + void *trace_data) { + GC_CRASH(); +} + +#endif // CONSERVATIVE_ROOTS_EMBEDDER_H diff --git a/conservative-roots-types.h b/conservative-roots-types.h new file mode 100644 index 000000000..4744d746e --- /dev/null +++ b/conservative-roots-types.h @@ -0,0 +1,8 @@ +#ifndef CONSERVATIVE_ROOTS_TYPES_H +#define CONSERVATIVE_ROOTS_TYPES_H + +struct handle { void *unused; }; +struct gc_heap_roots { void *unused; }; +struct gc_mutator_roots { void *unused; }; + +#endif // CONSERVATIVE_ROOTS_TYPES_H diff --git a/conservative-roots.h b/conservative-roots.h deleted file mode 100644 index 23fc38de7..000000000 --- a/conservative-roots.h +++ /dev/null @@ -1,21 +0,0 @@ -struct handle { void *unused; }; - -#define HANDLE_TO(T) union { T* v; struct handle handle; } -#define HANDLE_REF(h) h.v -#define HANDLE_SET(h,val) do { h.v = val; } while (0) -#define PUSH_HANDLE(cx, h) do { (void) &h; } while (0) -#define POP_HANDLE(cx) do { } while (0) - -static inline void visit_thread_roots(void *thread_roots, - void (*trace_edge)(struct gc_edge edge, - void *trace_data), - void *trace_data) { - abort(); -} - -static inline void visit_roots(struct handle *roots, - void (*trace_edge)(struct gc_edge edge, - void *trace_data), - void *trace_data) { - GC_ASSERT(!roots); -} diff --git a/gc-api.h b/gc-api.h index c7d332176..c00881f4f 100644 --- a/gc-api.h +++ b/gc-api.h @@ -32,7 +32,7 @@ struct gc_mutator { // FIXME: Conflict with bdw-gc GC_API. Switch prefix? #ifndef GC_API_ -#define GC_API_ static +#define GC_API_ __attribute__((visibility("hidden"))) #endif GC_API_ int gc_option_from_string(const char *str); @@ -159,12 +159,12 @@ static inline void* gc_allocate(struct mutator *mut, size_t size) { case GC_ALLOCATOR_INLINE_NONE: return gc_allocate_small(mut, size); default: - abort(); + GC_CRASH(); } } // FIXME: remove :P -static inline void* gc_allocate_pointerless(struct mutator *mut, size_t bytes); +GC_API_ void* gc_allocate_pointerless(struct mutator *mut, size_t bytes); static inline void gc_small_write_barrier(struct gc_ref obj, struct gc_edge edge, struct gc_ref new_val) GC_ALWAYS_INLINE; @@ -183,7 +183,7 @@ static inline void gc_small_write_barrier(struct gc_ref obj, struct gc_edge edge return; } default: - abort(); + GC_CRASH(); } } diff --git a/gc-assert.h b/gc-assert.h index dc39bee25..c3fa6b749 100644 --- a/gc-assert.h +++ b/gc-assert.h @@ -6,10 +6,14 @@ #define GC_UNLIKELY(e) __builtin_expect(e, 0) #define GC_LIKELY(e) __builtin_expect(e, 1) +#define GC_CRASH() __builtin_trap() + #if GC_DEBUG -#define GC_ASSERT(x) do { if (GC_UNLIKELY(!(x))) __builtin_trap(); } while (0) +#define GC_ASSERT(x) do { if (GC_UNLIKELY(!(x))) GC_CRASH(); } while (0) +#define GC_UNREACHABLE() GC_CRASH() #else #define GC_ASSERT(x) do { } while (0) +#define GC_UNREACHABLE() __builtin_unreachable() #endif #define GC_ASSERT_EQ(a, b) GC_ASSERT((a) == (b)) diff --git a/gc-attrs.h b/gc-attrs.h new file mode 100644 index 000000000..17ff2add5 --- /dev/null +++ b/gc-attrs.h @@ -0,0 +1,39 @@ +#ifndef GC_ATTRS_H +#define GC_ATTRS_H + +#include "gc-inline.h" + +#include <stddef.h> +#include <stdint.h> + +enum gc_allocator_kind { + GC_ALLOCATOR_INLINE_BUMP_POINTER, + GC_ALLOCATOR_INLINE_FREELIST, + GC_ALLOCATOR_INLINE_NONE +}; + +static inline enum gc_allocator_kind gc_allocator_kind(void) GC_ALWAYS_INLINE; +static inline size_t gc_allocator_large_threshold(void) GC_ALWAYS_INLINE; +static inline size_t gc_allocator_small_granule_size(void) GC_ALWAYS_INLINE; + +static inline size_t gc_allocator_allocation_pointer_offset(void) GC_ALWAYS_INLINE; +static inline size_t gc_allocator_allocation_limit_offset(void) GC_ALWAYS_INLINE; + +static inline size_t gc_allocator_freelist_offset(size_t size) GC_ALWAYS_INLINE; + +static inline size_t gc_allocator_alloc_table_alignment(void) GC_ALWAYS_INLINE; +static inline uint8_t gc_allocator_alloc_table_begin_pattern(void) GC_ALWAYS_INLINE; +static inline uint8_t gc_allocator_alloc_table_end_pattern(void) GC_ALWAYS_INLINE; + +static inline int gc_allocator_needs_clear(void) GC_ALWAYS_INLINE; + +enum gc_write_barrier_kind { + GC_WRITE_BARRIER_NONE, + GC_WRITE_BARRIER_CARD +}; + +static inline enum gc_write_barrier_kind gc_small_write_barrier_kind(void) GC_ALWAYS_INLINE; +static inline size_t gc_small_write_barrier_card_table_alignment(void) GC_ALWAYS_INLINE; +static inline size_t gc_small_write_barrier_card_size(void) GC_ALWAYS_INLINE; + +#endif // GC_ATTRS_H diff --git a/gc-config.h b/gc-config.h index cd78e23d5..5fc27b7e5 100644 --- a/gc-config.h +++ b/gc-config.h @@ -5,4 +5,16 @@ #define GC_DEBUG 0 #endif +#ifndef GC_PARALLEL +#define GC_PARALLEL 0 +#endif + +#ifndef GC_GENERATIONAL +#define GC_GENERATIONAL 0 +#endif + +#ifndef GC_PRECISE +#define GC_PRECISE 0 +#endif + #endif // GC_CONFIG_H diff --git a/gc-embedder-api.h b/gc-embedder-api.h index b74bd0486..26929b72e 100644 --- a/gc-embedder-api.h +++ b/gc-embedder-api.h @@ -8,6 +8,10 @@ #define GC_EMBEDDER_API static #endif +struct gc_mutator_roots; +struct gc_heap_roots; +struct gc_atomic_forward; + GC_EMBEDDER_API inline void gc_trace_object(void *object, void (*trace_edge)(struct gc_edge edge, void *trace_data), diff --git a/gc-visibility.h b/gc-visibility.h new file mode 100644 index 000000000..7360915a0 --- /dev/null +++ b/gc-visibility.h @@ -0,0 +1,7 @@ +#ifndef GC_VISIBILITY_H_ +#define GC_VISIBILITY_H_ + +#define GC_INTERNAL __attribute__((visibility("hidden"))) +#define GC_PUBLIC __attribute__((visibility("default"))) + +#endif // GC_VISIBILITY_H diff --git a/mt-gcbench-embedder.h b/mt-gcbench-embedder.h index 63076f474..3aec4808b 100644 --- a/mt-gcbench-embedder.h +++ b/mt-gcbench-embedder.h @@ -36,7 +36,7 @@ static inline void visit_hole_fields(Hole *obj, void (*visit)(struct gc_edge edge, void *visit_data), void *visit_data) { - abort(); + GC_CRASH(); } #include "simple-gc-embedder.h" diff --git a/mt-gcbench-types.h b/mt-gcbench-types.h index 32471d025..60bddc489 100644 --- a/mt-gcbench-types.h +++ b/mt-gcbench-types.h @@ -1,6 +1,9 @@ #ifndef GCBENCH_TYPES_H #define GCBENCH_TYPES_H +#include <stddef.h> +#include <stdint.h> + #define FOR_EACH_HEAP_OBJECT_KIND(M) \ M(node, Node, NODE) \ M(double_array, DoubleArray, DOUBLE_ARRAY) \ diff --git a/mt-gcbench.c b/mt-gcbench.c index 4d304c636..2d2012ae1 100644 --- a/mt-gcbench.c +++ b/mt-gcbench.c @@ -44,16 +44,16 @@ #include <stdlib.h> #include <sys/time.h> -#include "mt-gcbench-types.h" - #include "assert.h" -#include "simple-allocator.h" #include "gc-api.h" - -#include "mt-gcbench-embedder.h" -#include "gc.h" - -#include "gc-inline.h" +#include "mt-gcbench-types.h" +#if GC_PRECISE +#include "precise-roots-api.h" +#else +#include "conservative-roots-api.h" +#endif +#include "mt-gcbench-types.h" +#include "simple-allocator.h" #define MAX_THREAD_COUNT 256 diff --git a/parallel-tracer.h b/parallel-tracer.h index 4ee90de70..07561e215 100644 --- a/parallel-tracer.h +++ b/parallel-tracer.h @@ -149,7 +149,7 @@ static int trace_deque_grow(struct trace_deque *q, int cur, size_t b, size_t t) { if (!trace_buf_grow(&q->bufs[cur], &q->bufs[cur + 1], b, t)) { fprintf(stderr, "failed to grow deque!!\n"); - abort(); + GC_CRASH(); } cur++; @@ -359,7 +359,7 @@ trace_worker_thread(void *data) { pthread_mutex_unlock(&worker->lock); return NULL; default: - abort(); + GC_CRASH(); } } } diff --git a/precise-roots.h b/precise-roots-api.h similarity index 54% rename from precise-roots.h rename to precise-roots-api.h index 2eedb60ed..ced560d15 100644 --- a/precise-roots.h +++ b/precise-roots-api.h @@ -1,7 +1,7 @@ -struct handle { - void *v; - struct handle *next; -}; +#ifndef PRECISE_ROOTS_API_H +#define PRECISE_ROOTS_API_H + +#include "precise-roots-types.h" #define HANDLE_TO(T) union { T* v; struct handle handle; } #define HANDLE_REF(h) h.v @@ -18,10 +18,4 @@ static inline void pop_handle(struct handle **roots) { *roots = (*roots)->next; } -static inline void visit_roots(struct handle *roots, - void (*trace_edge)(struct gc_edge edge, - void *trace_data), - void *trace_data) { - for (struct handle *h = roots; h; h = h->next) - trace_edge(gc_edge(&h->v), trace_data); -} +#endif // PRECISE_ROOTS_API_H diff --git a/precise-roots-embedder.h b/precise-roots-embedder.h new file mode 100644 index 000000000..f37b38e1a --- /dev/null +++ b/precise-roots-embedder.h @@ -0,0 +1,31 @@ +#ifndef PRECISE_ROOTS_EMBEDDER_H +#define PRECISE_ROOTS_EMBEDDER_H + +#include "gc-edge.h" +#include "precise-roots-types.h" + +static inline void visit_roots(struct handle *roots, + void (*trace_edge)(struct gc_edge edge, + void *trace_data), + void *trace_data) { + for (struct handle *h = roots; h; h = h->next) + trace_edge(gc_edge(&h->v), trace_data); +} + +static inline void gc_trace_mutator_roots(struct gc_mutator_roots *roots, + void (*trace_edge)(struct gc_edge edge, + void *trace_data), + void *trace_data) { + if (roots) + visit_roots(roots->roots, trace_edge, trace_data); +} + +static inline void gc_trace_heap_roots(struct gc_heap_roots *roots, + void (*trace_edge)(struct gc_edge edge, + void *trace_data), + void *trace_data) { + if (roots) + visit_roots(roots->roots, trace_edge, trace_data); +} + +#endif // PRECISE_ROOTS_EMBEDDER_H diff --git a/precise-roots-types.h b/precise-roots-types.h new file mode 100644 index 000000000..d2dc96491 --- /dev/null +++ b/precise-roots-types.h @@ -0,0 +1,17 @@ +#ifndef PRECISE_ROOTS_TYPES_H +#define PRECISE_ROOTS_TYPES_H + +struct handle { + void *v; + struct handle *next; +}; + +struct gc_heap_roots { + struct handle *roots; +}; + +struct gc_mutator_roots { + struct handle *roots; +}; + +#endif // PRECISE_ROOTS_TYPES_H diff --git a/quads-embedder.h b/quads-embedder.h index 18047607c..714415dd0 100644 --- a/quads-embedder.h +++ b/quads-embedder.h @@ -1,6 +1,8 @@ #ifndef QUADS_EMBEDDER_H #define QUADS_EMBEDDER_H +#include <stddef.h> + #include "quads-types.h" #define DEFINE_METHODS(name, Name, NAME) \ diff --git a/quads.c b/quads.c index 7797bbd42..7620ff693 100644 --- a/quads.c +++ b/quads.c @@ -1,14 +1,17 @@ #include <stdio.h> +#include <stddef.h> #include <stdlib.h> #include <sys/time.h> #include "assert.h" +#include "gc-api.h" +#if GC_PRECISE +#include "precise-roots-api.h" +#else +#include "conservative-roots-api.h" +#endif #include "quads-types.h" #include "simple-allocator.h" -#include "gc-api.h" - -#include "quads-embedder.h" -#include "gc.h" typedef HANDLE_TO(Quad) QuadHandle; diff --git a/semi-attrs.h b/semi-attrs.h index 55691f047..e6b429178 100644 --- a/semi-attrs.h +++ b/semi-attrs.h @@ -2,6 +2,7 @@ #define SEMI_ATTRS_H #include "gc-attrs.h" +#include "gc-assert.h" static const uintptr_t GC_ALIGNMENT = 8; static const size_t GC_LARGE_OBJECT_THRESHOLD = 8192; @@ -24,7 +25,7 @@ static inline size_t gc_allocator_allocation_limit_offset(void) { } static inline size_t gc_allocator_freelist_offset(size_t size) { - abort(); + GC_CRASH(); } static inline int gc_allocator_needs_clear(void) { @@ -35,20 +36,20 @@ static inline size_t gc_allocator_alloc_table_alignment(void) { return 0; } static inline uint8_t gc_allocator_alloc_table_begin_pattern(void) { - abort(); + GC_CRASH(); } static inline uint8_t gc_allocator_alloc_table_end_pattern(void) { - abort(); + GC_CRASH(); } static inline enum gc_write_barrier_kind gc_small_write_barrier_kind(void) { return GC_WRITE_BARRIER_NONE; } static inline size_t gc_small_write_barrier_card_table_alignment(void) { - abort(); + GC_CRASH(); } static inline size_t gc_small_write_barrier_card_size(void) { - abort(); + GC_CRASH(); } #endif // SEMI_ATTRS_H diff --git a/semi.h b/semi.c similarity index 89% rename from semi.h rename to semi.c index bc32eecb2..64a9ee652 100644 --- a/semi.h +++ b/semi.c @@ -5,9 +5,17 @@ #include <sys/mman.h> #include <unistd.h> +#define GC_API_ +#include "gc-api.h" + #include "semi-attrs.h" #include "large-object-space.h" -#include "precise-roots.h" + +#if GC_PRECISE +#include "precise-roots-embedder.h" +#else +#error semi is a precise collector +#endif struct semi_space { uintptr_t hp; @@ -141,7 +149,7 @@ static void visit(struct gc_edge edge, void *visit_data) { else if (large_object_space_contains(heap_large_object_space(heap), obj)) visit_large_object_space(heap, heap_large_object_space(heap), obj); else - abort(); + GC_CRASH(); } static void collect(struct mutator *mut) { @@ -167,11 +175,11 @@ static void collect_for_alloc(struct mutator *mut, size_t bytes) { struct semi_space *space = mutator_semi_space(mut); if (space->limit - space->hp < bytes) { fprintf(stderr, "ran out of space, heap size %zu\n", space->size); - abort(); + GC_CRASH(); } } -static void* gc_allocate_large(struct mutator *mut, size_t size) { +void* gc_allocate_large(struct mutator *mut, size_t size) { struct heap *heap = mutator_heap(mut); struct large_object_space *space = heap_large_object_space(heap); struct semi_space *semi_space = heap_semi_space(heap); @@ -181,7 +189,7 @@ static void* gc_allocate_large(struct mutator *mut, size_t size) { collect(mut); if (!semi_space_steal_pages(semi_space, npages)) { fprintf(stderr, "ran out of space, heap size %zu\n", semi_space->size); - abort(); + GC_CRASH(); } } @@ -191,13 +199,13 @@ static void* gc_allocate_large(struct mutator *mut, size_t size) { if (!ret) { perror("weird: we have the space but mmap didn't work"); - abort(); + GC_CRASH(); } return ret; } -static void* gc_allocate_small(struct mutator *mut, size_t size) { +void* gc_allocate_small(struct mutator *mut, size_t size) { struct semi_space *space = mutator_semi_space(mut); while (1) { uintptr_t addr = space->hp; @@ -212,7 +220,7 @@ static void* gc_allocate_small(struct mutator *mut, size_t size) { return (void *)addr; } } -static inline void* gc_allocate_pointerless(struct mutator *mut, size_t size) { +void* gc_allocate_pointerless(struct mutator *mut, size_t size) { return gc_allocate(mut, size); } @@ -250,7 +258,7 @@ static void dump_available_gc_options(void) { fprintf(stderr, "\n"); } -static int gc_option_from_string(const char *str) { +int gc_option_from_string(const char *str) { #define PARSE_OPTION(option, name) if (strcmp(str, name) == 0) return option; FOR_EACH_GC_OPTION(PARSE_OPTION) #undef PARSE_OPTION @@ -269,8 +277,8 @@ struct options { }; static size_t parse_size_t(double value) { - ASSERT(value >= 0); - ASSERT(value <= (size_t) -1); + GC_ASSERT(value >= 0); + GC_ASSERT(value <= (size_t) -1); return value; } @@ -286,7 +294,7 @@ static int parse_options(int argc, struct gc_option argv[], options->parallelism = parse_size_t(argv[i].value); break; default: - abort(); + GC_CRASH(); } } @@ -302,8 +310,8 @@ static int parse_options(int argc, struct gc_option argv[], return 1; } -static int gc_init(int argc, struct gc_option argv[], - struct heap **heap, struct mutator **mut) { +int gc_init(int argc, struct gc_option argv[], + struct heap **heap, struct mutator **mut) { GC_ASSERT_EQ(gc_allocator_allocation_pointer_offset(), offsetof(struct semi_space, hp)); GC_ASSERT_EQ(gc_allocator_allocation_limit_offset(), @@ -314,7 +322,7 @@ static int gc_init(int argc, struct gc_option argv[], return 0; *mut = calloc(1, sizeof(struct mutator)); - if (!*mut) abort(); + if (!*mut) GC_CRASH(); *heap = mutator_heap(*mut); struct semi_space *space = mutator_semi_space(*mut); @@ -328,30 +336,30 @@ static int gc_init(int argc, struct gc_option argv[], return 1; } -static void gc_mutator_set_roots(struct mutator *mut, - struct gc_mutator_roots *roots) { +void gc_mutator_set_roots(struct mutator *mut, + struct gc_mutator_roots *roots) { mut->roots = roots; } -static void gc_heap_set_roots(struct heap *heap, struct gc_heap_roots *roots) { - abort(); +void gc_heap_set_roots(struct heap *heap, struct gc_heap_roots *roots) { + GC_CRASH(); } -static struct mutator* gc_init_for_thread(uintptr_t *stack_base, - struct heap *heap) { +struct mutator* gc_init_for_thread(uintptr_t *stack_base, + struct heap *heap) { fprintf(stderr, "Semispace copying collector not appropriate for multithreaded use.\n"); - exit(1); + GC_CRASH(); } -static void gc_finish_for_thread(struct mutator *space) { +void gc_finish_for_thread(struct mutator *space) { } -static void* gc_call_without_gc(struct mutator *mut, void* (*f)(void*), - void *data) { +void* gc_call_without_gc(struct mutator *mut, void* (*f)(void*), + void *data) { // Can't be threads, then there won't be collection. return f(data); } -static void gc_print_stats(struct heap *heap) { +void gc_print_stats(struct heap *heap) { struct semi_space *space = heap_semi_space(heap); printf("Completed %ld collections\n", space->count); printf("Heap size is %zd\n", space->size); diff --git a/serial-tracer.h b/serial-tracer.h index 68c4d489f..27ff36882 100644 --- a/serial-tracer.h +++ b/serial-tracer.h @@ -85,7 +85,7 @@ static inline void trace_queue_push(struct trace_queue *q, struct gcobj *p) { if (UNLIKELY(q->write - q->read == q->size)) { if (!trace_queue_grow(q)) - abort(); + GC_CRASH(); } trace_queue_put(q, q->write++, p); } @@ -94,7 +94,7 @@ static inline void trace_queue_push_many(struct trace_queue *q, struct gcobj **pv, size_t count) { while (q->size - (q->write - q->read) < count) { if (!trace_queue_grow(q)) - abort(); + GC_CRASH(); } for (size_t i = 0; i < count; i++) trace_queue_put(q, q->write++, pv[i]); diff --git a/simple-gc-embedder.h b/simple-gc-embedder.h index 5a8adf717..42e04485e 100644 --- a/simple-gc-embedder.h +++ b/simple-gc-embedder.h @@ -19,34 +19,15 @@ static inline void gc_trace_object(void *object, FOR_EACH_HEAP_OBJECT_KIND(SCAN_OBJECT) #undef SCAN_OBJECT default: - abort (); + GC_CRASH(); } } -struct handle; -struct gc_heap_roots { struct handle *roots; }; -struct gc_mutator_roots { struct handle *roots; }; - -static inline void visit_roots(struct handle *roots, - void (*trace_edge)(struct gc_edge edge, - void *trace_data), - void *trace_data); - -static inline void gc_trace_mutator_roots(struct gc_mutator_roots *roots, - void (*trace_edge)(struct gc_edge edge, - void *trace_data), - void *trace_data) { - if (roots) - visit_roots(roots->roots, trace_edge, trace_data); -} - -static inline void gc_trace_heap_roots(struct gc_heap_roots *roots, - void (*trace_edge)(struct gc_edge edge, - void *trace_data), - void *trace_data) { - if (roots) - visit_roots(roots->roots, trace_edge, trace_data); -} +#if GC_PRECISE +#include "precise-roots-embedder.h" +#else +#include "conservative-roots-embedder.h" +#endif static inline uintptr_t gc_object_forwarded_nonatomic(void *object) { uintptr_t tag = *tag_word(object); diff --git a/whippet-attrs.h b/whippet-attrs.h index 72915b1a1..bfecc44db 100644 --- a/whippet-attrs.h +++ b/whippet-attrs.h @@ -2,6 +2,7 @@ #define WHIPPET_ATTRS_H #include "gc-config.h" +#include "gc-assert.h" #include "gc-attrs.h" static inline enum gc_allocator_kind gc_allocator_kind(void) { @@ -22,7 +23,7 @@ static inline size_t gc_allocator_allocation_limit_offset(void) { } static inline size_t gc_allocator_freelist_offset(size_t size) { - abort(); + GC_CRASH(); } static inline size_t gc_allocator_alloc_table_alignment(void) { diff --git a/whippet.h b/whippet.c similarity index 98% rename from whippet.h rename to whippet.c index 654897b5c..2fdafa1c7 100644 --- a/whippet.h +++ b/whippet.c @@ -1,11 +1,3 @@ -#ifndef GC_PARALLEL_TRACE -#error define GC_PARALLEL_TRACE to 1 or 0 -#endif - -#ifndef GC_GENERATIONAL -#error define GC_GENERATIONAL to 1 or 0 -#endif - #include <pthread.h> #include <stdatomic.h> #include <stdint.h> @@ -15,11 +7,13 @@ #include <string.h> #include <unistd.h> +#define GC_API_ +#include "gc-api.h" + #include "debug.h" #include "gc-inline.h" #include "large-object-space.h" -#include "precise-roots.h" -#if GC_PARALLEL_TRACE +#if GC_PARALLEL #include "parallel-tracer.h" #else #include "serial-tracer.h" @@ -27,6 +21,12 @@ #include "spin.h" #include "whippet-attrs.h" +#if GC_PRECISE +#include "precise-roots-embedder.h" +#else +#error whippet only currently implements precise collection +#endif + #define GRANULE_SIZE 16 #define GRANULE_SIZE_LOG_2 4 #define MEDIUM_OBJECT_THRESHOLD 256 @@ -560,7 +560,7 @@ static inline int mark_space_evacuate_or_mark_object(struct mark_space *space, case GC_FORWARDING_STATE_NOT_FORWARDED: case GC_FORWARDING_STATE_ABORTED: // Impossible. - abort(); + GC_CRASH(); case GC_FORWARDING_STATE_ACQUIRED: { // We claimed the object successfully; evacuating is up to us. size_t object_granules = mark_space_live_object_granules(metadata); @@ -641,7 +641,7 @@ static inline int trace_edge(struct heap *heap, struct gc_edge edge) { return large_object_space_mark_object(heap_large_object_space(heap), obj); else - abort(); + GC_CRASH(); } static inline void trace_one(struct gcobj *obj, void *mark_data) { @@ -836,7 +836,7 @@ static void mutator_mark_buf_grow(struct mutator_mark_buf *buf) { MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (mem == MAP_FAILED) { perror("allocating mutator mark buffer failed"); - abort(); + GC_CRASH(); } if (old_bytes) { memcpy(mem, buf->objects, old_bytes); @@ -905,11 +905,11 @@ static int mutator_should_mark_while_stopping(struct mutator *mut) { return heap_should_mark_while_stopping(mutator_heap(mut)); } -static void gc_mutator_set_roots(struct mutator *mut, - struct gc_mutator_roots *roots) { +void gc_mutator_set_roots(struct mutator *mut, + struct gc_mutator_roots *roots) { mut->roots = roots; } -static void gc_heap_set_roots(struct heap *heap, struct gc_heap_roots *roots) { +void gc_heap_set_roots(struct heap *heap, struct gc_heap_roots *roots) { heap->roots = roots; } @@ -1213,7 +1213,7 @@ static void detect_out_of_memory(struct heap *heap) { // be able to yield more space: out of memory. fprintf(stderr, "ran out of space, heap size %zu (%zu slabs)\n", heap->size, mark_space->nslabs); - abort(); + GC_CRASH(); } static double clamp_major_gc_yield_threshold(struct heap *heap, @@ -1762,7 +1762,7 @@ static void trigger_collection(struct mutator *mut) { heap_unlock(heap); } -static void* gc_allocate_large(struct mutator *mut, size_t size) { +void* gc_allocate_large(struct mutator *mut, size_t size) { struct heap *heap = mutator_heap(mut); struct large_object_space *space = heap_large_object_space(heap); @@ -1781,13 +1781,13 @@ static void* gc_allocate_large(struct mutator *mut, size_t size) { if (!ret) { perror("weird: we have the space but mmap didn't work"); - abort(); + GC_CRASH(); } return ret; } -static void* gc_allocate_small(struct mutator *mut, size_t size) { +void* gc_allocate_small(struct mutator *mut, size_t size) { GC_ASSERT(size > 0); // allocating 0 bytes would be silly GC_ASSERT(size <= gc_allocator_large_threshold()); size = align_up(size, GRANULE_SIZE); @@ -1816,7 +1816,7 @@ static void* gc_allocate_small(struct mutator *mut, size_t size) { return obj; } -static inline void* gc_allocate_pointerless(struct mutator *mut, size_t size) { +void* gc_allocate_pointerless(struct mutator *mut, size_t size) { return gc_allocate(mut, size); } @@ -1832,7 +1832,7 @@ static void dump_available_gc_options(void) { fprintf(stderr, "\n"); } -static int gc_option_from_string(const char *str) { +int gc_option_from_string(const char *str) { #define PARSE_OPTION(option, name) if (strcmp(str, name) == 0) return option; FOR_EACH_GC_OPTION(PARSE_OPTION) #undef PARSE_OPTION @@ -1869,7 +1869,7 @@ static int parse_options(int argc, struct gc_option argv[], options->parallelism = parse_size_t(argv[i].value); break; default: - abort(); + GC_CRASH(); } } @@ -1916,7 +1916,7 @@ static int heap_init(struct heap *heap, struct options *options) { heap->size = options->fixed_heap_size; if (!tracer_init(heap, options->parallelism)) - abort(); + GC_CRASH(); heap->fragmentation_low_threshold = 0.05; heap->fragmentation_high_threshold = 0.10; @@ -1960,7 +1960,7 @@ static int mark_space_init(struct mark_space *space, struct heap *heap) { return 1; } -static int gc_init(int argc, struct gc_option argv[], +int gc_init(int argc, struct gc_option argv[], struct heap **heap, struct mutator **mut) { GC_ASSERT_EQ(gc_allocator_small_granule_size(), GRANULE_SIZE); GC_ASSERT_EQ(gc_allocator_large_threshold(), LARGE_OBJECT_THRESHOLD); @@ -1982,10 +1982,10 @@ static int gc_init(int argc, struct gc_option argv[], return 0; *heap = calloc(1, sizeof(struct heap)); - if (!*heap) abort(); + if (!*heap) GC_CRASH(); if (!heap_init(*heap, &options)) - abort(); + GC_CRASH(); struct mark_space *space = heap_mark_space(*heap); if (!mark_space_init(space, *heap)) { @@ -1995,24 +1995,24 @@ static int gc_init(int argc, struct gc_option argv[], } if (!large_object_space_init(heap_large_object_space(*heap), *heap)) - abort(); + GC_CRASH(); *mut = calloc(1, sizeof(struct mutator)); - if (!*mut) abort(); + if (!*mut) GC_CRASH(); add_mutator(*heap, *mut); return 1; } -static struct mutator* gc_init_for_thread(uintptr_t *stack_base, +struct mutator* gc_init_for_thread(uintptr_t *stack_base, struct heap *heap) { struct mutator *ret = calloc(1, sizeof(struct mutator)); if (!ret) - abort(); + GC_CRASH(); add_mutator(heap, ret); return ret; } -static void gc_finish_for_thread(struct mutator *mut) { +void gc_finish_for_thread(struct mutator *mut) { remove_mutator(mutator_heap(mut), mut); mutator_mark_buf_destroy(&mut->mark_buf); free(mut); @@ -2042,7 +2042,7 @@ static void reactivate_mutator(struct heap *heap, struct mutator *mut) { heap_unlock(heap); } -static void* gc_call_without_gc(struct mutator *mut, +void* gc_call_without_gc(struct mutator *mut, void* (*f)(void*), void *data) { struct heap *heap = mutator_heap(mut); @@ -2052,7 +2052,7 @@ static void* gc_call_without_gc(struct mutator *mut, return ret; } -static void gc_print_stats(struct heap *heap) { +void gc_print_stats(struct heap *heap) { printf("Completed %ld collections (%ld major)\n", heap->count, heap->count - heap->minor_count); printf("Heap size with overhead is %zd (%zu slabs)\n",