1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-16 16:50:21 +02:00

Explicit interrupt handling in VM

* libguile/foreign.c (CODE, get_foreign_stub_code): Add explicit
  handle-interrupts and return-values calls, as foreign-call will fall
  through.
* libguile/gsubr.c (A, B, C, AB, AC, BC, ABC, SUBR_STUB_CODE)
  (scm_i_primitive_call_ip): Same.
* libguile/vm-engine.c (VM_HANDLE_INTERRUPTS): Inline into
  handle-interrupts.
  (RETURN_ONE_VALUE, RETURN_VALUE_LIST): Inline into callers, and fall
  through instead of returning.
  (BR_BINARY, BR_UNARY, BR_ARITHMETIC, BR_U64_ARITHMETIC): Remove
  conditional VM_HANDLE_INTERRUPTS, as the compiler already inserted the
  handle-interrupts calls if needed.
  (vm_engine): Remove VM_HANDLE_INTERRUPTS invocations except in the
  handle-interrupts instruction.
This commit is contained in:
Andy Wingo 2016-11-17 22:13:53 +01:00
parent ca74e3fae5
commit 4985ef13e6
3 changed files with 70 additions and 95 deletions

View file

@ -127,22 +127,6 @@
#define ABORT_CONTINUATION_HOOK() \
RUN_HOOK0 (abort)
/* TODO: Invoke asyncs without trampolining out to C. That will let us
preempt computations via an asynchronous interrupt. */
#define VM_HANDLE_INTERRUPTS \
do \
if (SCM_LIKELY (thread->block_asyncs == 0)) \
{ \
SCM asyncs = scm_atomic_ref_scm (&thread->pending_asyncs); \
if (SCM_UNLIKELY (!scm_is_null (asyncs))) \
{ \
SYNC_IP (); \
scm_async_tick (); \
CACHE_SP (); \
} \
} \
while (0)
@ -282,38 +266,6 @@
#define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o)
#define VARIABLE_BOUNDP(v) (!scm_is_eq (VARIABLE_REF (v), SCM_UNDEFINED))
#define RETURN_ONE_VALUE(ret) \
do { \
SCM val = ret; \
union scm_vm_stack_element *old_fp; \
VM_HANDLE_INTERRUPTS; \
ALLOC_FRAME (2); \
old_fp = vp->fp; \
ip = SCM_FRAME_RETURN_ADDRESS (old_fp); \
vp->fp = SCM_FRAME_DYNAMIC_LINK (old_fp); \
/* Clear frame. */ \
old_fp[0].as_scm = SCM_BOOL_F; \
old_fp[1].as_scm = SCM_BOOL_F; \
/* Leave proc. */ \
SP_SET (0, val); \
POP_CONTINUATION_HOOK (old_fp); \
NEXT (0); \
} while (0)
/* While we could generate the list-unrolling code here, it's fine for
now to just tail-call (apply values vals). */
#define RETURN_VALUE_LIST(vals_) \
do { \
SCM vals = vals_; \
VM_HANDLE_INTERRUPTS; \
ALLOC_FRAME (3); \
SP_SET (2, vm_builtin_apply); \
SP_SET (1, vm_builtin_values); \
SP_SET (0, vals); \
ip = (scm_t_uint32 *) vm_builtin_apply_code; \
goto op_tail_apply; \
} while (0)
#define BR_NARGS(rel) \
scm_t_uint32 expected; \
UNPACK_24 (op, expected); \
@ -334,8 +286,6 @@
{ \
scm_t_int32 offset = ip[1]; \
offset >>= 8; /* Sign-extending shift. */ \
if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (2)
@ -351,8 +301,6 @@
{ \
scm_t_int32 offset = ip[2]; \
offset >>= 8; /* Sign-extending shift. */ \
if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (3)
@ -373,8 +321,6 @@
{ \
scm_t_int32 offset = ip[2]; \
offset >>= 8; /* Sign-extending shift. */ \
if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (3); \
@ -389,8 +335,6 @@
{ \
scm_t_int32 offset = ip[2]; \
offset >>= 8; /* Sign-extending shift. */ \
if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (3); \
@ -409,8 +353,6 @@
{ \
scm_t_int32 offset = ip[2]; \
offset >>= 8; /* Sign-extending shift. */ \
if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (3); \
@ -587,8 +529,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
UNPACK_24 (op, proc);
UNPACK_24 (ip[1], nlocals);
VM_HANDLE_INTERRUPTS;
PUSH_CONTINUATION_HOOK ();
old_fp = vp->fp;
@ -628,8 +568,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
UNPACK_24 (ip[1], nlocals);
label = ip[2];
VM_HANDLE_INTERRUPTS;
PUSH_CONTINUATION_HOOK ();
old_fp = vp->fp;
@ -658,8 +596,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
UNPACK_24 (op, nlocals);
VM_HANDLE_INTERRUPTS;
RESET_FRAME (nlocals);
if (SCM_LIKELY (SCM_PROGRAM_P (FP_REF (0))))
@ -685,8 +621,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
UNPACK_24 (op, nlocals);
label = ip[1];
VM_HANDLE_INTERRUPTS;
RESET_FRAME (nlocals);
ip += label;
@ -709,8 +643,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
UNPACK_24 (op, from);
VM_HANDLE_INTERRUPTS;
VM_ASSERT (from > 0, abort ());
nlocals = FRAME_LOCALS_COUNT ();
@ -789,8 +721,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
union scm_vm_stack_element *old_fp;
scm_t_uint32 nlocals;
VM_HANDLE_INTERRUPTS;
UNPACK_24 (op, nlocals);
if (nlocals)
RESET_FRAME (nlocals);
@ -831,10 +761,23 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
CACHE_SP ();
if (SCM_UNLIKELY (SCM_VALUESP (ret)))
/* multiple values returned to continuation */
RETURN_VALUE_LIST (scm_struct_ref (ret, SCM_INUM0));
{
SCM vals = scm_struct_ref (ret, SCM_INUM0);
long len = scm_ilength (vals);
ALLOC_FRAME (1 + len);
while (len--)
{
SP_SET (len, SCM_CAR (vals));
vals = SCM_CDR (vals);
}
NEXT (1);
}
else
RETURN_ONE_VALUE (ret);
{
ALLOC_FRAME (2);
SP_SET (0, ret);
NEXT (1);
}
}
/* foreign-call cif-idx:12 ptr-idx:12
@ -864,10 +807,23 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
CACHE_SP ();
if (SCM_UNLIKELY (SCM_VALUESP (ret)))
/* multiple values returned to continuation */
RETURN_VALUE_LIST (scm_struct_ref (ret, SCM_INUM0));
{
SCM vals = scm_struct_ref (ret, SCM_INUM0);
long len = scm_ilength (vals);
ALLOC_FRAME (1 + len);
while (len--)
{
SP_SET (len, SCM_CAR (vals));
vals = SCM_CDR (vals);
}
NEXT (1);
}
else
RETURN_ONE_VALUE (ret);
{
ALLOC_FRAME (2);
SP_SET (0, ret);
NEXT (1);
}
}
/* continuation-call contregs:24
@ -936,8 +892,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
int i, list_idx, list_len, nlocals;
SCM list;
VM_HANDLE_INTERRUPTS;
nlocals = FRAME_LOCALS_COUNT ();
// At a minimum, there should be apply, f, and the list.
VM_ASSERT (nlocals >= 3, abort ());
@ -983,8 +937,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
scm_t_dynstack *dynstack;
int first;
VM_HANDLE_INTERRUPTS;
SYNC_IP ();
dynstack = scm_dynstack_capture_all (&thread->dynstack);
vm_cont = scm_i_vm_capture_stack (vp->stack_top,
@ -1407,8 +1359,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
{
scm_t_int32 offset = op;
offset >>= 8; /* Sign-extending shift. */
if (offset <= 0)
VM_HANDLE_INTERRUPTS;
NEXT (offset);
}
@ -3704,8 +3654,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
{ \
scm_t_int32 offset = ip[2]; \
offset >>= 8; /* Sign-extending shift. */ \
if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (3); \
@ -3720,8 +3668,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
{ \
scm_t_int32 offset = ip[2]; \
offset >>= 8; /* Sign-extending shift. */ \
if (offset <= 0) \
VM_HANDLE_INTERRUPTS; \
NEXT (offset); \
} \
NEXT (3); \
@ -3926,7 +3872,18 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
*/
VM_DEFINE_OP (183, handle_interrupts, "handle-interrupts", OP1 (X32))
{
VM_HANDLE_INTERRUPTS;
/* TODO: Invoke asyncs without trampolining out to C. That will
let us preempt computations via an asynchronous interrupt. */
if (SCM_LIKELY (thread->block_asyncs == 0))
{
SCM asyncs = scm_atomic_ref_scm (&thread->pending_asyncs);
if (SCM_UNLIKELY (!scm_is_null (asyncs)))
{
SYNC_IP ();
scm_async_tick ();
CACHE_SP ();
}
}
NEXT (1);
}
@ -4045,8 +4002,6 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
#undef POP_CONTINUATION_HOOK
#undef PUSH_CONTINUATION_HOOK
#undef RETURN
#undef RETURN_ONE_VALUE
#undef RETURN_VALUE_LIST
#undef RUN_HOOK
#undef RUN_HOOK0
#undef RUN_HOOK1