mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-16 16:50:21 +02:00
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.
This commit is contained in:
parent
269479e31f
commit
d8873dfe47
6 changed files with 142 additions and 107 deletions
|
@ -982,7 +982,13 @@ VM_DEFINE_INSTRUCTION (89, continuation_call, "continuation-call", 0, -1, 0)
|
|||
{
|
||||
SCM contregs;
|
||||
POP (contregs);
|
||||
scm_i_continuation_call (contregs, sp - (fp - 1), fp);
|
||||
|
||||
scm_i_check_continuation (contregs);
|
||||
vm_return_to_continuation (scm_i_contregs_vm (contregs),
|
||||
scm_i_contregs_vm_cont (contregs),
|
||||
sp - (fp - 1), fp);
|
||||
scm_i_reinstate_continuation (contregs);
|
||||
|
||||
/* no NEXT */
|
||||
abort ();
|
||||
}
|
||||
|
@ -1090,10 +1096,11 @@ VM_DEFINE_INSTRUCTION (63, tail_apply, "tail-apply", 1, -1, 1)
|
|||
VM_DEFINE_INSTRUCTION (64, call_cc, "call/cc", 0, 1, 1)
|
||||
{
|
||||
int first;
|
||||
SCM proc, cont;
|
||||
SCM proc, vm_cont, cont;
|
||||
POP (proc);
|
||||
SYNC_ALL ();
|
||||
cont = scm_i_make_continuation (&first, vm, capture_vm_cont (vp));
|
||||
vm_cont = vm_capture_continuation (vp->stack_base, fp, sp, ip, NULL);
|
||||
cont = scm_i_make_continuation (&first, vm, vm_cont);
|
||||
if (first)
|
||||
{
|
||||
PUSH ((SCM)fp); /* dynamic link */
|
||||
|
@ -1104,22 +1111,14 @@ VM_DEFINE_INSTRUCTION (64, call_cc, "call/cc", 0, 1, 1)
|
|||
nargs = 1;
|
||||
goto vm_call;
|
||||
}
|
||||
ASSERT (sp == vp->sp);
|
||||
ASSERT (fp == vp->fp);
|
||||
else if (SCM_VALUESP (cont))
|
||||
else
|
||||
{
|
||||
/* multiple values returned to continuation */
|
||||
SCM values;
|
||||
values = scm_struct_ref (cont, SCM_INUM0);
|
||||
if (scm_is_null (values))
|
||||
goto vm_error_no_values;
|
||||
/* non-tail context does not accept multiple values? */
|
||||
PUSH (SCM_CAR (values));
|
||||
NEXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
PUSH (cont);
|
||||
/* otherwise, the vm continuation was reinstated, and
|
||||
scm_i_vm_return_to_continuation pushed on one value. So pull our regs
|
||||
back down from the vp, and march on to the next instruction. */
|
||||
CACHE_REGISTER ();
|
||||
program = SCM_FRAME_PROGRAM (fp);
|
||||
CACHE_PROGRAM ();
|
||||
NEXT;
|
||||
}
|
||||
}
|
||||
|
@ -1127,12 +1126,17 @@ VM_DEFINE_INSTRUCTION (64, call_cc, "call/cc", 0, 1, 1)
|
|||
VM_DEFINE_INSTRUCTION (65, tail_call_cc, "tail-call/cc", 0, 1, 1)
|
||||
{
|
||||
int first;
|
||||
SCM proc, cont;
|
||||
SCM proc, vm_cont, cont;
|
||||
POP (proc);
|
||||
SYNC_ALL ();
|
||||
cont = scm_i_make_continuation (&first, vm, capture_vm_cont (vp));
|
||||
ASSERT (sp == vp->sp);
|
||||
ASSERT (fp == vp->fp);
|
||||
/* In contrast to call/cc, tail-call/cc captures the continuation without the
|
||||
stack frame. */
|
||||
vm_cont = vm_capture_continuation (vp->stack_base,
|
||||
SCM_FRAME_DYNAMIC_LINK (fp),
|
||||
SCM_FRAME_LOWER_ADDRESS (fp) - 1,
|
||||
SCM_FRAME_RETURN_ADDRESS (fp),
|
||||
SCM_FRAME_MV_RETURN_ADDRESS (fp));
|
||||
cont = scm_i_make_continuation (&first, vm, vm_cont);
|
||||
if (first)
|
||||
{
|
||||
PUSH (proc);
|
||||
|
@ -1140,19 +1144,14 @@ VM_DEFINE_INSTRUCTION (65, tail_call_cc, "tail-call/cc", 0, 1, 1)
|
|||
nargs = 1;
|
||||
goto vm_tail_call;
|
||||
}
|
||||
else if (SCM_VALUESP (cont))
|
||||
{
|
||||
/* multiple values returned to continuation */
|
||||
SCM values;
|
||||
values = scm_struct_ref (cont, SCM_INUM0);
|
||||
nvalues = scm_ilength (values);
|
||||
PUSH_LIST (values, scm_is_null);
|
||||
goto vm_return_values;
|
||||
}
|
||||
else
|
||||
{
|
||||
PUSH (cont);
|
||||
goto vm_return;
|
||||
/* Otherwise, cache regs and NEXT, as above. Invoking the continuation
|
||||
does a return from the frame, either to the RA or MVRA. */
|
||||
CACHE_REGISTER ();
|
||||
program = SCM_FRAME_PROGRAM (fp);
|
||||
CACHE_PROGRAM ();
|
||||
NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue