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