mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-28 16:00:22 +02:00
Reinstating undelimited continuations uses intrinsic
* libguile/continuations.h (scm_t_contregs): Remove "struct vm*" member; unneeded. * libguile/continuations.c (scm_i_make_continuation): No need to store continuation->vp. (scm_i_contregs): New internal function, replaces scm_i_contregs_vp and scm_i_contregs_vm_cont. (scm_i_check_continuation): Remove; moved to vm.c. (scm_i_reinstate_continuation): Add an abort(), to satisfy SCM_NORETURN. * libguile/intrinsics.h: Add new "reinstate-continuation!" intrinsic. * libguile/vm-engine.c (continuation-call): Use new reinstate-continuation! intrinsic. * libguile/vm.c (vm_return_to_continuation_inner): Move later in the file. (reinstate_continuation_x): New intrinsic. (scm_bootstrap_vm): Init new intrinsic.
This commit is contained in:
parent
3b6bf20ef5
commit
5e8e816c61
5 changed files with 83 additions and 93 deletions
|
@ -193,7 +193,6 @@ scm_i_make_continuation (int *first, struct scm_vm *vp, SCM vm_cont)
|
||||||
#endif
|
#endif
|
||||||
continuation->offset = continuation->stack - src;
|
continuation->offset = continuation->stack - src;
|
||||||
memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size);
|
memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size);
|
||||||
continuation->vp = vp;
|
|
||||||
continuation->vm_cont = vm_cont;
|
continuation->vm_cont = vm_cont;
|
||||||
saved_cookie = vp->resumable_prompt_cookie;
|
saved_cookie = vp->resumable_prompt_cookie;
|
||||||
capture_auxiliary_stack (thread, continuation);
|
capture_auxiliary_stack (thread, continuation);
|
||||||
|
@ -236,16 +235,13 @@ scm_i_continuation_to_frame (SCM continuation, struct scm_frame *frame)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct scm_vm *
|
scm_t_contregs *
|
||||||
scm_i_contregs_vp (SCM contregs)
|
scm_i_contregs (SCM contregs)
|
||||||
{
|
{
|
||||||
return SCM_CONTREGS (contregs)->vp;
|
if (!SCM_CONTREGSP (contregs))
|
||||||
}
|
abort ();
|
||||||
|
|
||||||
SCM
|
return SCM_CONTREGS (contregs);
|
||||||
scm_i_contregs_vm_cont (SCM contregs)
|
|
||||||
{
|
|
||||||
return SCM_CONTREGS (contregs)->vm_cont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -336,24 +332,11 @@ scm_dynthrow (SCM cont)
|
||||||
copy_stack_and_call (continuation, dst);
|
copy_stack_and_call (continuation, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
scm_i_check_continuation (SCM cont)
|
|
||||||
{
|
|
||||||
scm_i_thread *thread = SCM_I_CURRENT_THREAD;
|
|
||||||
scm_t_contregs *continuation = SCM_CONTREGS (cont);
|
|
||||||
|
|
||||||
if (!scm_is_eq (continuation->root, thread->continuation_root))
|
|
||||||
scm_misc_error
|
|
||||||
("%continuation-call",
|
|
||||||
"invoking continuation would cross continuation barrier: ~A",
|
|
||||||
scm_list_1 (cont));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
scm_i_reinstate_continuation (SCM cont)
|
scm_i_reinstate_continuation (SCM cont)
|
||||||
{
|
{
|
||||||
scm_dynthrow (cont);
|
scm_dynthrow (cont);
|
||||||
|
abort (); /* Unreachable. */
|
||||||
}
|
}
|
||||||
|
|
||||||
SCM
|
SCM
|
||||||
|
|
|
@ -49,7 +49,6 @@ typedef struct
|
||||||
#endif
|
#endif
|
||||||
size_t num_stack_items; /* size of the saved stack. */
|
size_t num_stack_items; /* size of the saved stack. */
|
||||||
SCM root; /* continuation root identifier. */
|
SCM root; /* continuation root identifier. */
|
||||||
struct scm_vm *vp; /* vm */
|
|
||||||
SCM vm_cont; /* vm's stack and regs */
|
SCM vm_cont; /* vm's stack and regs */
|
||||||
|
|
||||||
/* The offset from the live stack location to this copy. This is
|
/* The offset from the live stack location to this copy. This is
|
||||||
|
@ -71,15 +70,12 @@ typedef struct
|
||||||
SCM_INTERNAL SCM scm_i_make_continuation (int *first,
|
SCM_INTERNAL SCM scm_i_make_continuation (int *first,
|
||||||
struct scm_vm *vp,
|
struct scm_vm *vp,
|
||||||
SCM vm_cont);
|
SCM vm_cont);
|
||||||
SCM_INTERNAL void scm_i_check_continuation (SCM cont);
|
SCM_INTERNAL void scm_i_reinstate_continuation (SCM cont) SCM_NORETURN;
|
||||||
SCM_INTERNAL void scm_i_reinstate_continuation (SCM cont);
|
|
||||||
|
|
||||||
struct scm_frame;
|
|
||||||
SCM_INTERNAL int scm_i_continuation_to_frame (SCM cont,
|
SCM_INTERNAL int scm_i_continuation_to_frame (SCM cont,
|
||||||
struct scm_frame *frame);
|
struct scm_frame *frame);
|
||||||
|
|
||||||
SCM_INTERNAL struct scm_vm* scm_i_contregs_vp (SCM contregs);
|
SCM_INTERNAL scm_t_contregs* scm_i_contregs (SCM contregs);
|
||||||
SCM_INTERNAL SCM scm_i_contregs_vm_cont (SCM contregs);
|
|
||||||
|
|
||||||
SCM_API void *scm_c_with_continuation_barrier (void *(*func)(void*), void *);
|
SCM_API void *scm_c_with_continuation_barrier (void *(*func)(void*), void *);
|
||||||
SCM_API SCM scm_with_continuation_barrier (SCM proc);
|
SCM_API SCM scm_with_continuation_barrier (SCM proc);
|
||||||
|
|
|
@ -52,6 +52,7 @@ typedef void (*scm_t_thread_u32_u32_scm_u8_u8_intrinsic) (scm_i_thread*, uint32_
|
||||||
uint8_t);
|
uint8_t);
|
||||||
typedef SCM (*scm_t_scm_from_scm_scm_intp_sp_intrinsic) (SCM, SCM, int*,
|
typedef SCM (*scm_t_scm_from_scm_scm_intp_sp_intrinsic) (SCM, SCM, int*,
|
||||||
const union scm_vm_stack_element*);
|
const union scm_vm_stack_element*);
|
||||||
|
typedef void (*scm_t_thread_scm_noreturn_intrinsic) (scm_i_thread*, SCM) SCM_NORETURN;
|
||||||
|
|
||||||
#define SCM_FOR_ALL_VM_INTRINSICS(M) \
|
#define SCM_FOR_ALL_VM_INTRINSICS(M) \
|
||||||
M(scm_from_scm_scm, add, "add", ADD) \
|
M(scm_from_scm_scm, add, "add", ADD) \
|
||||||
|
@ -102,6 +103,7 @@ typedef SCM (*scm_t_scm_from_scm_scm_intp_sp_intrinsic) (SCM, SCM, int*,
|
||||||
M(thread_u32_u32_scm_u8_u8, bind_kwargs, "bind-kwargs", BIND_KWARGS) \
|
M(thread_u32_u32_scm_u8_u8, bind_kwargs, "bind-kwargs", BIND_KWARGS) \
|
||||||
M(thread, push_interrupt_frame, "push-interrupt-frame", PUSH_INTERRUPT_FRAME) \
|
M(thread, push_interrupt_frame, "push-interrupt-frame", PUSH_INTERRUPT_FRAME) \
|
||||||
M(scm_from_scm_scm_intp_sp, foreign_call, "foreign-call", FOREIGN_CALL) \
|
M(scm_from_scm_scm_intp_sp, foreign_call, "foreign-call", FOREIGN_CALL) \
|
||||||
|
M(thread_scm_noreturn, reinstate_continuation_x, "reinstate-continuation!", REINSTATE_CONTINUATION_X) \
|
||||||
/* Add new intrinsics here; also update scm_bootstrap_intrinsics. */
|
/* Add new intrinsics here; also update scm_bootstrap_intrinsics. */
|
||||||
|
|
||||||
enum scm_vm_intrinsic
|
enum scm_vm_intrinsic
|
||||||
|
|
|
@ -650,7 +650,7 @@ VM_NAME (scm_i_thread *thread, jmp_buf *registers, int resume)
|
||||||
|
|
||||||
ALLOC_FRAME (3);
|
ALLOC_FRAME (3);
|
||||||
SP_SET (1, ret);
|
SP_SET (1, ret);
|
||||||
SP_SET (0, scm_from_int (err));
|
SP_SET (0, scm_vm_intrinsics.s64_to_scm (err));
|
||||||
|
|
||||||
NEXT (1);
|
NEXT (1);
|
||||||
}
|
}
|
||||||
|
@ -674,12 +674,7 @@ VM_NAME (scm_i_thread *thread, jmp_buf *registers, int resume)
|
||||||
SCM_PROGRAM_FREE_VARIABLE_REF (FP_REF (0), contregs_idx);
|
SCM_PROGRAM_FREE_VARIABLE_REF (FP_REF (0), contregs_idx);
|
||||||
|
|
||||||
SYNC_IP ();
|
SYNC_IP ();
|
||||||
scm_i_check_continuation (contregs);
|
scm_vm_intrinsics.reinstate_continuation_x (thread, contregs);
|
||||||
vm_return_to_continuation (scm_i_contregs_vp (contregs),
|
|
||||||
scm_i_contregs_vm_cont (contregs),
|
|
||||||
FRAME_LOCALS_COUNT_FROM (1),
|
|
||||||
sp);
|
|
||||||
scm_i_reinstate_continuation (contregs);
|
|
||||||
|
|
||||||
/* no NEXT */
|
/* no NEXT */
|
||||||
abort ();
|
abort ();
|
||||||
|
|
128
libguile/vm.c
128
libguile/vm.c
|
@ -182,63 +182,6 @@ scm_i_vm_capture_stack (union scm_vm_stack_element *stack_top,
|
||||||
return scm_cell (scm_tc7_vm_cont, (scm_t_bits) p);
|
return scm_cell (scm_tc7_vm_cont, (scm_t_bits) p);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct return_to_continuation_data
|
|
||||||
{
|
|
||||||
struct scm_vm_cont *cp;
|
|
||||||
struct scm_vm *vp;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Called with the GC lock to prevent the stack marker from traversing a
|
|
||||||
stack in an inconsistent state. */
|
|
||||||
static void *
|
|
||||||
vm_return_to_continuation_inner (void *data_ptr)
|
|
||||||
{
|
|
||||||
struct return_to_continuation_data *data = data_ptr;
|
|
||||||
struct scm_vm *vp = data->vp;
|
|
||||||
struct scm_vm_cont *cp = data->cp;
|
|
||||||
|
|
||||||
/* We know that there is enough space for the continuation, because we
|
|
||||||
captured it in the past. However there may have been an expansion
|
|
||||||
since the capture, so we may have to re-link the frame
|
|
||||||
pointers. */
|
|
||||||
memcpy (vp->stack_top - cp->stack_size,
|
|
||||||
cp->stack_bottom,
|
|
||||||
cp->stack_size * sizeof (*cp->stack_bottom));
|
|
||||||
vp->fp = vp->stack_top - cp->fp_offset;
|
|
||||||
vm_restore_sp (vp, vp->stack_top - cp->stack_size);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
vm_return_to_continuation (struct scm_vm *vp, SCM cont, size_t n,
|
|
||||||
union scm_vm_stack_element *argv)
|
|
||||||
{
|
|
||||||
struct scm_vm_cont *cp;
|
|
||||||
union scm_vm_stack_element *argv_copy;
|
|
||||||
struct return_to_continuation_data data;
|
|
||||||
|
|
||||||
argv_copy = alloca (n * sizeof (*argv));
|
|
||||||
memcpy (argv_copy, argv, n * sizeof (*argv));
|
|
||||||
|
|
||||||
cp = SCM_VM_CONT_DATA (cont);
|
|
||||||
|
|
||||||
data.cp = cp;
|
|
||||||
data.vp = vp;
|
|
||||||
GC_call_with_alloc_lock (vm_return_to_continuation_inner, &data);
|
|
||||||
|
|
||||||
/* Now we have the continuation properly copied over. We just need to
|
|
||||||
copy on an empty frame and the return values, as the continuation
|
|
||||||
expects. */
|
|
||||||
vm_push_sp (vp, vp->sp - 3 - n);
|
|
||||||
vp->sp[n+2].as_scm = SCM_BOOL_F;
|
|
||||||
vp->sp[n+1].as_scm = SCM_BOOL_F;
|
|
||||||
vp->sp[n].as_scm = SCM_BOOL_F;
|
|
||||||
memcpy(vp->sp, argv_copy, n * sizeof (union scm_vm_stack_element));
|
|
||||||
|
|
||||||
vp->ip = cp->ra;
|
|
||||||
}
|
|
||||||
|
|
||||||
SCM
|
SCM
|
||||||
scm_i_capture_current_stack (void)
|
scm_i_capture_current_stack (void)
|
||||||
{
|
{
|
||||||
|
@ -1285,6 +1228,76 @@ push_interrupt_frame (scm_i_thread *thread)
|
||||||
SCM_FRAME_LOCAL (thread->vm.fp, 0) = proc;
|
SCM_FRAME_LOCAL (thread->vm.fp, 0) = proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct return_to_continuation_data
|
||||||
|
{
|
||||||
|
struct scm_vm_cont *cp;
|
||||||
|
struct scm_vm *vp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Called with the GC lock to prevent the stack marker from traversing a
|
||||||
|
stack in an inconsistent state. */
|
||||||
|
static void *
|
||||||
|
vm_return_to_continuation_inner (void *data_ptr)
|
||||||
|
{
|
||||||
|
struct return_to_continuation_data *data = data_ptr;
|
||||||
|
struct scm_vm *vp = data->vp;
|
||||||
|
struct scm_vm_cont *cp = data->cp;
|
||||||
|
|
||||||
|
/* We know that there is enough space for the continuation, because we
|
||||||
|
captured it in the past. However there may have been an expansion
|
||||||
|
since the capture, so we may have to re-link the frame
|
||||||
|
pointers. */
|
||||||
|
memcpy (vp->stack_top - cp->stack_size,
|
||||||
|
cp->stack_bottom,
|
||||||
|
cp->stack_size * sizeof (*cp->stack_bottom));
|
||||||
|
vp->fp = vp->stack_top - cp->fp_offset;
|
||||||
|
vm_restore_sp (vp, vp->stack_top - cp->stack_size);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reinstate_continuation_x (scm_i_thread *thread, SCM cont) SCM_NORETURN;
|
||||||
|
|
||||||
|
static void
|
||||||
|
reinstate_continuation_x (scm_i_thread *thread, SCM cont)
|
||||||
|
{
|
||||||
|
scm_t_contregs *continuation = scm_i_contregs (cont);
|
||||||
|
struct scm_vm *vp = &thread->vm;
|
||||||
|
struct scm_vm_cont *cp;
|
||||||
|
size_t n;
|
||||||
|
union scm_vm_stack_element *argv;
|
||||||
|
struct return_to_continuation_data data;
|
||||||
|
|
||||||
|
if (!scm_is_eq (continuation->root, thread->continuation_root))
|
||||||
|
scm_misc_error
|
||||||
|
("%continuation-call",
|
||||||
|
"invoking continuation would cross continuation barrier: ~A",
|
||||||
|
scm_list_1 (cont));
|
||||||
|
|
||||||
|
n = frame_locals_count (thread) - 1,
|
||||||
|
argv = alloca (n * sizeof (*argv));
|
||||||
|
memcpy (argv, vp->sp, n * sizeof (*argv));
|
||||||
|
|
||||||
|
cp = SCM_VM_CONT_DATA (continuation->vm_cont);
|
||||||
|
|
||||||
|
data.cp = cp;
|
||||||
|
data.vp = vp;
|
||||||
|
GC_call_with_alloc_lock (vm_return_to_continuation_inner, &data);
|
||||||
|
|
||||||
|
/* Now we have the continuation properly copied over. We just need to
|
||||||
|
copy on an empty frame and the return values, as the continuation
|
||||||
|
expects. */
|
||||||
|
vm_push_sp (vp, vp->sp - 3 - n);
|
||||||
|
vp->sp[n+2].as_scm = SCM_BOOL_F;
|
||||||
|
vp->sp[n+1].as_scm = SCM_BOOL_F;
|
||||||
|
vp->sp[n].as_scm = SCM_BOOL_F;
|
||||||
|
memcpy(vp->sp, argv, n * sizeof (union scm_vm_stack_element));
|
||||||
|
|
||||||
|
vp->ip = cp->ra;
|
||||||
|
|
||||||
|
scm_i_reinstate_continuation (cont);
|
||||||
|
}
|
||||||
|
|
||||||
SCM
|
SCM
|
||||||
scm_call_n (SCM proc, SCM *argv, size_t nargs)
|
scm_call_n (SCM proc, SCM *argv, size_t nargs)
|
||||||
{
|
{
|
||||||
|
@ -1628,6 +1641,7 @@ scm_bootstrap_vm (void)
|
||||||
scm_vm_intrinsics.compute_kwargs_npositional = compute_kwargs_npositional;
|
scm_vm_intrinsics.compute_kwargs_npositional = compute_kwargs_npositional;
|
||||||
scm_vm_intrinsics.bind_kwargs = bind_kwargs;
|
scm_vm_intrinsics.bind_kwargs = bind_kwargs;
|
||||||
scm_vm_intrinsics.push_interrupt_frame = push_interrupt_frame;
|
scm_vm_intrinsics.push_interrupt_frame = push_interrupt_frame;
|
||||||
|
scm_vm_intrinsics.reinstate_continuation_x = reinstate_continuation_x;
|
||||||
|
|
||||||
sym_vm_run = scm_from_latin1_symbol ("vm-run");
|
sym_vm_run = scm_from_latin1_symbol ("vm-run");
|
||||||
sym_vm_error = scm_from_latin1_symbol ("vm-error");
|
sym_vm_error = scm_from_latin1_symbol ("vm-error");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue