From d691ac206906d2539cb94667fd10854aafc8955a Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Fri, 18 Oct 2013 18:44:11 +0200 Subject: [PATCH] Continuations are RTL stubs * libguile/continuations.h: * libguile/continuations.c: Reimplement continuations and the call_cc stub as RTL programs. * libguile/programs.c (scm_i_rtl_program_minimum_arity): Add a case for continuations. * libguile/vm-engine.c (rtl_vm_debug_engine): Always call the abort continuation hook with the number of non-procedure locals. Fix compose-continuation argument count. Enable call/cc. --- libguile/continuations.c | 120 ++++++++------------------------------- libguile/continuations.h | 4 +- libguile/programs.c | 7 +++ libguile/vm-engine.c | 45 +++++++++------ 4 files changed, 61 insertions(+), 115 deletions(-) diff --git a/libguile/continuations.c b/libguile/continuations.c index fe7618f5e..58a193618 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 @@ -58,107 +58,35 @@ static scm_t_bits tc16_continuation; -/* 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 +static const scm_t_uint32 continuation_stub_code[] = + { + SCM_PACK_RTL_24 (scm_rtl_op_continuation_call, 0) + }; -#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 */ -}; +/* Before Scheme's call/cc is compiled, eval.c will use this hand-coded + call/cc. */ +static const scm_t_uint32 call_cc_code[] = + { + SCM_PACK_RTL_24 (scm_rtl_op_assert_nargs_ee, 2), + SCM_PACK_RTL_24 (scm_rtl_op_call_cc, 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_rtl_program | (nfree << 16) | flags, nfree + 2); + SCM_SET_CELL_WORD_1 (ret, continuation_stub_code); + SCM_RTL_PROGRAM_FREE_VARIABLE_SET (ret, 0, contregs); return ret; } @@ -252,7 +180,7 @@ 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); + call_cc = scm_i_make_rtl_program (call_cc_code); return scm_call_1 (call_cc, proc); } @@ -263,7 +191,7 @@ 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_RTL_PROGRAM_FREE_VARIABLE_REF (continuation, 0); cont = SCM_CONTREGS (contregs); if (scm_is_true (cont->vm_cont)) diff --git a/libguile/continuations.h b/libguile/continuations.h index 29ea1c1a1..e7fa16d9c 100644 --- a/libguile/continuations.h +++ b/libguile/continuations.h @@ -3,7 +3,7 @@ #ifndef SCM_CONTINUATIONS_H #define SCM_CONTINUATIONS_H -/* Copyright (C) 1995,1996,2000,2001, 2006, 2008, 2009, 2010, 2012 Free Software Foundation, Inc. +/* Copyright (C) 1995,1996,2000,2001, 2006, 2008, 2009, 2010, 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 @@ -32,7 +32,7 @@ #define SCM_CONTINUATIONP(x) \ - (SCM_PROGRAM_P (x) && SCM_PROGRAM_IS_CONTINUATION (x)) + (SCM_RTL_PROGRAM_P (x) && SCM_PROGRAM_IS_CONTINUATION (x)) /* a continuation SCM is a non-immediate pointing to a heap cell with: word 0: bits 0-15: smob type tag: scm_tc16_continuation. diff --git a/libguile/programs.c b/libguile/programs.c index a88c48b0d..a0decdd91 100644 --- a/libguile/programs.c +++ b/libguile/programs.c @@ -527,6 +527,13 @@ scm_i_rtl_program_minimum_arity (SCM program, int *req, int *opt, int *rest) if (SCM_PROGRAM_IS_FOREIGN (program)) return scm_i_foreign_arity (program, req, opt, rest); + if (SCM_PROGRAM_IS_CONTINUATION (program)) + { + *req = *opt = 0; + *rest = 1; + return 1; + } + if (scm_is_false (rtl_program_minimum_arity) && scm_module_system_booted_p) rtl_program_minimum_arity = scm_c_private_variable ("system vm program", diff --git a/libguile/vm-engine.c b/libguile/vm-engine.c index 095f0bcc8..e2f8745eb 100644 --- a/libguile/vm-engine.c +++ b/libguile/vm-engine.c @@ -849,7 +849,7 @@ RTL_VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_) to pull all our state back from the ip/fp/sp. */ CACHE_REGISTER (); - ABORT_CONTINUATION_HOOK (fp, FRAME_LOCALS_COUNT()); + ABORT_CONTINUATION_HOOK (fp, FRAME_LOCALS_COUNT () - 1); NEXT (0); } @@ -1252,7 +1252,7 @@ RTL_VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_) scm_i_check_continuation (contregs); vm_return_to_continuation (scm_i_contregs_vm (contregs), scm_i_contregs_vm_cont (contregs), - FRAME_LOCALS_COUNT (), fp); + FRAME_LOCALS_COUNT () - 1, fp); scm_i_reinstate_continuation (contregs); /* no NEXT */ @@ -1278,7 +1278,7 @@ RTL_VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_) SYNC_IP (); VM_ASSERT (SCM_VM_CONT_REWINDABLE_P (vmcont), vm_error_continuation_not_rewindable (vmcont)); - vm_reinstate_partial_continuation (vm, vmcont, FRAME_LOCALS_COUNT (), fp, + vm_reinstate_partial_continuation (vm, vmcont, FRAME_LOCALS_COUNT () - 1, fp, ¤t_thread->dynstack, ®isters); CACHE_REGISTER (); @@ -1333,14 +1333,14 @@ RTL_VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_) /* call/cc _:24 * * Capture the current continuation, and tail-apply the procedure in - * local slot 0 to it. This instruction is part of the implementation + * local slot 1 to it. This instruction is part of the implementation * of `call/cc', and is not generated by the compiler. */ VM_DEFINE_OP (12, call_cc, "call/cc", OP1 (U8_X24)) -#if 0 { SCM vm_cont, cont; scm_t_dynstack *dynstack; + int first; VM_HANDLE_INTERRUPTS; @@ -1353,23 +1353,34 @@ RTL_VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_) SCM_FRAME_MV_RETURN_ADDRESS (fp), dynstack, 0); - cont = scm_i_make_continuation (®isters, vm, vm_cont); + /* FIXME: Seems silly to capture the registers here, when they are + already captured in the registers local, which here we are + copying out to the heap; and likewise, the setjmp(®isters) + code already has the non-local return handler. But oh + well! */ + cont = scm_i_make_continuation (&first, vm, vm_cont); - fp[-1] = fp[0]; - fp[0] = cont; - RESET_FRAME (2); + if (first) + { + LOCAL_SET (0, LOCAL_REF (1)); + LOCAL_SET (1, cont); + RESET_FRAME (2); - APPLY_HOOK (); + APPLY_HOOK (); - if (SCM_UNLIKELY (!SCM_RTL_PROGRAM_P (SCM_FRAME_PROGRAM (fp)))) - goto apply; + if (SCM_UNLIKELY (!SCM_RTL_PROGRAM_P (SCM_FRAME_PROGRAM (fp)))) + goto apply; - ip = SCM_RTL_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp)); - NEXT (0); + ip = SCM_RTL_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp)); + NEXT (0); + } + else + { + CACHE_REGISTER (); + ABORT_CONTINUATION_HOOK (fp, FRAME_LOCALS_COUNT () - 1); + NEXT (0); + } } -#else - abort(); -#endif