1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 04:10:18 +02:00

Switch to use Whippet allocation fast paths

* libguile/Makefile.am (noinst_HEADERS, modinclude_HEADERS): Move
gc-inline.h to be a private header.
* libguile/gc-inline.h (scm_inline_gc_malloc_pointerless):
(scm_inline_gc_malloc): Use gc_allocate.
* libguile/intrinsics.c (allocate_words_with_freelist):
(allocate_pointerless_words_with_freelist): Remove these intrinsics.
Renumbers the intrinsics.
(scm_bootstrap_intrinsics):
* libguile/intrinsics.h (SCM_FOR_ALL_VM_INTRINSICS): Adapt to intrinsics
change.
* libguile/jit.c (emit_update_alloc_table):
(emit_allocate_bytes_fast_freelist):
(emit_allocate_words_slow): New helpers.
(compile_allocate_words):
(compile_allocate_words_immediate):
(compile_allocate_words_immediate_slow):
(compile_allocate_pointerless_words):
(compile_allocate_pointerless_words_immediate):
(compile_allocate_pointerless_words_immediate_slow): Use new helpers.
* libguile/threads.c (scm_trace_thread_mutator_roots):
(on_thread_exit):
* libguile/threads.h: Remove Guile-managed thread-local freelists.
This commit is contained in:
Andy Wingo 2025-04-22 13:44:44 +02:00
parent 7696344634
commit 0532602cd3
7 changed files with 93 additions and 185 deletions

View file

