mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-29 19:30:36 +02:00
Speed up returns in JIT
This patch is a bit unfortunate, in the sense that it exposes some of the JIT guts to the rest of the VM. Code needs to treat "machine return addresses" as valid if non-NULL (as before) and also not equal to a tier-down trampoline. This is because tier-down at a return needs the old frame pointer to load the "virtual return address", and the way this patch works is that it passes the vra in a well-known register. It's a custom calling convention for a certain kind of return. * libguile/jit.h (scm_jit_return_to_interpreter_trampoline): New internal global. * libguile/jit.c: (scm_jit_clear_mcode_return_addresses): Move here, from vm.c. Instead of zeroing return addresses, set them to the return-to-interpreter trampoline. * libguile/vm-engine.c (return-values): Don't enter mcode if the mra is scm_jit_return_to_interpreter_trampoline. * libguile/vm.c (capture_continuation): Treat the tier-down trampoline as NULL.
This commit is contained in:
parent
e8203a3f8c
commit
af72d01de8
4 changed files with 49 additions and 27 deletions
|
@ -152,6 +152,10 @@ static void *exit_mcode;
|
||||||
instruction, compiled as a stub on the side to reduce code size. */
|
instruction, compiled as a stub on the side to reduce code size. */
|
||||||
static void *handle_interrupts_trampoline;
|
static void *handle_interrupts_trampoline;
|
||||||
|
|
||||||
|
/* Return to interpreter trampoline: trampoline to load IP from the VRA
|
||||||
|
and tier down. */
|
||||||
|
void *scm_jit_return_to_interpreter_trampoline;
|
||||||
|
|
||||||
/* Thread-local buffer into which to write code. */
|
/* Thread-local buffer into which to write code. */
|
||||||
struct code_arena
|
struct code_arena
|
||||||
{
|
{
|
||||||
|
@ -1590,27 +1594,31 @@ compile_shuffle_down (scm_jit_state *j, uint16_t from, uint16_t to)
|
||||||
j->frame_size_max -= (from - to);
|
j->frame_size_max -= (from - to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const jit_gpr_t old_fp_for_return_trampoline = T0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
compile_return_values (scm_jit_state *j)
|
compile_return_values (scm_jit_state *j)
|
||||||
{
|
{
|
||||||
jit_gpr_t old_fp = T0, ra = T1;
|
jit_gpr_t ra = T1;
|
||||||
jit_reloc_t interp;
|
|
||||||
|
|
||||||
emit_pop_fp (j, old_fp);
|
emit_pop_fp (j, old_fp_for_return_trampoline);
|
||||||
|
emit_load_mra (j, ra, old_fp_for_return_trampoline);
|
||||||
emit_load_mra (j, ra, old_fp);
|
|
||||||
interp = jit_beqi (j->jit, ra, 0);
|
|
||||||
jit_jmpr (j->jit, ra);
|
jit_jmpr (j->jit, ra);
|
||||||
|
|
||||||
jit_patch_here (j->jit, interp);
|
|
||||||
emit_load_vra (j, ra, old_fp);
|
|
||||||
emit_store_ip (j, ra);
|
|
||||||
emit_exit (j);
|
|
||||||
|
|
||||||
j->frame_size_min = 0;
|
j->frame_size_min = 0;
|
||||||
j->frame_size_max = INT32_MAX;
|
j->frame_size_max = INT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emit_return_to_interpreter_trampoline (scm_jit_state *j)
|
||||||
|
{
|
||||||
|
jit_gpr_t ra = T1;
|
||||||
|
|
||||||
|
emit_load_vra (j, ra, old_fp_for_return_trampoline);
|
||||||
|
emit_store_ip (j, ra);
|
||||||
|
emit_exit (j);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
compile_subr_call (scm_jit_state *j, uint32_t idx)
|
compile_subr_call (scm_jit_state *j, uint32_t idx)
|
||||||
{
|
{
|
||||||
|
@ -4688,6 +4696,10 @@ initialize_jit (void)
|
||||||
handle_interrupts_trampoline =
|
handle_interrupts_trampoline =
|
||||||
emit_code (j, emit_handle_interrupts_trampoline);
|
emit_code (j, emit_handle_interrupts_trampoline);
|
||||||
ASSERT (handle_interrupts_trampoline);
|
ASSERT (handle_interrupts_trampoline);
|
||||||
|
|
||||||
|
scm_jit_return_to_interpreter_trampoline =
|
||||||
|
emit_code (j, emit_return_to_interpreter_trampoline);
|
||||||
|
ASSERT (scm_jit_return_to_interpreter_trampoline);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *
|
static uint8_t *
|
||||||
|
@ -4804,10 +4816,26 @@ void
|
||||||
scm_jit_enter_mcode (scm_thread *thread, const uint8_t *mcode)
|
scm_jit_enter_mcode (scm_thread *thread, const uint8_t *mcode)
|
||||||
{
|
{
|
||||||
LOG ("entering mcode: %p\n", mcode);
|
LOG ("entering mcode: %p\n", mcode);
|
||||||
|
if (!SCM_FRAME_MACHINE_RETURN_ADDRESS (thread->vm.fp))
|
||||||
|
SCM_FRAME_SET_MACHINE_RETURN_ADDRESS
|
||||||
|
(thread->vm.fp, scm_jit_return_to_interpreter_trampoline);
|
||||||
enter_mcode (thread, mcode);
|
enter_mcode (thread, mcode);
|
||||||
LOG ("exited mcode\n");
|
LOG ("exited mcode\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Call to force a thread to go back to the interpreter, for example
|
||||||
|
when single-stepping is enabled. */
|
||||||
|
void
|
||||||
|
scm_jit_clear_mcode_return_addresses (scm_thread *thread)
|
||||||
|
{
|
||||||
|
union scm_vm_stack_element *fp;
|
||||||
|
struct scm_vm *vp = &thread->vm;
|
||||||
|
|
||||||
|
for (fp = vp->fp; fp < vp->stack_top; fp = SCM_FRAME_DYNAMIC_LINK (fp))
|
||||||
|
SCM_FRAME_SET_MACHINE_RETURN_ADDRESS
|
||||||
|
(fp, scm_jit_return_to_interpreter_trampoline);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scm_jit_state_free (scm_jit_state *j)
|
scm_jit_state_free (scm_jit_state *j)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef SCM_JIT_H
|
#ifndef SCM_JIT_H
|
||||||
#define SCM_JIT_H
|
#define SCM_JIT_H
|
||||||
|
|
||||||
/* Copyright 2018
|
/* Copyright 2018-2019
|
||||||
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of Guile.
|
This file is part of Guile.
|
||||||
|
@ -62,6 +62,9 @@ SCM_INTERNAL void scm_jit_enter_mcode (scm_thread *thread,
|
||||||
const uint8_t *mcode);
|
const uint8_t *mcode);
|
||||||
SCM_INTERNAL void scm_jit_state_free (struct scm_jit_state *j);
|
SCM_INTERNAL void scm_jit_state_free (struct scm_jit_state *j);
|
||||||
|
|
||||||
|
SCM_INTERNAL void *scm_jit_return_to_interpreter_trampoline;
|
||||||
|
SCM_INTERNAL void scm_jit_clear_mcode_return_addresses (scm_thread *thread);
|
||||||
|
|
||||||
SCM_INTERNAL void scm_init_jit (void);
|
SCM_INTERNAL void scm_init_jit (void);
|
||||||
|
|
||||||
#endif /* SCM_JIT_H */
|
#endif /* SCM_JIT_H */
|
||||||
|
|
|
@ -551,7 +551,7 @@ VM_NAME (scm_thread *thread)
|
||||||
if (!VP->disable_mcode)
|
if (!VP->disable_mcode)
|
||||||
{
|
{
|
||||||
mcode = SCM_FRAME_MACHINE_RETURN_ADDRESS (old_fp);
|
mcode = SCM_FRAME_MACHINE_RETURN_ADDRESS (old_fp);
|
||||||
if (mcode)
|
if (mcode && mcode != scm_jit_return_to_interpreter_trampoline)
|
||||||
{
|
{
|
||||||
scm_jit_enter_mcode (thread, mcode);
|
scm_jit_enter_mcode (thread, mcode);
|
||||||
CACHE_REGISTER ();
|
CACHE_REGISTER ();
|
||||||
|
|
|
@ -199,18 +199,6 @@ scm_i_capture_current_stack (void)
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call to force a thread to go back to the interpreter, for example
|
|
||||||
when single-stepping is enabled. */
|
|
||||||
static void
|
|
||||||
vm_clear_mcode_return_addresses (scm_thread *thread)
|
|
||||||
{
|
|
||||||
union scm_vm_stack_element *fp;
|
|
||||||
struct scm_vm *vp = &thread->vm;
|
|
||||||
|
|
||||||
for (fp = vp->fp; fp < vp->stack_top; fp = SCM_FRAME_DYNAMIC_LINK (fp))
|
|
||||||
SCM_FRAME_SET_MACHINE_RETURN_ADDRESS (fp, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FOR_EACH_HOOK(M) \
|
#define FOR_EACH_HOOK(M) \
|
||||||
M(apply) \
|
M(apply) \
|
||||||
M(return) \
|
M(return) \
|
||||||
|
@ -242,7 +230,7 @@ vm_recompute_disable_mcode (scm_thread *thread)
|
||||||
#undef DISABLE_MCODE_IF_HOOK_ENABLED
|
#undef DISABLE_MCODE_IF_HOOK_ENABLED
|
||||||
|
|
||||||
if (thread->vm.disable_mcode && !was_disabled)
|
if (thread->vm.disable_mcode && !was_disabled)
|
||||||
vm_clear_mcode_return_addresses (thread);
|
scm_jit_clear_mcode_return_addresses (thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1163,11 +1151,14 @@ static SCM
|
||||||
capture_continuation (scm_thread *thread)
|
capture_continuation (scm_thread *thread)
|
||||||
{
|
{
|
||||||
struct scm_vm *vp = &thread->vm;
|
struct scm_vm *vp = &thread->vm;
|
||||||
|
void *mra = SCM_FRAME_MACHINE_RETURN_ADDRESS (vp->fp);
|
||||||
|
if (mra == scm_jit_return_to_interpreter_trampoline)
|
||||||
|
mra = NULL;
|
||||||
SCM vm_cont = capture_stack (vp->stack_top,
|
SCM vm_cont = capture_stack (vp->stack_top,
|
||||||
SCM_FRAME_DYNAMIC_LINK (vp->fp),
|
SCM_FRAME_DYNAMIC_LINK (vp->fp),
|
||||||
SCM_FRAME_PREVIOUS_SP (vp->fp),
|
SCM_FRAME_PREVIOUS_SP (vp->fp),
|
||||||
SCM_FRAME_VIRTUAL_RETURN_ADDRESS (vp->fp),
|
SCM_FRAME_VIRTUAL_RETURN_ADDRESS (vp->fp),
|
||||||
SCM_FRAME_MACHINE_RETURN_ADDRESS (vp->fp),
|
mra,
|
||||||
scm_dynstack_capture_all (&thread->dynstack),
|
scm_dynstack_capture_all (&thread->dynstack),
|
||||||
0);
|
0);
|
||||||
return scm_i_make_continuation (thread, vm_cont);
|
return scm_i_make_continuation (thread, vm_cont);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue