eval.c uses scm_i_call_with_current_continuation
[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"
ce212434 37#include "libguile/values.h"
9de87eea 38#include "libguile/eval.h"
bfffd258 39#include "libguile/vm.h"
1d1cae0e 40#include "libguile/instructions.h"
5f144b10 41
db4b4ca6 42#include "libguile/validate.h"
a0599745 43#include "libguile/continuations.h"
01c8a3dd 44
0f2d19dd
JB
45\f
46
1d1cae0e
AW
47static scm_t_bits tc16_continuation;
48#define SCM_CONTREGSP(x) SCM_TYP16_PREDICATE (tc16_continuation, x)
49
50#define SCM_CONTREGS(x) ((scm_t_contregs *) SCM_SMOB_DATA_1 (x))
51
52#define SCM_CONTINUATION_LENGTH(x) (SCM_CONTREGS (x)->num_stack_items)
53#define SCM_SET_CONTINUATION_LENGTH(x, n)\
54 (SCM_CONTREGS (x)->num_stack_items = (n))
55#define SCM_JMPBUF(x) ((SCM_CONTREGS (x))->jmpbuf)
56#define SCM_DYNENV(x) ((SCM_CONTREGS (x))->dynenv)
57#define SCM_THROW_VALUE(x) ((SCM_CONTREGS (x))->throw_value)
58#define SCM_CONTINUATION_ROOT(x) ((SCM_CONTREGS (x))->root)
59#define SCM_DFRAME(x) ((SCM_CONTREGS (x))->dframe)
60
61\f
62
63/* scm_make_continuation will return a procedure whose objcode contains an
64 instruction to reinstate the continuation. Here, as in gsubr.c and smob.c, we
65 define the form of that trampoline function.
0f2d19dd
JB
66 */
67
1d1cae0e 68#ifdef WORDS_BIGENDIAN
babfc7b2
AW
69#define OBJCODE_HEADER(main,meta) 0, 0, 0, main, 0, 0, 0, meta+8
70#define META_HEADER(meta) 0, 0, 0, meta, 0, 0, 0, 0
1d1cae0e 71#else
babfc7b2
AW
72#define OBJCODE_HEADER(main,meta) main, 0, 0, 0, meta+8, 0, 0, 0
73#define META_HEADER(meta) meta, 0, 0, 0, 0, 0, 0, 0
1d1cae0e
AW
74#endif
75
76#define ROUND_UP(len,align) (((len-1)|(align-1))+1)
77#define ALIGN_PTR(type,p,align) (type*)(ROUND_UP (((scm_t_bits)p), align))
78
79#ifdef SCM_ALIGNED
80#define SCM_DECLARE_STATIC_ALIGNED_ARRAY(type, sym)\
81static const type sym[]
82#define SCM_STATIC_ALIGNED_ARRAY(alignment, type, sym)\
83static SCM_ALIGNED (alignment) const type sym[]
84#else
85#define SCM_DECLARE_STATIC_ALIGNED_ARRAY(type, sym)\
86static type *sym
87#define SCM_STATIC_ALIGNED_ARRAY(alignment, type, sym) \
88SCM_SNARF_INIT(sym = scm_malloc (sizeof(sym##__unaligned) + alignment - 1); \
89 sym = ALIGN_PTR (type, sym, alignment); \
90 memcpy (sym, sym##__unaligned, sizeof(sym##__unaligned));) \
91static type *sym = NULL; \
92static const type sym##__unaligned[]
93#endif
94
95#define STATIC_OBJCODE_TAG \
96 SCM_PACK (scm_tc7_objcode | (SCM_F_OBJCODE_IS_STATIC << 8))
97
98#define SCM_STATIC_OBJCODE(sym) \
99 SCM_DECLARE_STATIC_ALIGNED_ARRAY (scm_t_uint8, sym##__bytecode); \
100 SCM_STATIC_ALIGNED_ARRAY (8, scm_t_cell, sym##__cells) = { \
101 { STATIC_OBJCODE_TAG, SCM_PACK (sym##__bytecode) }, \
102 { SCM_BOOL_F, SCM_PACK (0) } \
103 }; \
104 static const SCM sym = SCM_PACK (sym##__cells); \
105 SCM_STATIC_ALIGNED_ARRAY (8, scm_t_uint8, sym##__bytecode)
106
107
108SCM_STATIC_OBJCODE (cont_objcode) = {
109 /* This code is the same as in gsubr.c, except we use smob_call instead of
110 struct_call. */
babfc7b2 111 OBJCODE_HEADER (8, 19),
1d1cae0e
AW
112 /* leave args on the stack */
113 /* 0 */ scm_op_object_ref, 0, /* push scm_t_contregs smob */
114 /* 2 */ scm_op_continuation_call, /* and longjmp (whee) */
115 /* 3 */ scm_op_nop, /* pad to 8 bytes */
116 /* 4 */ scm_op_nop, scm_op_nop, scm_op_nop, scm_op_nop,
117 /* 8 */
118
119 /* We could put some meta-info to say that this proc is a continuation. Not sure
120 how to do that, though. */
babfc7b2 121 META_HEADER (19),
1d1cae0e
AW
122 /* 0 */ scm_op_make_eol, /* bindings */
123 /* 1 */ scm_op_make_eol, /* sources */
124 /* 2 */ scm_op_make_int8, 0, scm_op_make_int8, 3, /* arity: from ip 0 to ip 3 */
125 /* 6 */ scm_op_make_int8_0, /* the arity is 0 required args */
126 /* 7 */ scm_op_make_int8_0, /* 0 optionals */
127 /* 8 */ scm_op_make_true, /* and a rest arg */
128 /* 9 */ scm_op_list, 0, 5, /* make a list of those 5 vals */
129 /* 12 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */
130 /* 15 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */
131 /* 18 */ scm_op_return /* and return */
132 /* 19 */
133};
134
135
babfc7b2
AW
136SCM_STATIC_OBJCODE (call_cc_objcode) = {
137 /* Before Scheme's call/cc is compiled, eval.c will use this hand-coded
138 call/cc. */
139 OBJCODE_HEADER (8, 17),
140 /* 0 */ scm_op_assert_nargs_ee, 0, 1, /* assert that nargs==1 */
141 /* 3 */ scm_op_local_ref, 0, /* push the proc */
142 /* 5 */ scm_op_tail_call_cc, /* and call/cc */
143 /* 6 */ scm_op_nop, scm_op_nop, /* pad to 8 bytes */
144 /* 8 */
145
146 META_HEADER (17),
147 /* 0 */ scm_op_make_eol, /* bindings */
148 /* 1 */ scm_op_make_eol, /* sources */
149 /* 2 */ scm_op_make_int8, 3, scm_op_make_int8, 6, /* arity: from ip 0 to ip 6 */
150 /* 6 */ scm_op_make_int8_1, /* the arity is 0 required args */
151 /* 7 */ scm_op_list, 0, 3, /* make a list of those 5 vals */
152 /* 10 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */
153 /* 13 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */
154 /* 16 */ scm_op_return /* and return */
155 /* 17 */
156};
157
158
1d1cae0e
AW
159static SCM
160make_continuation_trampoline (SCM contregs)
161{
162 SCM ret = scm_make_program (cont_objcode,
163 scm_c_make_vector (1, contregs),
164 SCM_BOOL_F);
165 SCM_SET_CELL_WORD_0 (ret,
166 SCM_CELL_WORD_0 (ret) | SCM_F_PROGRAM_IS_CONTINUATION);
167
168 return ret;
169}
170
171
172/* {Continuations}
173 */
0f2d19dd 174
01c8a3dd 175
e841c3e0 176static int
e81d98ec 177continuation_print (SCM obj, SCM port, scm_print_state *state SCM_UNUSED)
5f144b10 178{
92c2555f 179 scm_t_contregs *continuation = SCM_CONTREGS (obj);
5f144b10
GH
180
181 scm_puts ("#<continuation ", port);
182 scm_intprint (continuation->num_stack_items, 10, port);
183 scm_puts (" @ ", port);
0236bc68 184 scm_uintprint (SCM_SMOB_DATA_1 (obj), 16, port);
5f144b10
GH
185 scm_putc ('>', port);
186 return 1;
187}
1cc91f1b 188
5f144b10
GH
189/* this may return more than once: the first time with the escape
190 procedure, then subsequently with the value to be passed to the
191 continuation. */
192#define FUNC_NAME "scm_make_continuation"
0f2d19dd 193SCM
5f144b10 194scm_make_continuation (int *first)
0f2d19dd 195{
9de87eea
MV
196 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
197 SCM cont;
92c2555f 198 scm_t_contregs *continuation;
c014a02e 199 long stack_size;
01c8a3dd 200 SCM_STACKITEM * src;
0f2d19dd 201
0f2d19dd 202 SCM_FLUSH_REGISTER_WINDOWS;
9de87eea 203 stack_size = scm_stack_size (thread->continuation_base);
4c9419ac
MV
204 continuation = scm_gc_malloc (sizeof (scm_t_contregs)
205 + (stack_size - 1) * sizeof (SCM_STACKITEM),
206 "continuation");
5f144b10 207 continuation->num_stack_items = stack_size;
9de87eea 208 continuation->dynenv = scm_i_dynwinds ();
5f144b10 209 continuation->throw_value = SCM_EOL;
9de87eea 210 continuation->root = thread->continuation_root;
9de87eea 211 src = thread->continuation_base;
4ccb2cd2 212#if ! SCM_STACK_GROWS_UP
5f144b10
GH
213 src -= stack_size;
214#endif
5c5c27dc 215 continuation->offset = continuation->stack - src;
5f144b10 216 memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size);
bfffd258 217 continuation->vm_conts = scm_vm_capture_continuations ();
5f144b10 218
1d1cae0e 219 SCM_NEWSMOB (cont, tc16_continuation, continuation);
79824460 220
a4dbe1ac 221 *first = !SCM_I_SETJMP (continuation->jmpbuf);
346e4402 222 if (*first)
193297d8 223 {
346e4402 224#ifdef __ia64__
9a5fa6e9 225 continuation->backing_store_size =
346e4402 226 (char *) scm_ia64_ar_bsp(&continuation->jmpbuf.ctx)
9a5fa6e9 227 -
346e4402 228 (char *) thread->register_backing_store_base;
193297d8
RB
229 continuation->backing_store = NULL;
230 continuation->backing_store =
4c9419ac
MV
231 scm_gc_malloc (continuation->backing_store_size,
232 "continuation backing store");
193297d8 233 memcpy (continuation->backing_store,
346e4402 234 (void *) thread->register_backing_store_base,
193297d8 235 continuation->backing_store_size);
346e4402 236#endif /* __ia64__ */
1d1cae0e 237 return make_continuation_trampoline (cont);
193297d8
RB
238 }
239 else
240 {
3c468478 241 SCM ret = continuation->throw_value;
3c468478
MV
242 continuation->throw_value = SCM_BOOL_F;
243 return ret;
5f144b10 244 }
0f2d19dd 245}
5f144b10 246#undef FUNC_NAME
0f2d19dd 247
babfc7b2
AW
248SCM
249scm_i_call_with_current_continuation (SCM proc)
250{
251 static SCM call_cc = SCM_BOOL_F;
252
253 if (scm_is_false (call_cc))
254 call_cc = scm_make_program (call_cc_objcode, SCM_BOOL_F, SCM_BOOL_F);
255
256 return scm_call_1 (call_cc, proc);
257}
258
1d1cae0e
AW
259SCM
260scm_i_continuation_to_frame (SCM continuation)
261{
262 SCM contregs;
263 scm_t_contregs *cont;
264
265 contregs = scm_c_vector_ref (scm_program_objects (continuation), 0);
266 cont = SCM_CONTREGS (contregs);
267
268 if (!scm_is_null (cont->vm_conts))
269 {
270 SCM vm_cont;
271 struct scm_vm_cont *data;
272 vm_cont = scm_cdr (scm_car (cont->vm_conts));
273 data = SCM_VM_CONT_DATA (vm_cont);
274 return scm_c_make_frame (vm_cont,
275 data->fp + data->reloc,
276 data->sp + data->reloc,
277 data->ip,
278 data->reloc);
279 }
280 else
281 return SCM_BOOL_F;
282}
283
284
285/* {Apply}
286 */
d3c6aef9
MV
287
288/* Invoking a continuation proceeds as follows:
289 *
290 * - the stack is made large enough for the called continuation
291 * - the old windchain is unwound down to the branching point
292 * - the continuation stack is copied into place
293 * - the windchain is rewound up to the continuation's context
294 * - the continuation is invoked via longjmp (or setcontext)
295 *
296 * This order is important so that unwind and rewind handlers are run
297 * with their correct stack.
298 */
299
5f144b10 300static void scm_dynthrow (SCM, SCM);
01c8a3dd
DH
301
302/* Grow the stack by a fixed amount to provide space to copy in the
303 * continuation. Possibly this function has to be called several times
304 * recursively before enough space is available. Make sure the compiler does
305 * not optimize the growth array away by storing it's address into a global
306 * variable.
307 */
308
92c2555f 309scm_t_bits scm_i_dummy;
1cc91f1b 310
0f2d19dd 311static void
01c8a3dd
DH
312grow_stack (SCM cont, SCM val)
313{
92c2555f 314 scm_t_bits growth[100];
01c8a3dd 315
92c2555f 316 scm_i_dummy = (scm_t_bits) growth;
01c8a3dd 317 scm_dynthrow (cont, val);
0f2d19dd 318}
0f2d19dd 319
1cc91f1b 320
01c8a3dd
DH
321/* Copy the continuation stack into the current stack. Calling functions from
322 * within this function is safe, since only stack frames below this function's
323 * own frame are overwritten. Thus, memcpy can be used for best performance.
324 */
d3c6aef9
MV
325
326typedef struct {
327 scm_t_contregs *continuation;
328 SCM_STACKITEM *dst;
329} copy_stack_data;
330
01c8a3dd 331static void
d3c6aef9
MV
332copy_stack (void *data)
333{
334 copy_stack_data *d = (copy_stack_data *)data;
335 memcpy (d->dst, d->continuation->stack,
336 sizeof (SCM_STACKITEM) * d->continuation->num_stack_items);
bfffd258 337 scm_vm_reinstate_continuations (d->continuation->vm_conts);
346e4402
NJ
338#ifdef __ia64__
339 SCM_I_CURRENT_THREAD->pending_rbs_continuation = d->continuation;
340#endif
d3c6aef9
MV
341}
342
343static void
344copy_stack_and_call (scm_t_contregs *continuation, SCM val,
5f144b10 345 SCM_STACKITEM * dst)
0f2d19dd 346{
d3c6aef9
MV
347 long delta;
348 copy_stack_data data;
349
9de87eea 350 delta = scm_ilength (scm_i_dynwinds ()) - scm_ilength (continuation->dynenv);
d3c6aef9
MV
351 data.continuation = continuation;
352 data.dst = dst;
14578fa4 353 scm_i_dowinds (continuation->dynenv, delta, copy_stack, &data);
01c8a3dd 354
5f144b10 355 continuation->throw_value = val;
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
381scm_dynthrow (SCM cont, SCM val)
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)
01c8a3dd 396 grow_stack (cont, val);
0f2d19dd 397#else
5f144b10 398 dst -= continuation->num_stack_items;
c8a1bdc4 399 if (dst <= &stack_top_element)
01c8a3dd 400 grow_stack (cont, val);
0f2d19dd 401#endif /* def SCM_STACK_GROWS_UP */
01c8a3dd 402
5f144b10
GH
403 SCM_FLUSH_REGISTER_WINDOWS;
404 copy_stack_and_call (continuation, val, dst);
0f2d19dd
JB
405}
406
db4b4ca6 407
1d1cae0e
AW
408void
409scm_i_continuation_call (SCM cont, size_t n, SCM *argv)
0f2d19dd 410{
9de87eea 411 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
92c2555f 412 scm_t_contregs *continuation = SCM_CONTREGS (cont);
1d1cae0e
AW
413 SCM args = SCM_EOL;
414
415 /* FIXME: shuffle args on VM stack instead of heap-allocating */
416 while (n--)
417 args = scm_cons (argv[n], args);
5f144b10 418
9de87eea 419 if (continuation->root != thread->continuation_root)
1d1cae0e
AW
420 scm_misc_error
421 ("%continuation-call",
422 "invoking continuation would cross continuation barrier: ~A",
423 scm_list_1 (cont));
0f2d19dd 424
ce212434 425 scm_dynthrow (cont, scm_values (args));
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*/