@ -2285,18 +2285,60 @@ compile_bind_optionals_slow (scm_jit_state *j, uint32_t nlocals)
{
}
static void
emit_update_alloc_table(scm_jit_state *j, jit_gpr_t obj, size_t size,
enum gc_allocation_kind kind)
{
size_t alignment = gc_allocator_alloc_table_alignment();
if (!alignment) return;
DIE ("allocation table unimplemented");
}
static inline void
emit_allocate_bytes_fast_freelist (scm_jit_state *j, jit_gpr_t dst, size_t bytes,
enum gc_allocation_kind kind,
jit_gpr_t tmp1, jit_gpr_t tmp2)
{
jit_gpr_t mut = tmp1;
emit_ldxi (j, mut, THREAD, offsetof(struct scm_thread, mutator));
size_t offset = gc_allocator_freelist_offset (bytes, kind);
emit_ldxi (j, dst, mut, offset);
add_slow_path_patch (j, jit_beqi (j->jit, dst, 0));
jit_gpr_t new_freelist = tmp2;
emit_ldr (j, new_freelist, dst);
jit_stxi (j->jit, offset, mut, new_freelist);
emit_update_alloc_table(j, dst, bytes, kind);
}
static inline void
emit_allocate_words_slow (scm_jit_state *j, jit_gpr_t res, jit_operand_t nwords,
enum gc_allocation_kind kind)
{
emit_store_current_ip (j, res);
SCM (*intrinsic)(struct scm_thread *, size_t);
switch (kind)
{
case GC_ALLOCATION_TAGGED:
intrinsic = scm_vm_intrinsics.allocate_words;
break;
case GC_ALLOCATION_UNTAGGED_POINTERLESS:
intrinsic = scm_vm_intrinsics.allocate_pointerless_words;
break;
default:
DIE ("unknown allocation kind");
}
emit_call_2 (j, intrinsic, thread_operand(), nwords);
emit_retval (j, res);
emit_reload_sp (j);
}
static void
compile_allocate_words (scm_jit_state *j, uint32_t dst, uint32_t nwords)
{
jit_gpr_t t = T0;
emit_store_current_ip (j, t);
emit_call_2 (j, scm_vm_intrinsics.allocate_words, thread_operand (),
sp_sz_operand (j, nwords));
emit_retval (j, t);
record_gpr_clobber (j, t);
emit_reload_sp (j);
emit_sp_set_scm (j, dst, t);
emit_allocate_words_slow (j, T0, sp_sz_operand (j, nwords),
GC_ALLOCATION_TAGGED);
emit_sp_set_scm (j, dst, T0);
}
static void
compile_allocate_words_slow (scm_jit_state *j, uint32_t dst, uint32_t nwords)
@ -2307,49 +2349,30 @@ static void
compile_allocate_words_immediate (scm_jit_state *j, uint32_t dst, uint32_t nwords)
{
size_t bytes = nwords * sizeof(SCM);
size_t idx = scm_inline_gc_bytes_to_freelist_index (bytes);
if (SCM_UNLIKELY (idx >= SCM_INLINE_GC_FREELIST_COUNT))
{
jit_gpr_t t = T0;
emit_store_current_ip (j, t);
emit_call_1 (j, GC_malloc, jit_operand_imm (JIT_OPERAND_ABI_WORD, bytes));
emit_retval (j, t);
emit_reload_sp (j);
emit_sp_set_scm (j, dst, t);
}
if (gc_allocator_kind() == GC_ALLOCATOR_INLINE_FREELIST &&
bytes <= gc_allocator_large_threshold ())
emit_allocate_bytes_fast_freelist (j, T0, bytes, GC_ALLOCATION_TAGGED,
T1, T2);
else
{
jit_gpr_t res = T0;
ptrdiff_t offset = offsetof(struct scm_thread, freelists);
offset += idx * sizeof(void*);
emit_ldxi (j, res, THREAD, offset);
add_slow_path_patch (j, jit_beqi (j->jit, res, 0));
jit_gpr_t new_freelist = T1;
emit_ldr (j, new_freelist, res);
jit_stxi (j->jit, offset, THREAD, new_freelist);
emit_sp_set_scm (j, dst, res);
}
emit_allocate_words_slow (j, T0,
jit_operand_imm (JIT_OPERAND_ABI_WORD, nwords),
GC_ALLOCATION_TAGGED);
emit_sp_set_scm (j, dst, T0);
}
static void
compile_allocate_words_immediate_slow (scm_jit_state *j, uint32_t dst, uint32_t nwords)
{
size_t bytes = nwords * sizeof(SCM);
size_t idx = scm_inline_gc_bytes_to_freelist_index (bytes);
if (SCM_UNLIKELY (idx >= SCM_INLINE_GC_FREELIST_COUNT))
/* Only emit a slow path if there is a fast path. */
if (gc_allocator_kind() == GC_ALLOCATOR_INLINE_FREELIST &&
bytes <= gc_allocator_large_threshold ())
{
}
else
{
jit_gpr_t res = T0;
emit_store_current_ip (j, res);
emit_call_2 (j, scm_vm_intrinsics.allocate_words_with_freelist,
thread_operand (),
jit_operand_imm (JIT_OPERAND_ABI_WORD, idx));
emit_retval (j, res);
emit_reload_sp (j);
emit_sp_set_scm (j, dst, res);
emit_allocate_words_slow (j, T0,
jit_operand_imm (JIT_OPERAND_ABI_WORD, nwords),
GC_ALLOCATION_TAGGED);
emit_sp_set_scm (j, dst, T0);
continue_after_slow_path (j, j->next_ip);
}
}
@ -2357,15 +2380,9 @@ compile_allocate_words_immediate_slow (scm_jit_state *j, uint32_t dst, uint32_t
static void
compile_allocate_pointerless_words (scm_jit_state *j, uint32_t dst, uint32_t nwords)
{
jit_gpr_t t = T0;
emit_store_current_ip (j, t);
emit_call_2 (j, scm_vm_intrinsics.allocate_pointerless_words, thread_operand (),
sp_sz_operand (j, nwords));
emit_retval (j, t);
record_gpr_clobber (j, t);
emit_reload_sp (j);
emit_sp_set_scm (j, dst, t);
emit_allocate_words_slow (j, T0, sp_sz_operand (j, nwords),
GC_ALLOCATION_UNTAGGED_POINTERLESS);
emit_sp_set_scm (j, dst, T0);
}
static void
compile_allocate_pointerless_words_slow (scm_jit_state *j, uint32_t dst, uint32_t nwords)
@ -2376,49 +2393,31 @@ static void
compile_allocate_pointerless_words_immediate (scm_jit_state *j, uint32_t dst, uint32_t nwords)
{
size_t bytes = nwords * sizeof(SCM);
size_t idx = scm_inline_gc_bytes_to_freelist_index (bytes);
if (SCM_UNLIKELY (idx >= SCM_INLINE_GC_FREELIST_COUNT))
{
jit_gpr_t t = T0;
emit_store_current_ip (j, t);
emit_call_1 (j, GC_malloc_atomic, jit_operand_imm (JIT_OPERAND_ABI_WORD, bytes));
emit_retval (j, t);
emit_reload_sp (j);
emit_sp_set_scm (j, dst, t);
}
if (gc_allocator_kind() == GC_ALLOCATOR_INLINE_FREELIST &&
bytes <= gc_allocator_large_threshold ())
emit_allocate_bytes_fast_freelist (j, T0, bytes,
GC_ALLOCATION_UNTAGGED_POINTERLESS,
T1, T2);
else
{
jit_gpr_t res = T0;
ptrdiff_t offset = offsetof(struct scm_thread, pointerless_freelists);
offset += idx * sizeof(void*);
emit_ldxi (j, res, THREAD, offset);
add_slow_path_patch (j, jit_beqi (j->jit, res, 0));
jit_gpr_t new_freelist = T1;
emit_ldr (j, new_freelist, res);
jit_stxi (j->jit, offset, THREAD, new_freelist);
emit_sp_set_scm (j, dst, res);
}
emit_allocate_words_slow (j, T0,
jit_operand_imm (JIT_OPERAND_ABI_WORD, nwords),
GC_ALLOCATION_UNTAGGED_POINTERLESS);
emit_sp_set_scm (j, dst, T0);
}
static void
compile_allocate_pointerless_words_immediate_slow (scm_jit_state *j, uint32_t dst, uint32_t nwords)
{
size_t bytes = nwords * sizeof(SCM);
size_t idx = scm_inline_gc_bytes_to_freelist_index (bytes);
if (SCM_UNLIKELY (idx >= SCM_INLINE_GC_FREELIST_COUNT))
/* Only emit a slow path if there is a fast path. */
if (gc_allocator_kind() == GC_ALLOCATOR_INLINE_FREELIST &&
bytes <= gc_allocator_large_threshold ())
{
}
else
{
jit_gpr_t res = T0;
emit_store_current_ip (j, res);
emit_call_2 (j, scm_vm_intrinsics.allocate_pointerless_words_with_freelist,
thread_operand (),
jit_operand_imm (JIT_OPERAND_ABI_WORD, idx));
emit_retval (j, res);
emit_reload_sp (j);
emit_sp_set_scm (j, dst, res);
emit_allocate_words_slow (j, T0,
jit_operand_imm (JIT_OPERAND_ABI_WORD, nwords),
GC_ALLOCATION_UNTAGGED_POINTERLESS);
emit_sp_set_scm (j, dst, T0);
continue_after_slow_path (j, j->next_ip);
}
}