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:
parent
0007507340
commit
aa9f6b0082
1 changed files with 66 additions and 54 deletions
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue