diff options
Diffstat (limited to 'libguile/continuations.c')
-rw-r--r-- | libguile/continuations.c | 209 |
1 files changed, 59 insertions, 150 deletions
diff --git a/libguile/continuations.c b/libguile/continuations.c index d9912783d..1d677610b 100644 --- a/libguile/continuations.c +++ b/libguile/continuations.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1995,1996,1998,2000,2001,2004, 2006, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +/* Copyright (C) 1995,1996,1998,2000,2001,2004, 2006, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -24,6 +24,7 @@ #include "libguile/_scm.h" +#include <assert.h> #include <string.h> #include <stdio.h> @@ -33,7 +34,7 @@ #include "libguile/stackchk.h" #include "libguile/smob.h" #include "libguile/ports.h" -#include "libguile/dynwind.h" +#include "libguile/dynstack.h" #include "libguile/eval.h" #include "libguile/vm.h" #include "libguile/instructions.h" @@ -52,113 +53,31 @@ static scm_t_bits tc16_continuation; #define SCM_SET_CONTINUATION_LENGTH(x, n)\ (SCM_CONTREGS (x)->num_stack_items = (n)) #define SCM_JMPBUF(x) ((SCM_CONTREGS (x))->jmpbuf) -#define SCM_DYNENV(x) ((SCM_CONTREGS (x))->dynenv) #define SCM_CONTINUATION_ROOT(x) ((SCM_CONTREGS (x))->root) #define SCM_DFRAME(x) ((SCM_CONTREGS (x))->dframe) -/* scm_i_make_continuation will return a procedure whose objcode contains an - instruction to reinstate the continuation. Here, as in gsubr.c and smob.c, we - define the form of that trampoline function. +/* scm_i_make_continuation will return a procedure whose code will + reinstate the continuation. Here, as in gsubr.c, we define the form + of that trampoline function. */ -#ifdef WORDS_BIGENDIAN -#define OBJCODE_HEADER(main,meta) 0, 0, 0, main, 0, 0, 0, meta+8 -#define META_HEADER(meta) 0, 0, 0, meta, 0, 0, 0, 0 -#else -#define OBJCODE_HEADER(main,meta) main, 0, 0, 0, meta+8, 0, 0, 0 -#define META_HEADER(meta) meta, 0, 0, 0, 0, 0, 0, 0 -#endif - -#define OBJCODE_TAG SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_STATIC, 0) - -#if defined (SCM_ALIGNED) && 0 -#define SCM_DECLARE_STATIC_ALIGNED_ARRAY(type, sym) \ -static const type sym[] -#define SCM_STATIC_ALIGNED_ARRAY(alignment, type, sym) \ -static SCM_ALIGNED (alignment) const type sym[] -#define SCM_STATIC_OBJCODE(sym) \ - SCM_DECLARE_STATIC_ALIGNED_ARRAY (scm_t_uint8, sym##__bytecode); \ - SCM_STATIC_ALIGNED_ARRAY (8, scm_t_cell, sym##__cells) = { \ - { SCM_PACK (OBJCODE_TAG), SCM_PACK (sym##__bytecode) }, \ - { SCM_BOOL_F, SCM_PACK (0) } \ - }; \ - static const SCM sym = SCM_PACK (sym##__cells); \ - SCM_STATIC_ALIGNED_ARRAY (8, scm_t_uint8, sym##__bytecode) -#else -#define SCM_STATIC_OBJCODE(sym) \ -static SCM sym; \ -static scm_t_uint8 *sym##_bytecode; \ -SCM_SNARF_INIT(sym##_bytecode = scm_gc_malloc_pointerless (sizeof(sym##_bytecode__unaligned), "partial continuation stub"); \ - memcpy (sym##_bytecode, sym##_bytecode__unaligned, sizeof(sym##_bytecode__unaligned));) \ -SCM_SNARF_INIT(sym = scm_double_cell (OBJCODE_TAG, \ - (scm_t_bits)sym##_bytecode, \ - SCM_UNPACK (SCM_BOOL_F), \ - 0);) \ -static const scm_t_uint8 sym##_bytecode__unaligned[] -#endif - - -SCM_STATIC_OBJCODE (cont_objcode) = { - /* This code is the same as in gsubr.c, except we use continuation_call - instead of subr_call. */ - OBJCODE_HEADER (8, 19), - /* leave args on the stack */ - /* 0 */ scm_op_object_ref, 0, /* push scm_t_contregs smob */ - /* 2 */ scm_op_continuation_call, /* and longjmp (whee) */ - /* 3 */ scm_op_nop, /* pad to 8 bytes */ - /* 4 */ scm_op_nop, scm_op_nop, scm_op_nop, scm_op_nop, - /* 8 */ - - /* We could put some meta-info to say that this proc is a continuation. Not sure - how to do that, though. */ - META_HEADER (19), - /* 0 */ scm_op_make_eol, /* bindings */ - /* 1 */ scm_op_make_eol, /* sources */ - /* 2 */ scm_op_make_int8, 0, scm_op_make_int8, 3, /* arity: from ip 0 to ip 3 */ - /* 6 */ scm_op_make_int8_0, /* the arity is 0 required args */ - /* 7 */ scm_op_make_int8_0, /* 0 optionals */ - /* 8 */ scm_op_make_true, /* and a rest arg */ - /* 9 */ scm_op_list, 0, 5, /* make a list of those 5 vals */ - /* 12 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */ - /* 15 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */ - /* 18 */ scm_op_return /* and return */ - /* 19 */ -}; - - -SCM_STATIC_OBJCODE (call_cc_objcode) = { - /* Before Scheme's call/cc is compiled, eval.c will use this hand-coded - call/cc. */ - OBJCODE_HEADER (8, 17), - /* 0 */ scm_op_assert_nargs_ee, 0, 1, /* assert that nargs==1 */ - /* 3 */ scm_op_local_ref, 0, /* push the proc */ - /* 5 */ scm_op_tail_call_cc, /* and call/cc */ - /* 6 */ scm_op_nop, scm_op_nop, /* pad to 8 bytes */ - /* 8 */ - - META_HEADER (17), - /* 0 */ scm_op_make_eol, /* bindings */ - /* 1 */ scm_op_make_eol, /* sources */ - /* 2 */ scm_op_make_int8, 3, scm_op_make_int8, 6, /* arity: from ip 0 to ip 6 */ - /* 6 */ scm_op_make_int8_1, /* the arity is 0 required args */ - /* 7 */ scm_op_list, 0, 3, /* make a list of those 5 vals */ - /* 10 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */ - /* 13 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */ - /* 16 */ scm_op_return /* and return */ - /* 17 */ -}; - +static const scm_t_uint32 continuation_stub_code[] = + { + SCM_PACK_OP_24 (continuation_call, 0) + }; static SCM make_continuation_trampoline (SCM contregs) { - SCM ret = scm_make_program (cont_objcode, - scm_c_make_vector (1, contregs), - SCM_BOOL_F); - SCM_SET_CELL_WORD_0 (ret, - SCM_CELL_WORD_0 (ret) | SCM_F_PROGRAM_IS_CONTINUATION); + SCM ret; + scm_t_bits nfree = 1; + scm_t_bits flags = SCM_F_PROGRAM_IS_CONTINUATION; + + ret = scm_words (scm_tc7_program | (nfree << 16) | flags, nfree + 2); + SCM_SET_CELL_WORD_1 (ret, continuation_stub_code); + SCM_PROGRAM_FREE_VARIABLE_SET (ret, 0, contregs); return ret; } @@ -173,20 +92,31 @@ continuation_print (SCM obj, SCM port, scm_print_state *state SCM_UNUSED) { scm_t_contregs *continuation = SCM_CONTREGS (obj); - scm_puts ("#<continuation ", port); + scm_puts_unlocked ("#<continuation ", port); scm_intprint (continuation->num_stack_items, 10, port); - scm_puts (" @ ", port); + scm_puts_unlocked (" @ ", port); scm_uintprint (SCM_SMOB_DATA_1 (obj), 16, port); - scm_putc ('>', port); + scm_putc_unlocked ('>', port); return 1; } +/* James Clark came up with this neat one instruction fix for + * continuations on the SPARC. It flushes the register windows so + * that all the state of the process is contained in the stack. + */ + +#if defined (sparc) || defined (__sparc__) || defined (__sparc) +# define SCM_FLUSH_REGISTER_WINDOWS asm("ta 3") +#else +# define SCM_FLUSH_REGISTER_WINDOWS /* empty */ +#endif + /* this may return more than once: the first time with the escape procedure, then subsequently with SCM_UNDEFINED (the vals already having been placed on the VM stack). */ #define FUNC_NAME "scm_i_make_continuation" SCM -scm_i_make_continuation (int *first, SCM vm, SCM vm_cont) +scm_i_make_continuation (int *first, struct scm_vm *vp, SCM vm_cont) { scm_i_thread *thread = SCM_I_CURRENT_THREAD; SCM cont; @@ -200,7 +130,6 @@ scm_i_make_continuation (int *first, SCM vm, SCM vm_cont) + (stack_size - 1) * sizeof (SCM_STACKITEM), "continuation"); continuation->num_stack_items = stack_size; - continuation->dynenv = scm_i_dynwinds (); continuation->root = thread->continuation_root; src = thread->continuation_base; #if ! SCM_STACK_GROWS_UP @@ -208,7 +137,7 @@ scm_i_make_continuation (int *first, SCM vm, SCM vm_cont) #endif continuation->offset = continuation->stack - src; memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size); - continuation->vm = vm; + continuation->vp = vp; continuation->vm_cont = vm_cont; SCM_NEWSMOB (cont, tc16_continuation, continuation); @@ -237,42 +166,30 @@ scm_i_make_continuation (int *first, SCM vm, SCM vm_cont) #undef FUNC_NAME SCM -scm_i_call_with_current_continuation (SCM proc) -{ - static SCM call_cc = SCM_BOOL_F; - - if (scm_is_false (call_cc)) - call_cc = scm_make_program (call_cc_objcode, SCM_BOOL_F, SCM_BOOL_F); - - return scm_call_1 (call_cc, proc); -} - -SCM scm_i_continuation_to_frame (SCM continuation) { SCM contregs; scm_t_contregs *cont; - contregs = scm_c_vector_ref (scm_program_objects (continuation), 0); + contregs = SCM_PROGRAM_FREE_VARIABLE_REF (continuation, 0); cont = SCM_CONTREGS (contregs); if (scm_is_true (cont->vm_cont)) { struct scm_vm_cont *data = SCM_VM_CONT_DATA (cont->vm_cont); - return scm_c_make_frame (cont->vm_cont, - data->fp + data->reloc, - data->sp + data->reloc, - data->ra, - data->reloc); + return scm_c_make_frame (SCM_VM_FRAME_KIND_CONT, data, + (data->fp + data->reloc) - data->stack_base, + (data->sp + data->reloc) - data->stack_base, + data->ra); } else return SCM_BOOL_F; } -SCM -scm_i_contregs_vm (SCM contregs) +struct scm_vm * +scm_i_contregs_vp (SCM contregs) { - return SCM_CONTREGS (contregs)->vm; + return SCM_CONTREGS (contregs)->vp; } SCM @@ -323,33 +240,25 @@ grow_stack (SCM cont) * own frame are overwritten. Thus, memcpy can be used for best performance. */ -typedef struct { - scm_t_contregs *continuation; - SCM_STACKITEM *dst; -} copy_stack_data; - -static void -copy_stack (void *data) -{ - copy_stack_data *d = (copy_stack_data *)data; - memcpy (d->dst, d->continuation->stack, - sizeof (SCM_STACKITEM) * d->continuation->num_stack_items); -#ifdef __ia64__ - SCM_I_CURRENT_THREAD->pending_rbs_continuation = d->continuation; -#endif -} - static void copy_stack_and_call (scm_t_contregs *continuation, SCM_STACKITEM * dst) { - long delta; - copy_stack_data data; + scm_t_dynstack *dynstack; + scm_t_bits *joint; + scm_i_thread *thread = SCM_I_CURRENT_THREAD; + + dynstack = SCM_VM_CONT_DATA (continuation->vm_cont)->dynstack; + + joint = scm_dynstack_unwind_fork (&thread->dynstack, dynstack); + + memcpy (dst, continuation->stack, + sizeof (SCM_STACKITEM) * continuation->num_stack_items); +#ifdef __ia64__ + thread->pending_rbs_continuation = continuation; +#endif - delta = scm_ilength (scm_i_dynwinds ()) - scm_ilength (continuation->dynenv); - data.continuation = continuation; - data.dst = dst; - scm_i_dowinds (continuation->dynenv, delta, copy_stack, &data); + scm_dynstack_wind (&thread->dynstack, joint); SCM_I_LONGJMP (continuation->jmpbuf, 1); } @@ -486,7 +395,7 @@ print_exception_and_backtrace (SCM port, SCM tag, SCM args) if (should_print_backtrace (tag, stack)) { - scm_puts ("Backtrace:\n", port); + scm_puts_unlocked ("Backtrace:\n", port); scm_display_backtrace_with_highlights (stack, port, SCM_BOOL_F, SCM_BOOL_F, SCM_EOL); @@ -531,7 +440,7 @@ pre_unwind_handler (void *error_port, SCM tag, SCM args) { /* Print the exception unless TAG is `quit'. */ if (!scm_is_eq (tag, scm_from_latin1_symbol ("quit"))) - print_exception_and_backtrace (PTR2SCM (error_port), tag, args); + print_exception_and_backtrace (SCM_PACK_POINTER (error_port), tag, args); return SCM_UNSPECIFIED; } @@ -545,7 +454,7 @@ scm_c_with_continuation_barrier (void *(*func) (void *), void *data) scm_i_with_continuation_barrier (c_body, &c_data, c_handler, &c_data, pre_unwind_handler, - SCM2PTR (scm_current_error_port ())); + SCM_UNPACK_POINTER (scm_current_error_port ())); return c_data.result; } @@ -589,7 +498,7 @@ SCM_DEFINE (scm_with_continuation_barrier, "with-continuation-barrier", 1,0,0, return scm_i_with_continuation_barrier (scm_body, &scm_data, scm_handler, &scm_data, pre_unwind_handler, - SCM2PTR (scm_current_error_port ())); + SCM_UNPACK_POINTER (scm_current_error_port ())); } #undef FUNC_NAME |