memoize (begin foo) to foo
[bpt/guile.git] / libguile / continuations.c
CommitLineData
1d1cae0e 1/* Copyright (C) 1995,1996,1998,2000,2001,2004, 2006, 2008, 2009, 2010 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
0f2d19dd 24
bbd43f03
RB
25#include "libguile/_scm.h"
26
13070bd3 27#include <string.h>
8b7f0bb3 28#include <stdio.h>
13070bd3 29
8b7f0bb3 30#include "libguile/async.h"
d0f6ceb8 31#include "libguile/debug.h"
a0599745
MD
32#include "libguile/root.h"
33#include "libguile/stackchk.h"
5f144b10
GH
34#include "libguile/smob.h"
35#include "libguile/ports.h"
36#include "libguile/dynwind.h"
9de87eea 37#include "libguile/eval.h"
bfffd258 38#include "libguile/vm.h"
1d1cae0e 39#include "libguile/instructions.h"
5f144b10 40
db4b4ca6 41#include "libguile/validate.h"
a0599745 42#include "libguile/continuations.h"
01c8a3dd 43
0f2d19dd
JB
44\f
45
1d1cae0e
AW
46static scm_t_bits tc16_continuation;
47#define SCM_CONTREGSP(x) SCM_TYP16_PREDICATE (tc16_continuation, x)
48
49#define SCM_CONTREGS(x) ((scm_t_contregs *) SCM_SMOB_DATA_1 (x))
50
51#define SCM_CONTINUATION_LENGTH(x) (SCM_CONTREGS (x)->num_stack_items)
52#define SCM_SET_CONTINUATION_LENGTH(x, n)\
53 (SCM_CONTREGS (x)->num_stack_items = (n))
54#define SCM_JMPBUF(x) ((SCM_CONTREGS (x))->jmpbuf)
55#define SCM_DYNENV(x) ((SCM_CONTREGS (x))->dynenv)
1d1cae0e
AW
56#define SCM_CONTINUATION_ROOT(x) ((SCM_CONTREGS (x))->root)
57#define SCM_DFRAME(x) ((SCM_CONTREGS (x))->dframe)
58
59\f
60
997659f8 61/* scm_i_make_continuation will return a procedure whose objcode contains an
1d1cae0e
AW
62 instruction to reinstate the continuation. Here, as in gsubr.c and smob.c, we
63 define the form of that trampoline function.
0f2d19dd
JB
64 */
65
1d1cae0e 66#ifdef WORDS_BIGENDIAN
babfc7b2
AW
67#define OBJCODE_HEADER(main,meta) 0, 0, 0, main, 0, 0, 0, meta+8
68#define META_HEADER(meta) 0, 0, 0, meta, 0, 0, 0, 0
1d1cae0e 69#else
babfc7b2
AW
70#define OBJCODE_HEADER(main,meta) main, 0, 0, 0, meta+8, 0, 0, 0
71#define META_HEADER(meta) meta, 0, 0, 0, 0, 0, 0, 0
1d1cae0e
AW
72#endif
73
74#define ROUND_UP(len,align) (((len-1)|(align-1))+1)
75#define ALIGN_PTR(type,p,align) (type*)(ROUND_UP (((scm_t_bits)p), align))
76
77#ifdef SCM_ALIGNED
78#define SCM_DECLARE_STATIC_ALIGNED_ARRAY(type, sym)\
79static const type sym[]
80#define SCM_STATIC_ALIGNED_ARRAY(alignment, type, sym)\
81static SCM_ALIGNED (alignment) const type sym[]
82#else
83#define SCM_DECLARE_STATIC_ALIGNED_ARRAY(type, sym)\
84static type *sym
85#define SCM_STATIC_ALIGNED_ARRAY(alignment, type, sym) \
86SCM_SNARF_INIT(sym = scm_malloc (sizeof(sym##__unaligned) + alignment - 1); \
87 sym = ALIGN_PTR (type, sym, alignment); \
88 memcpy (sym, sym##__unaligned, sizeof(sym##__unaligned));) \
89static type *sym = NULL; \
90static const type sym##__unaligned[]
91#endif
92
93#define STATIC_OBJCODE_TAG \
94 SCM_PACK (scm_tc7_objcode | (SCM_F_OBJCODE_IS_STATIC << 8))
95
96#define SCM_STATIC_OBJCODE(sym) \
97 SCM_DECLARE_STATIC_ALIGNED_ARRAY (scm_t_uint8, sym##__bytecode); \
98 SCM_STATIC_ALIGNED_ARRAY (8, scm_t_cell, sym##__cells) = { \
99 { STATIC_OBJCODE_TAG, SCM_PACK (sym##__bytecode) }, \
100 { SCM_BOOL_F, SCM_PACK (0) } \
101 }; \
102 static const SCM sym = SCM_PACK (sym##__cells); \
103 SCM_STATIC_ALIGNED_ARRAY (8, scm_t_uint8, sym##__bytecode)
104
105
106SCM_STATIC_OBJCODE (cont_objcode) = {
107 /* This code is the same as in gsubr.c, except we use smob_call instead of
108 struct_call. */
babfc7b2 109 OBJCODE_HEADER (8, 19),
1d1cae0e
AW
110 /* leave args on the stack */
111 /* 0 */ scm_op_object_ref, 0, /* push scm_t_contregs smob */
112 /* 2 */ scm_op_continuation_call, /* and longjmp (whee) */
113 /* 3 */ scm_op_nop, /* pad to 8 bytes */
114 /* 4 */ scm_op_nop, scm_op_nop, scm_op_nop, scm_op_nop,
115 /* 8 */
116
117 /* We could put some meta-info to say that this proc is a continuation. Not sure
118 how to do that, though. */
babfc7b2 119 META_HEADER (19),
1d1cae0e
AW
120 /* 0 */ scm_op_make_eol, /* bindings */
121 /* 1 */ scm_op_make_eol, /* sources */
122 /* 2 */ scm_op_make_int8, 0, scm_op_make_int8, 3, /* arity: from ip 0 to ip 3 */
123 /* 6 */ scm_op_make_int8_0, /* the arity is 0 required args */
124 /* 7 */ scm_op_make_int8_0, /* 0 optionals */
125 /* 8 */ scm_op_make_true, /* and a rest arg */
126 /* 9 */ scm_op_list, 0, 5, /* make a list of those 5 vals */
127 /* 12 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */
128 /* 15 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */
129 /* 18 */ scm_op_return /* and return */
130 /* 19 */
131};
132
133
babfc7b2
AW
134SCM_STATIC_OBJCODE (call_cc_objcode) = {
135 /* Before Scheme's call/cc is compiled, eval.c will use this hand-coded
136 call/cc. */
137 OBJCODE_HEADER (8, 17),
138 /* 0 */ scm_op_assert_nargs_ee, 0, 1, /* assert that nargs==1 */
139 /* 3 */ scm_op_local_ref, 0, /* push the proc */
140 /* 5 */ scm_op_tail_call_cc, /* and call/cc */
141 /* 6 */ scm_op_nop, scm_op_nop, /* pad to 8 bytes */
142 /* 8 */
143
144 META_HEADER (17),
145 /* 0 */ scm_op_make_eol, /* bindings */
146 /* 1 */ scm_op_make_eol, /* sources */
147 /* 2 */ scm_op_make_int8, 3, scm_op_make_int8, 6, /* arity: from ip 0 to ip 6 */
148 /* 6 */ scm_op_make_int8_1, /* the arity is 0 required args */
149 /* 7 */ scm_op_list, 0, 3, /* make a list of those 5 vals */
150 /* 10 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */
151 /* 13 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */
152 /* 16 */ scm_op_return /* and return */
153 /* 17 */
154};
155
156
1d1cae0e
AW
157static SCM
158make_continuation_trampoline (SCM contregs)
159{
160 SCM ret = scm_make_program (cont_objcode,
161 scm_c_make_vector (1, contregs),
162 SCM_BOOL_F);
163 SCM_SET_CELL_WORD_0 (ret,
164 SCM_CELL_WORD_0 (ret) | SCM_F_PROGRAM_IS_CONTINUATION);
165
166 return ret;
167}
168
169
170/* {Continuations}
171 */
0f2d19dd 172
01c8a3dd 173
e841c3e0 174static int
e81d98ec 175continuation_print (SCM obj, SCM port, scm_print_state *state SCM_UNUSED)
5f144b10 176{
92c2555f 177 scm_t_contregs *continuation = SCM_CONTREGS (obj);
5f144b10
GH
178
179 scm_puts ("#<continuation ", port);
180 scm_intprint (continuation->num_stack_items, 10, port);
181 scm_puts (" @ ", port);
0236bc68 182 scm_uintprint (SCM_SMOB_DATA_1 (obj), 16, port);
5f144b10
GH
183 scm_putc ('>', port);
184 return 1;
185}
1cc91f1b 186
5f144b10 187/* this may return more than once: the first time with the escape
d8873dfe
AW
188 procedure, then subsequently with SCM_UNDEFINED (the vals already having been
189 placed on the VM stack). */
997659f8 190#define FUNC_NAME "scm_i_make_continuation"
0f2d19dd 191SCM
269479e3 192scm_i_make_continuation (int *first, SCM vm, SCM vm_cont)
0f2d19dd 193{
9de87eea
MV
194 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
195 SCM cont;
92c2555f 196 scm_t_contregs *continuation;
c014a02e 197 long stack_size;
01c8a3dd 198 SCM_STACKITEM * src;
0f2d19dd 199
0f2d19dd 200 SCM_FLUSH_REGISTER_WINDOWS;
9de87eea 201 stack_size = scm_stack_size (thread->continuation_base);
4c9419ac
MV
202 continuation = scm_gc_malloc (sizeof (scm_t_contregs)
203 + (stack_size - 1) * sizeof (SCM_STACKITEM),
204 "continuation");
5f144b10 205 continuation->num_stack_items = stack_size;
9de87eea 206 continuation->dynenv = scm_i_dynwinds ();
9de87eea 207 continuation->root = thread->continuation_root;
9de87eea 208 src = thread->continuation_base;
4ccb2cd2 209#if ! SCM_STACK_GROWS_UP
5f144b10
GH
210 src -= stack_size;
211#endif
5c5c27dc 212 continuation->offset = continuation->stack - src;
5f144b10 213 memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size);
269479e3
AW
214 continuation->vm = vm;
215 continuation->vm_cont = vm_cont;
5f144b10 216
1d1cae0e 217 SCM_NEWSMOB (cont, tc16_continuation, continuation);
79824460 218
a4dbe1ac 219 *first = !SCM_I_SETJMP (continuation->jmpbuf);
346e4402 220 if (*first)
193297d8 221 {
346e4402 222#ifdef __ia64__
9a5fa6e9 223 continuation->backing_store_size =
346e4402 224 (char *) scm_ia64_ar_bsp(&continuation->jmpbuf.ctx)
9a5fa6e9 225 -
346e4402 226 (char *) thread->register_backing_store_base;
193297d8
RB
227 continuation->backing_store = NULL;
228 continuation->backing_store =
4c9419ac
MV
229 scm_gc_malloc (continuation->backing_store_size,
230 "continuation backing store");
193297d8 231 memcpy (continuation->backing_store,
346e4402 232 (void *) thread->register_backing_store_base,
193297d8 233 continuation->backing_store_size);
346e4402 234#endif /* __ia64__ */
1d1cae0e 235 return make_continuation_trampoline (cont);
193297d8
RB
236 }
237 else
d8873dfe 238 return SCM_UNDEFINED;
0f2d19dd 239}
5f144b10 240#undef FUNC_NAME
0f2d19dd 241
babfc7b2
AW
242SCM
243scm_i_call_with_current_continuation (SCM proc)
244{
245 static SCM call_cc = SCM_BOOL_F;
246
247 if (scm_is_false (call_cc))
248 call_cc = scm_make_program (call_cc_objcode, SCM_BOOL_F, SCM_BOOL_F);
249
250 return scm_call_1 (call_cc, proc);
251}
252
1d1cae0e
AW
253SCM
254scm_i_continuation_to_frame (SCM continuation)
255{
256 SCM contregs;
257 scm_t_contregs *cont;
258
259 contregs = scm_c_vector_ref (scm_program_objects (continuation), 0);
260 cont = SCM_CONTREGS (contregs);
261
269479e3 262 if (scm_is_true (cont->vm_cont))
1d1cae0e 263 {
269479e3
AW
264 struct scm_vm_cont *data = SCM_VM_CONT_DATA (cont->vm_cont);
265 return scm_c_make_frame (cont->vm_cont,
1d1cae0e
AW
266 data->fp + data->reloc,
267 data->sp + data->reloc,
d8873dfe 268 data->ra,
1d1cae0e
AW
269 data->reloc);
270 }
271 else
272 return SCM_BOOL_F;
273}
274
d8873dfe
AW
275SCM
276scm_i_contregs_vm (SCM contregs)
277{
278 return SCM_CONTREGS (contregs)->vm;
279}
280
281SCM
282scm_i_contregs_vm_cont (SCM contregs)
283{
284 return SCM_CONTREGS (contregs)->vm_cont;
285}
286
1d1cae0e
AW
287
288/* {Apply}
289 */
d3c6aef9
MV
290
291/* Invoking a continuation proceeds as follows:
292 *
293 * - the stack is made large enough for the called continuation
294 * - the old windchain is unwound down to the branching point
295 * - the continuation stack is copied into place
296 * - the windchain is rewound up to the continuation's context
297 * - the continuation is invoked via longjmp (or setcontext)
298 *
299 * This order is important so that unwind and rewind handlers are run
300 * with their correct stack.
301 */
302
d8873dfe 303static void scm_dynthrow (SCM);
01c8a3dd
DH
304
305/* Grow the stack by a fixed amount to provide space to copy in the
306 * continuation. Possibly this function has to be called several times
307 * recursively before enough space is available. Make sure the compiler does
308 * not optimize the growth array away by storing it's address into a global
309 * variable.
310 */
311
92c2555f 312scm_t_bits scm_i_dummy;
1cc91f1b 313
0f2d19dd 314static void
d8873dfe 315grow_stack (SCM cont)
01c8a3dd 316{
92c2555f 317 scm_t_bits growth[100];
01c8a3dd 318
92c2555f 319 scm_i_dummy = (scm_t_bits) growth;
d8873dfe 320 scm_dynthrow (cont);
0f2d19dd 321}
0f2d19dd 322
1cc91f1b 323
01c8a3dd
DH
324/* Copy the continuation stack into the current stack. Calling functions from
325 * within this function is safe, since only stack frames below this function's
326 * own frame are overwritten. Thus, memcpy can be used for best performance.
327 */
d3c6aef9
MV
328
329typedef struct {
330 scm_t_contregs *continuation;
331 SCM_STACKITEM *dst;
332} copy_stack_data;
333
01c8a3dd 334static void
d3c6aef9
MV
335copy_stack (void *data)
336{
337 copy_stack_data *d = (copy_stack_data *)data;
338 memcpy (d->dst, d->continuation->stack,
339 sizeof (SCM_STACKITEM) * d->continuation->num_stack_items);
346e4402
NJ
340#ifdef __ia64__
341 SCM_I_CURRENT_THREAD->pending_rbs_continuation = d->continuation;
342#endif
d3c6aef9
MV
343}
344
345static void
d8873dfe 346copy_stack_and_call (scm_t_contregs *continuation,
5f144b10 347 SCM_STACKITEM * dst)
0f2d19dd 348{
d3c6aef9
MV
349 long delta;
350 copy_stack_data data;
351
9de87eea 352 delta = scm_ilength (scm_i_dynwinds ()) - scm_ilength (continuation->dynenv);
d3c6aef9
MV
353 data.continuation = continuation;
354 data.dst = dst;
14578fa4 355 scm_i_dowinds (continuation->dynenv, delta, copy_stack, &data);
01c8a3dd 356
a4dbe1ac 357 SCM_I_LONGJMP (continuation->jmpbuf, 1);
01c8a3dd
DH
358}
359
346e4402
NJ
360#ifdef __ia64__
361void
a4dbe1ac 362scm_ia64_longjmp (scm_i_jmp_buf *JB, int VAL)
346e4402
NJ
363{
364 scm_i_thread *t = SCM_I_CURRENT_THREAD;
365
366 if (t->pending_rbs_continuation)
367 {
368 memcpy (t->register_backing_store_base,
369 t->pending_rbs_continuation->backing_store,
370 t->pending_rbs_continuation->backing_store_size);
371 t->pending_rbs_continuation = NULL;
372 }
373 setcontext (&JB->ctx);
374}
375#endif
376
01c8a3dd
DH
377/* Call grow_stack until the stack space is large enough, then, as the current
378 * stack frame might get overwritten, let copy_stack_and_call perform the
379 * actual copying and continuation calling.
380 */
381static void
d8873dfe 382scm_dynthrow (SCM cont)
01c8a3dd 383{
9de87eea 384 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
92c2555f 385 scm_t_contregs *continuation = SCM_CONTREGS (cont);
9de87eea 386 SCM_STACKITEM *dst = thread->continuation_base;
01c8a3dd
DH
387 SCM_STACKITEM stack_top_element;
388
87f30eda 389 if (thread->critical_section_level)
8b7f0bb3
MV
390 {
391 fprintf (stderr, "continuation invoked from within critical section.\n");
392 abort ();
393 }
394
4ccb2cd2 395#if SCM_STACK_GROWS_UP
5afcf08b 396 if (dst + continuation->num_stack_items >= &stack_top_element)
d8873dfe 397 grow_stack (cont);
0f2d19dd 398#else
5f144b10 399 dst -= continuation->num_stack_items;
c8a1bdc4 400 if (dst <= &stack_top_element)
d8873dfe 401 grow_stack (cont);
0f2d19dd 402#endif /* def SCM_STACK_GROWS_UP */
01c8a3dd 403
5f144b10 404 SCM_FLUSH_REGISTER_WINDOWS;
d8873dfe 405 copy_stack_and_call (continuation, dst);
0f2d19dd
JB
406}
407
db4b4ca6 408
1d1cae0e 409void
d8873dfe 410scm_i_check_continuation (SCM cont)
0f2d19dd 411{
9de87eea 412 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
92c2555f 413 scm_t_contregs *continuation = SCM_CONTREGS (cont);
5f144b10 414
9de87eea 415 if (continuation->root != thread->continuation_root)
1d1cae0e
AW
416 scm_misc_error
417 ("%continuation-call",
418 "invoking continuation would cross continuation barrier: ~A",
419 scm_list_1 (cont));
d8873dfe
AW
420}
421
422void
423scm_i_reinstate_continuation (SCM cont)
424{
425 scm_dynthrow (cont);
0f2d19dd 426}
0f2d19dd 427
9de87eea
MV
428SCM
429scm_i_with_continuation_barrier (scm_t_catch_body body,
430 void *body_data,
431 scm_t_catch_handler handler,
43e01b1e
NJ
432 void *handler_data,
433 scm_t_catch_handler pre_unwind_handler,
434 void *pre_unwind_handler_data)
9de87eea
MV
435{
436 SCM_STACKITEM stack_item;
437 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
438 SCM old_controot;
439 SCM_STACKITEM *old_contbase;
9de87eea
MV
440 SCM result;
441
442 /* Establish a fresh continuation root.
443 */
444 old_controot = thread->continuation_root;
445 old_contbase = thread->continuation_base;
9de87eea
MV
446 thread->continuation_root = scm_cons (thread->handle, old_controot);
447 thread->continuation_base = &stack_item;
9de87eea
MV
448
449 /* Call FUNC inside a catch all. This is now guaranteed to return
450 directly and exactly once.
451 */
43e01b1e
NJ
452 result = scm_c_catch (SCM_BOOL_T,
453 body, body_data,
454 handler, handler_data,
455 pre_unwind_handler, pre_unwind_handler_data);
9de87eea
MV
456
457 /* Return to old continuation root.
458 */
9de87eea
MV
459 thread->continuation_base = old_contbase;
460 thread->continuation_root = old_controot;
461
462 return result;
463}
464
465struct c_data {
466 void *(*func) (void *);
467 void *data;
468 void *result;
469};
470
471static SCM
472c_body (void *d)
473{
474 struct c_data *data = (struct c_data *)d;
475 data->result = data->func (data->data);
476 return SCM_UNSPECIFIED;
477}
478
479static SCM
480c_handler (void *d, SCM tag, SCM args)
481{
482 struct c_data *data = (struct c_data *)d;
9de87eea
MV
483 data->result = NULL;
484 return SCM_UNSPECIFIED;
485}
486
487void *
488scm_c_with_continuation_barrier (void *(*func) (void *), void *data)
489{
490 struct c_data c_data;
491 c_data.func = func;
492 c_data.data = data;
493 scm_i_with_continuation_barrier (c_body, &c_data,
43e01b1e
NJ
494 c_handler, &c_data,
495 scm_handle_by_message_noexit, NULL);
9de87eea
MV
496 return c_data.result;
497}
498
499struct scm_data {
500 SCM proc;
501};
502
503static SCM
504scm_body (void *d)
505{
506 struct scm_data *data = (struct scm_data *)d;
507 return scm_call_0 (data->proc);
508}
509
510static SCM
511scm_handler (void *d, SCM tag, SCM args)
512{
9de87eea
MV
513 return SCM_BOOL_F;
514}
515
516SCM_DEFINE (scm_with_continuation_barrier, "with-continuation-barrier", 1,0,0,
517 (SCM proc),
69d2000d
MV
518"Call @var{proc} and return its result. Do not allow the invocation of\n"
519"continuations that would leave or enter the dynamic extent of the call\n"
520"to @code{with-continuation-barrier}. Such an attempt causes an error\n"
521"to be signaled.\n"
522"\n"
523"Throws (such as errors) that are not caught from within @var{proc} are\n"
524"caught by @code{with-continuation-barrier}. In that case, a short\n"
525"message is printed to the current error port and @code{#f} is returned.\n"
526"\n"
527"Thus, @code{with-continuation-barrier} returns exactly once.\n")
9de87eea
MV
528#define FUNC_NAME s_scm_with_continuation_barrier
529{
530 struct scm_data scm_data;
531 scm_data.proc = proc;
532 return scm_i_with_continuation_barrier (scm_body, &scm_data,
43e01b1e
NJ
533 scm_handler, &scm_data,
534 scm_handle_by_message_noexit, NULL);
9de87eea
MV
535}
536#undef FUNC_NAME
db4b4ca6 537
0f2d19dd
JB
538void
539scm_init_continuations ()
0f2d19dd 540{
1d1cae0e
AW
541 tc16_continuation = scm_make_smob_type ("continuation", 0);
542 scm_set_smob_print (tc16_continuation, continuation_print);
a0599745 543#include "libguile/continuations.x"
0f2d19dd
JB
544}
545
89e00824
ML
546/*
547 Local Variables:
548 c-file-style: "gnu"
549 End:
550*/