summaryrefslogtreecommitdiff
path: root/libguile/vm.c
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2010-02-08 22:59:25 +0100
committerAndy Wingo <wingo@pobox.com>2010-02-08 22:59:25 +0100
commitd8873dfe4754daf031a6709738bd31afa8edb443 (patch)
treedbad856934bd9069258d0db8e010f9a9a556ef69 /libguile/vm.c
parent269479e31f70d40a82b75be87c1b2a7363c85696 (diff)
downloadguile-d8873dfe4754daf031a6709738bd31afa8edb443.tar.gz
continuations return multiple values on the stack
* libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
Diffstat (limited to 'libguile/vm.c')
-rw-r--r--libguile/vm.c107
1 files changed, 70 insertions, 37 deletions
diff --git a/libguile/vm.c b/libguile/vm.c
index 425e57ed5..66d89a4fe 100644
--- a/libguile/vm.c
+++ b/libguile/vm.c
@@ -80,72 +80,105 @@ scm_i_vm_cont_print (SCM x, SCM port, scm_print_state *pstate)
scm_puts (">", port);
}
+/* In theory, a number of vm instances can be active in the call trace, and we
+ only want to reify the continuations of those in the current continuation
+ root. I don't see a nice way to do this -- ideally it would involve dynwinds,
+ and previous values of the *the-vm* fluid within the current continuation
+ root. But we don't have access to continuation roots in the dynwind stack.
+ So, just punt for now, we just capture the continuation for the current VM.
+
+ While I'm on the topic, ideally we could avoid copying the C stack if the
+ continuation root is inside VM code, and call/cc was invoked within that same
+ call to vm_run; but that's currently not implemented.
+ */
static SCM
-capture_vm_cont (struct scm_vm *vp)
+vm_capture_continuation (SCM *stack_base,
+ SCM *fp, SCM *sp, scm_t_uint8 *ra, scm_t_uint8 *mvra)
{
- struct scm_vm_cont *p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
- p->stack_size = vp->sp - vp->stack_base + 1;
+ struct scm_vm_cont *p;
+
+ p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
+ p->stack_size = sp - stack_base + 1;
p->stack_base = scm_gc_malloc (p->stack_size * sizeof (SCM),
"capture_vm_cont");
-#ifdef VM_ENABLE_STACK_NULLING
- if (vp->sp >= vp->stack_base)
+#if defined(VM_ENABLE_STACK_NULLING) && 0
+ /* Tail continuations leave their frame on the stack for subsequent
+ application, but don't capture the frame -- so there are some elements on
+ the stack then, and this check doesn't work, so disable it for now. */
+ if (sp >= vp->stack_base)
if (!vp->sp[0] || vp->sp[1])
abort ();
memset (p->stack_base, 0, p->stack_size * sizeof (SCM));
#endif
- p->ip = vp->ip;
- p->sp = vp->sp;
- p->fp = vp->fp;
- memcpy (p->stack_base, vp->stack_base, p->stack_size * sizeof (SCM));
- p->reloc = p->stack_base - vp->stack_base;
+ p->ra = ra;
+ p->mvra = mvra;
+ p->sp = sp;
+ p->fp = fp;
+ memcpy (p->stack_base, stack_base, (sp + 1 - stack_base) * sizeof (SCM));
+ p->reloc = p->stack_base - stack_base;
return scm_cell (scm_tc7_vm_cont, (scm_t_bits)p);
}
static void
-reinstate_vm_cont (struct scm_vm *vp, SCM cont)
+vm_return_to_continuation (SCM vm, SCM cont, size_t n, SCM *argv)
{
- struct scm_vm_cont *p = SCM_VM_CONT_DATA (cont);
- if (vp->stack_size < p->stack_size)
+ struct scm_vm *vp;
+ struct scm_vm_cont *cp;
+ SCM *argv_copy;
+
+ argv_copy = alloca (n * sizeof(SCM));
+ memcpy (argv_copy, argv, n * sizeof(SCM));
+
+ vp = SCM_VM_DATA (vm);
+ cp = SCM_VM_CONT_DATA (cont);
+
+ if (n == 0 && !cp->mvra)
+ scm_misc_error (NULL, "Too few values returned to continuation",
+ SCM_EOL);
+
+ if (vp->stack_size < cp->stack_size + n + 1)
{
/* puts ("FIXME: Need to expand"); */
abort ();
}
#ifdef VM_ENABLE_STACK_NULLING
{
- scm_t_ptrdiff nzero = (vp->sp - p->sp);
+ scm_t_ptrdiff nzero = (vp->sp - cp->sp);
if (nzero > 0)
- memset (vp->stack_base + p->stack_size, 0, nzero * sizeof (SCM));
+ memset (vp->stack_base + cp->stack_size, 0, nzero * sizeof (SCM));
/* actually nzero should always be negative, because vm_reset_stack will
unwind the stack to some point *below* this continuation */
}
#endif
- vp->ip = p->ip;
- vp->sp = p->sp;
- vp->fp = p->fp;
- memcpy (vp->stack_base, p->stack_base, p->stack_size * sizeof (SCM));
-}
+ vp->sp = cp->sp;
+ vp->fp = cp->fp;
+ memcpy (vp->stack_base, cp->stack_base, cp->stack_size * sizeof (SCM));
-/* In theory, a number of vm instances can be active in the call trace, and we
- only want to reify the continuations of those in the current continuation
- root. I don't see a nice way to do this -- ideally it would involve dynwinds,
- and previous values of the *the-vm* fluid within the current continuation
- root. But we don't have access to continuation roots in the dynwind stack.
- So, just punt for now -- take the current value of *the-vm*.
+ if (n == 1 || !cp->mvra)
+ {
+ vp->ip = cp->ra;
+ vp->sp++;
+ *vp->sp = argv_copy[0];
+ }
+ else
+ {
+ size_t i;
+ for (i = 0; i < n; i++)
+ {
+ vp->sp++;
+ *vp->sp = argv_copy[i];
+ }
+ vp->sp++;
+ *vp->sp = scm_from_size_t (n);
+ vp->ip = cp->mvra;
+ }
+}
- While I'm on the topic, ideally we could avoid copying the C stack if the
- continuation root is inside VM code, and call/cc was invoked within that same
- call to vm_run; but that's currently not implemented.
- */
SCM
scm_i_vm_capture_continuation (SCM vm)
{
- return capture_vm_cont (SCM_VM_DATA (vm));
-}
-
-void
-scm_i_vm_reinstate_continuation (SCM vm, SCM cont)
-{
- reinstate_vm_cont (SCM_VM_DATA (vm), cont);
+ struct scm_vm *vp = SCM_VM_DATA (vm);
+ return vm_capture_continuation (vp->stack_base, vp->fp, vp->sp, vp->ip, NULL);
}
static void