1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-28 16:00:22 +02:00

VM caches address of local 0 instead of FP

* libguile/vm-engine.c (vm_engine): Cache the address of local 0 instead
  of the FP.  This makes locals access a bit cheaper, but we still have
  to negate the index.  The right fix is to index relative to the SP
  instead.  That's a more involved change, so we punt until later.
This commit is contained in:
Andy Wingo 2015-10-18 19:54:58 +02:00
parent 0007507340
commit aa9f6b0082

View file

@ -107,7 +107,7 @@
{ \ { \
SYNC_IP (); \ SYNC_IP (); \
exp; \ exp; \
CACHE_FP (); \ CACHE_LOCALS (); \
} \ } \
} while (0) } while (0)
#else #else
@ -128,37 +128,39 @@
RUN_HOOK0 (abort) RUN_HOOK0 (abort)
#define VM_HANDLE_INTERRUPTS \ #define VM_HANDLE_INTERRUPTS \
SCM_ASYNC_TICK_WITH_GUARD_CODE (thread, SYNC_IP (), CACHE_FP ()) SCM_ASYNC_TICK_WITH_GUARD_CODE (thread, SYNC_IP (), CACHE_LOCALS ())
/* Virtual Machine /* Virtual Machine
The VM has three state bits: the instruction pointer (IP), the frame The VM has three state bits: the instruction pointer (IP), the frame
pointer (FP), and the stack pointer (SP). We cache the first two of pointer (FP), and the stack pointer (SP). We cache the IP in a
these in machine registers, local to the VM, because they are used machine register, local to the VM, because it is used extensively by
extensively by the VM. As the SP is used more by code outside the VM the VM. We cache the address of local 0 too, for now; when we change
than by the VM itself, we don't bother caching it locally. to reference variables relative to the SP we'll cache the SP instead.
As it is, the SP is used more by code outside the VM than by the VM
itself, we don't bother caching it locally.
Since the FP changes infrequently, relative to the IP, we keep vp->fp Keeping vp->ip in sync with the local IP would be a big lose, as it
in sync with the local FP. This would be a big lose for the IP, is updated so often. Instead of updating vp->ip all the time, we
though, so instead of updating vp->ip all the time, we call SYNC_IP call SYNC_IP whenever we would need to know the IP of the top frame.
whenever we would need to know the IP of the top frame. In practice, In practice, we need to SYNC_IP whenever we call out of the VM to a
we need to SYNC_IP whenever we call out of the VM to a function that function that would like to walk the stack, perhaps as the result of
would like to walk the stack, perhaps as the result of an an exception.
exception.
One more thing. We allow the stack to move, when it expands. One more thing. We allow the stack to move, when it expands.
Therefore if you call out to a C procedure that could call Scheme Therefore if you call out to a C procedure that could call Scheme
code, or otherwise push anything on the stack, you will need to code, or otherwise push anything on the stack, you will need to
CACHE_FP afterwards to restore the possibly-changed FP. */ CACHE_LOCALS afterwards to restore the possibly-changed address of
local 0. */
#define SYNC_IP() vp->ip = (ip) #define SYNC_IP() vp->ip = (ip)
#define CACHE_FP() fp = (vp->fp) #define CACHE_LOCALS() locals = (vp->fp - 1)
#define CACHE_REGISTER() \ #define CACHE_REGISTER() \
do { \ do { \
ip = vp->ip; \ ip = vp->ip; \
fp = vp->fp; \ CACHE_LOCALS (); \
} while (0) } while (0)
@ -179,7 +181,7 @@
{ \ { \
SYNC_IP (); \ SYNC_IP (); \
vm_expand_stack (vp, new_sp); \ vm_expand_stack (vp, new_sp); \
CACHE_FP (); \ CACHE_LOCALS (); \
} \ } \
else \ else \
vp->sp_min_since_gc = vp->sp = new_sp; \ vp->sp_min_since_gc = vp->sp = new_sp; \
@ -246,9 +248,15 @@
case opcode: case opcode:
#endif #endif
#define LOCAL_ADDRESS(i) SCM_FRAME_SLOT (fp, i) // This "locals + 1" is actually an optimization, because vp->fp points
#define LOCAL_REF(i) SCM_FRAME_LOCAL (fp, i) // on before the zeroeth local. The result is to reference locals[-i].
#define LOCAL_SET(i,o) SCM_FRAME_LOCAL (fp, i) = o // In the future we should change to reference locals relative to the SP
// and cache the SP instead, which would give direct (non-negated)
// indexing off the SP, which is more in line with addressing modes
// supported by common CPUs.
#define LOCAL_ADDRESS(i) SCM_FRAME_SLOT (locals + 1, i)
#define LOCAL_REF(i) SCM_FRAME_LOCAL (locals + 1, i)
#define LOCAL_SET(i,o) SCM_FRAME_LOCAL (locals + 1, i) = o
#define VARIABLE_REF(v) SCM_VARIABLE_REF (v) #define VARIABLE_REF(v) SCM_VARIABLE_REF (v)
#define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o) #define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o)
@ -260,9 +268,10 @@
union scm_vm_stack_element *old_fp; \ union scm_vm_stack_element *old_fp; \
VM_HANDLE_INTERRUPTS; \ VM_HANDLE_INTERRUPTS; \
ALLOC_FRAME (2); \ ALLOC_FRAME (2); \
old_fp = fp; \ old_fp = vp->fp; \
ip = SCM_FRAME_RETURN_ADDRESS (fp); \ ip = SCM_FRAME_RETURN_ADDRESS (vp->fp); \
fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp); \ vp->fp = SCM_FRAME_DYNAMIC_LINK (vp->fp); \
CACHE_LOCALS (); \
/* Clear frame. */ \ /* Clear frame. */ \
old_fp[0].scm = SCM_BOOL_F; \ old_fp[0].scm = SCM_BOOL_F; \
old_fp[1].scm = SCM_BOOL_F; \ old_fp[1].scm = SCM_BOOL_F; \
@ -280,9 +289,9 @@
SCM vals = vals_; \ SCM vals = vals_; \
VM_HANDLE_INTERRUPTS; \ VM_HANDLE_INTERRUPTS; \
ALLOC_FRAME (3); \ ALLOC_FRAME (3); \
SCM_FRAME_LOCAL (fp, 0) = vm_builtin_apply; \ SCM_FRAME_LOCAL (vp->fp, 0) = vm_builtin_apply; \
SCM_FRAME_LOCAL (fp, 1) = vm_builtin_values; \ SCM_FRAME_LOCAL (vp->fp, 1) = vm_builtin_values; \
SCM_FRAME_LOCAL (fp, 2) = vals; \ SCM_FRAME_LOCAL (vp->fp, 2) = vals; \
ip = (scm_t_uint32 *) vm_builtin_apply_code; \ ip = (scm_t_uint32 *) vm_builtin_apply_code; \
goto op_tail_apply; \ goto op_tail_apply; \
} while (0) } while (0)
@ -355,7 +364,7 @@
SCM res; \ SCM res; \
SYNC_IP (); \ SYNC_IP (); \
res = srel (x, y); \ res = srel (x, y); \
CACHE_FP (); \ CACHE_LOCALS (); \
if ((ip[1] & 0x1) ? scm_is_false (res) : scm_is_true (res)) \ if ((ip[1] & 0x1) ? scm_is_false (res) : scm_is_true (res)) \
{ \ { \
scm_t_int32 offset = ip[1]; \ scm_t_int32 offset = ip[1]; \
@ -382,7 +391,7 @@
#define RETURN(x) \ #define RETURN(x) \
do { LOCAL_SET (dst, x); NEXT (1); } while (0) do { LOCAL_SET (dst, x); NEXT (1); } while (0)
#define RETURN_EXP(exp) \ #define RETURN_EXP(exp) \
do { SCM __x; SYNC_IP (); __x = exp; CACHE_FP (); RETURN (__x); } while (0) do { SCM __x; SYNC_IP (); __x = exp; CACHE_LOCALS (); RETURN (__x); } while (0)
/* The maximum/minimum tagged integers. */ /* The maximum/minimum tagged integers. */
#define INUM_MAX \ #define INUM_MAX \
@ -429,7 +438,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
/* Frame pointer: A pointer into the stack, off of which we index /* Frame pointer: A pointer into the stack, off of which we index
arguments and local variables. Pushed at function calls, popped on arguments and local variables. Pushed at function calls, popped on
returns. */ returns. */
register union scm_vm_stack_element *fp FP_REG; register union scm_vm_stack_element *locals FP_REG;
/* Current opcode: A cache of *ip. */ /* Current opcode: A cache of *ip. */
register scm_t_uint32 op; register scm_t_uint32 op;
@ -524,9 +533,9 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
ret = scm_values (ret); ret = scm_values (ret);
} }
vp->ip = SCM_FRAME_RETURN_ADDRESS (fp); vp->ip = SCM_FRAME_RETURN_ADDRESS (vp->fp);
vp->sp = SCM_FRAME_PREVIOUS_SP (fp); vp->sp = SCM_FRAME_PREVIOUS_SP (vp->fp);
vp->fp = SCM_FRAME_DYNAMIC_LINK (fp); vp->fp = SCM_FRAME_DYNAMIC_LINK (vp->fp);
return ret; return ret;
} }
@ -556,10 +565,11 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
PUSH_CONTINUATION_HOOK (); PUSH_CONTINUATION_HOOK ();
old_fp = fp; old_fp = vp->fp;
fp = vp->fp = SCM_FRAME_SLOT (old_fp, proc - 1); vp->fp = SCM_FRAME_SLOT (old_fp, proc - 1);
SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp); CACHE_LOCALS ();
SCM_FRAME_SET_RETURN_ADDRESS (fp, ip + 2); SCM_FRAME_SET_DYNAMIC_LINK (vp->fp, old_fp);
SCM_FRAME_SET_RETURN_ADDRESS (vp->fp, ip + 2);
RESET_FRAME (nlocals); RESET_FRAME (nlocals);
@ -597,10 +607,11 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
PUSH_CONTINUATION_HOOK (); PUSH_CONTINUATION_HOOK ();
old_fp = fp; old_fp = vp->fp;
fp = vp->fp = SCM_FRAME_SLOT (old_fp, proc - 1); vp->fp = SCM_FRAME_SLOT (old_fp, proc - 1);
SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp); CACHE_LOCALS ();
SCM_FRAME_SET_RETURN_ADDRESS (fp, ip + 3); SCM_FRAME_SET_DYNAMIC_LINK (vp->fp, old_fp);
SCM_FRAME_SET_RETURN_ADDRESS (vp->fp, ip + 3);
RESET_FRAME (nlocals); RESET_FRAME (nlocals);
@ -759,9 +770,10 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
VM_HANDLE_INTERRUPTS; VM_HANDLE_INTERRUPTS;
old_fp = fp; old_fp = vp->fp;
ip = SCM_FRAME_RETURN_ADDRESS (fp); ip = SCM_FRAME_RETURN_ADDRESS (vp->fp);
fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp); vp->fp = SCM_FRAME_DYNAMIC_LINK (vp->fp);
CACHE_LOCALS ();
/* Clear stack frame. */ /* Clear stack frame. */
old_fp[0].scm = SCM_BOOL_F; old_fp[0].scm = SCM_BOOL_F;
@ -850,7 +862,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
abort (); abort ();
} }
CACHE_FP (); CACHE_LOCALS ();
if (SCM_UNLIKELY (SCM_VALUESP (ret))) if (SCM_UNLIKELY (SCM_VALUESP (ret)))
/* multiple values returned to continuation */ /* multiple values returned to continuation */
@ -884,7 +896,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
ret = scm_i_foreign_call (scm_inline_cons (thread, cif, pointer), ret = scm_i_foreign_call (scm_inline_cons (thread, cif, pointer),
vp->sp); vp->sp);
CACHE_FP (); CACHE_LOCALS ();
if (SCM_UNLIKELY (SCM_VALUESP (ret))) if (SCM_UNLIKELY (SCM_VALUESP (ret)))
/* multiple values returned to continuation */ /* multiple values returned to continuation */
@ -1011,9 +1023,9 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
SYNC_IP (); SYNC_IP ();
dynstack = scm_dynstack_capture_all (&thread->dynstack); dynstack = scm_dynstack_capture_all (&thread->dynstack);
vm_cont = scm_i_vm_capture_stack (vp->stack_top, vm_cont = scm_i_vm_capture_stack (vp->stack_top,
SCM_FRAME_DYNAMIC_LINK (fp), SCM_FRAME_DYNAMIC_LINK (vp->fp),
SCM_FRAME_PREVIOUS_SP (fp), SCM_FRAME_PREVIOUS_SP (vp->fp),
SCM_FRAME_RETURN_ADDRESS (fp), SCM_FRAME_RETURN_ADDRESS (vp->fp),
dynstack, dynstack,
0); 0);
/* FIXME: Seems silly to capture the registers here, when they are /* FIXME: Seems silly to capture the registers here, when they are
@ -1477,7 +1489,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
* If the value in A is equal? to the value in B, add OFFSET, a signed * If the value in A is equal? to the value in B, add OFFSET, a signed
* 24-bit number, to the current instruction pointer. * 24-bit number, to the current instruction pointer.
*/ */
// FIXME: Should sync_ip before calling out and cache_fp before coming // FIXME: Should sync_ip before calling out and cache_locals before coming
// back! Another reason to remove this opcode! // back! Another reason to remove this opcode!
VM_DEFINE_OP (40, br_if_equal, "br-if-equal", OP2 (U8_U12_U12, B1_X7_L24)) VM_DEFINE_OP (40, br_if_equal, "br-if-equal", OP2 (U8_U12_U12, B1_X7_L24))
{ {
@ -1893,7 +1905,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
SYNC_IP (); SYNC_IP ();
var = scm_lookup (LOCAL_REF (sym)); var = scm_lookup (LOCAL_REF (sym));
CACHE_FP (); CACHE_LOCALS ();
if (ip[1] & 0x1) if (ip[1] & 0x1)
VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (LOCAL_REF (sym))); VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (LOCAL_REF (sym)));
LOCAL_SET (dst, var); LOCAL_SET (dst, var);
@ -1912,7 +1924,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
UNPACK_12_12 (op, sym, val); UNPACK_12_12 (op, sym, val);
SYNC_IP (); SYNC_IP ();
scm_define (LOCAL_REF (sym), LOCAL_REF (val)); scm_define (LOCAL_REF (sym), LOCAL_REF (val));
CACHE_FP (); CACHE_LOCALS ();
NEXT (1); NEXT (1);
} }
@ -1972,7 +1984,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
mod = scm_the_root_module (); mod = scm_the_root_module ();
var = scm_module_lookup (mod, sym); var = scm_module_lookup (mod, sym);
CACHE_FP (); CACHE_LOCALS ();
if (ip[4] & 0x1) if (ip[4] & 0x1)
VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym)); VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym));
@ -2033,7 +2045,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
else else
var = scm_private_lookup (SCM_CDR (modname), sym); var = scm_private_lookup (SCM_CDR (modname), sym);
CACHE_FP (); CACHE_LOCALS ();
if (ip[4] & 0x1) if (ip[4] & 0x1)
VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym)); VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym));
@ -2075,7 +2087,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
flags = escape_only_p ? SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY : 0; flags = escape_only_p ? SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY : 0;
scm_dynstack_push_prompt (&thread->dynstack, flags, scm_dynstack_push_prompt (&thread->dynstack, flags,
LOCAL_REF (tag), LOCAL_REF (tag),
vp->stack_top - fp, vp->stack_top - vp->fp,
vp->stack_top - LOCAL_ADDRESS (proc_slot), vp->stack_top - LOCAL_ADDRESS (proc_slot),
ip + offset, ip + offset,
registers); registers);