diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-11-05 05:25:21 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-11-05 05:25:21 -0800 |
commit | 33719b3b1101faef84ca091540caffb652b9d0dd (patch) | |
tree | 03a82844d9b5d9d130325b72ae0d61d196fe7386 /unwind.h | |
parent | 7deb862ac8925c4ced0246adbd79b353b88512d8 (diff) | |
download | txr-33719b3b1101faef84ca091540caffb652b9d0dd.tar.gz txr-33719b3b1101faef84ca091540caffb652b9d0dd.tar.bz2 txr-33719b3b1101faef84ca091540caffb652b9d0dd.zip |
Copy envs for middle-of-binding continuations.
When continuations are captured/restored in the middle of
variable binding constructs, a hidden problem occurs.
Binding constructs work by allocating an empty environment
and then destructively extending it. Since the environment
is not on the stack, but a referenced object, it doesn't
get deep copied into a continuation. As the continuation is
revived repeatedly, parts of the variable binding code are
repeatedly re-executed, and keep pushing fresh bindings into
the same environment object. Though the new bindings
correctly shadow the old, the old bindings are there and
potentially hang on to garbage.
The solution taken here is to introduce a new kind of frame
for handling the situation: a continuation copy handling
frame. This frame allows functions to register objects to
be copied more deeply if a continuation is captured/revived
across them.
* eval.c (copy_env): New static function.
(copy_env_handler): New static function.
(bind_args, bind_macro_params): Install continuation copy
handling frame for cloning new_env.
(struct bindings_helper_vars): New struct type.
(copy_bh_env_handler): New static function.
(bindings_helper): Install continuation copy handling frame
for de and ne variables which hold environments. The variables
are moved to a struct to facilitate access from the handler.
* eval.h (copy_env): Declared.
* unwind.c (uw_push_cont_copy): New function.
(call_copy_handler): New static function.
(revive_cont): When a continuation is being revived invoke the
copying actions in its continuation copy handling frames,
but not if it is only being temporarily revived for immediate
unwinding.
(capture_cont): After copying the continuation, invoke any
continuation copying frames in the "parent": the original
frames that were captured.
* unwind.h (enum uw_frtype): New type, UW_CONT_COPY.
(struct uw_cont_copy): New struct type.
(union uw_frame): New member cp.
(uw_push_cont_copy): Declared.
Diffstat (limited to 'unwind.h')
-rw-r--r-- | unwind.h | 13 |
1 files changed, 12 insertions, 1 deletions
@@ -26,7 +26,8 @@ typedef union uw_frame uw_frame_t; typedef enum uw_frtype { - UW_BLOCK, UW_CAPTURED_BLOCK, UW_ENV, UW_CATCH, UW_HANDLE, UW_DBG + UW_BLOCK, UW_CAPTURED_BLOCK, UW_ENV, UW_CATCH, UW_HANDLE, + UW_CONT_COPY, UW_DBG } uw_frtype_t; struct uw_common { @@ -70,6 +71,13 @@ struct uw_handler { val fun; }; +struct uw_cont_copy { + uw_frame_t *up; + uw_frtype_t type; + mem_t *ptr; + void (*copy)(mem_t *ptr, int parent); +}; + struct uw_debug { uw_frame_t *up; uw_frtype_t type; @@ -88,6 +96,7 @@ union uw_frame { struct uw_dynamic_env ev; struct uw_catch ca; struct uw_handler ha; + struct uw_cont_copy cp; struct uw_debug db; }; @@ -126,6 +135,8 @@ val uw_get_frames(void); val uw_find_frame(val extype, val frtype); val uw_invoke_catch(val catch_frame, val sym, struct args *); val uw_capture_cont(val tag, val fun, val ctx_form); +void uw_push_cont_copy(uw_frame_t *, mem_t *ptr, + void (*copy)(mem_t *ptr, int parent)); void uw_init(void); void uw_late_init(void); |