diff options
author | Andy Wingo <wingo@pobox.com> | 2010-02-08 22:59:25 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2010-02-08 22:59:25 +0100 |
commit | d8873dfe4754daf031a6709738bd31afa8edb443 (patch) | |
tree | dbad856934bd9069258d0db8e010f9a9a556ef69 /libguile/vm.c | |
parent | 269479e31f70d40a82b75be87c1b2a7363c85696 (diff) | |
download | guile-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.c | 107 |
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 |