summaryrefslogtreecommitdiff
path: root/libguile/whippet/benchmarks/simple-gc-embedder.h
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/whippet/benchmarks/simple-gc-embedder.h')
-rw-r--r--libguile/whippet/benchmarks/simple-gc-embedder.h183
1 files changed, 183 insertions, 0 deletions
diff --git a/libguile/whippet/benchmarks/simple-gc-embedder.h b/libguile/whippet/benchmarks/simple-gc-embedder.h
new file mode 100644
index 000000000..904d2c740
--- /dev/null
+++ b/libguile/whippet/benchmarks/simple-gc-embedder.h
@@ -0,0 +1,183 @@
+#include <stdatomic.h>
+
+#include "simple-tagging-scheme.h"
+#include "simple-roots-types.h"
+#include "gc-config.h"
+#include "gc-embedder-api.h"
+
+#define GC_EMBEDDER_EPHEMERON_HEADER struct gc_header header;
+#define GC_EMBEDDER_FINALIZER_HEADER struct gc_header header;
+
+static inline size_t gc_finalizer_priority_count(void) { return 2; }
+
+static inline int
+gc_is_valid_conservative_ref_displacement(uintptr_t displacement) {
+#if GC_CONSERVATIVE_ROOTS || GC_CONSERVATIVE_TRACE
+ // Here is where you would allow tagged heap object references.
+ return displacement == 0;
+#else
+ // Shouldn't get here.
+ GC_CRASH();
+#endif
+}
+
+// No external objects in simple benchmarks.
+static inline int gc_extern_space_visit(struct gc_extern_space *space,
+ struct gc_edge edge,
+ struct gc_ref ref) {
+ GC_CRASH();
+}
+static inline void gc_extern_space_start_gc(struct gc_extern_space *space,
+ int is_minor_gc) {
+}
+static inline void gc_extern_space_finish_gc(struct gc_extern_space *space,
+ int is_minor_gc) {
+}
+
+static inline void gc_trace_object(struct gc_ref ref,
+ void (*trace_edge)(struct gc_edge edge,
+ struct gc_heap *heap,
+ void *trace_data),
+ struct gc_heap *heap,
+ void *trace_data,
+ size_t *size) {
+#if GC_CONSERVATIVE_TRACE
+ // Shouldn't get here.
+ GC_CRASH();
+#else
+ switch (tag_live_alloc_kind(*tag_word(ref))) {
+#define SCAN_OBJECT(name, Name, NAME) \
+ case ALLOC_KIND_##NAME: \
+ if (trace_edge) \
+ visit_##name##_fields(gc_ref_heap_object(ref), trace_edge, \
+ heap, trace_data); \
+ if (size) \
+ *size = name##_size(gc_ref_heap_object(ref)); \
+ break;
+ FOR_EACH_HEAP_OBJECT_KIND(SCAN_OBJECT)
+#undef SCAN_OBJECT
+ default:
+ GC_CRASH();
+ }
+#endif
+}
+
+static inline void visit_roots(struct handle *roots,
+ void (*trace_edge)(struct gc_edge edge,
+ struct gc_heap *heap,
+ void *trace_data),
+ struct gc_heap *heap,
+ void *trace_data) {
+ for (struct handle *h = roots; h; h = h->next)
+ trace_edge(gc_edge(&h->v), heap, trace_data);
+}
+
+static inline void gc_trace_mutator_roots(struct gc_mutator_roots *roots,
+ void (*trace_edge)(struct gc_edge edge,
+ struct gc_heap *heap,
+ void *trace_data),
+ struct gc_heap *heap,
+ void *trace_data) {
+ if (roots)
+ visit_roots(roots->roots, trace_edge, heap, trace_data);
+}
+
+static inline void gc_trace_heap_roots(struct gc_heap_roots *roots,
+ void (*trace_edge)(struct gc_edge edge,
+ struct gc_heap *heap,
+ void *trace_data),
+ struct gc_heap *heap,
+ void *trace_data) {
+ if (roots)
+ visit_roots(roots->roots, trace_edge, heap, trace_data);
+}
+
+static inline uintptr_t gc_object_forwarded_nonatomic(struct gc_ref ref) {
+ uintptr_t tag = *tag_word(ref);
+ return (tag & gcobj_not_forwarded_bit) ? 0 : tag;
+}
+
+static inline void gc_object_forward_nonatomic(struct gc_ref ref,
+ struct gc_ref new_ref) {
+ *tag_word(ref) = gc_ref_value(new_ref);
+}
+
+static inline struct gc_atomic_forward
+gc_atomic_forward_begin(struct gc_ref ref) {
+ uintptr_t tag = atomic_load_explicit(tag_word(ref), memory_order_acquire);
+ enum gc_forwarding_state state;
+ if (tag == gcobj_busy)
+ state = GC_FORWARDING_STATE_BUSY;
+ else if (tag & gcobj_not_forwarded_bit)
+ state = GC_FORWARDING_STATE_NOT_FORWARDED;
+ else
+ state = GC_FORWARDING_STATE_FORWARDED;
+ return (struct gc_atomic_forward){ ref, tag, state };
+}
+
+static inline int
+gc_atomic_forward_retry_busy(struct gc_atomic_forward *fwd) {
+ GC_ASSERT(fwd->state == GC_FORWARDING_STATE_BUSY);
+ uintptr_t tag = atomic_load_explicit(tag_word(fwd->ref),
+ memory_order_acquire);
+ if (tag == gcobj_busy)
+ return 0;
+ if (tag & gcobj_not_forwarded_bit) {
+ fwd->state = GC_FORWARDING_STATE_NOT_FORWARDED;
+ fwd->data = tag;
+ } else {
+ fwd->state = GC_FORWARDING_STATE_FORWARDED;
+ fwd->data = tag;
+ }
+ return 1;
+}
+
+static inline void
+gc_atomic_forward_acquire(struct gc_atomic_forward *fwd) {
+ GC_ASSERT(fwd->state == GC_FORWARDING_STATE_NOT_FORWARDED);
+ if (atomic_compare_exchange_strong(tag_word(fwd->ref), &fwd->data,
+ gcobj_busy))
+ fwd->state = GC_FORWARDING_STATE_ACQUIRED;
+ else if (fwd->data == gcobj_busy)
+ fwd->state = GC_FORWARDING_STATE_BUSY;
+ else {
+ GC_ASSERT((fwd->data & gcobj_not_forwarded_bit) == 0);
+ fwd->state = GC_FORWARDING_STATE_FORWARDED;
+ }
+}
+
+static inline void
+gc_atomic_forward_abort(struct gc_atomic_forward *fwd) {
+ GC_ASSERT(fwd->state == GC_FORWARDING_STATE_ACQUIRED);
+ atomic_store_explicit(tag_word(fwd->ref), fwd->data, memory_order_release);
+ fwd->state = GC_FORWARDING_STATE_NOT_FORWARDED;
+}
+
+static inline size_t
+gc_atomic_forward_object_size(struct gc_atomic_forward *fwd) {
+ GC_ASSERT(fwd->state == GC_FORWARDING_STATE_ACQUIRED);
+ switch (tag_live_alloc_kind(fwd->data)) {
+#define OBJECT_SIZE(name, Name, NAME) \
+ case ALLOC_KIND_##NAME: \
+ return name##_size(gc_ref_heap_object(fwd->ref));
+ FOR_EACH_HEAP_OBJECT_KIND(OBJECT_SIZE)
+#undef OBJECT_SIZE
+ default:
+ GC_CRASH();
+ }
+}
+
+static inline void
+gc_atomic_forward_commit(struct gc_atomic_forward *fwd, struct gc_ref new_ref) {
+ GC_ASSERT(fwd->state == GC_FORWARDING_STATE_ACQUIRED);
+ *tag_word(new_ref) = fwd->data;
+ atomic_store_explicit(tag_word(fwd->ref), gc_ref_value(new_ref),
+ memory_order_release);
+ fwd->state = GC_FORWARDING_STATE_FORWARDED;
+}
+
+static inline uintptr_t
+gc_atomic_forward_address(struct gc_atomic_forward *fwd) {
+ GC_ASSERT(fwd->state == GC_FORWARDING_STATE_FORWARDED);
+ return fwd->data;
+}