From 951af56540ce995cf8526bf1671c5964ba06116b Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 14:53:09 +0900 Subject: [PATCH 01/13] publish struct pic_escape --- cont.c | 17 ----------------- include/picrin/cont.h | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cont.c b/cont.c index 8ee36b33..496503cc 100644 --- a/cont.c +++ b/cont.c @@ -57,23 +57,6 @@ pic_dynamic_wind(pic_state *pic, struct pic_proc *in, struct pic_proc *thunk, st return val; } -struct pic_escape { - jmp_buf jmp; - - bool valid; - - struct pic_winder *wind; - - ptrdiff_t sp_offset; - ptrdiff_t ci_offset; - ptrdiff_t xp_offset; - int arena_idx; - - pic_code *ip; - - pic_value results; -}; - static int save_point(pic_state *pic, struct pic_escape *escape) { diff --git a/include/picrin/cont.h b/include/picrin/cont.h index c0868f79..f49d6595 100644 --- a/include/picrin/cont.h +++ b/include/picrin/cont.h @@ -9,6 +9,23 @@ extern "C" { #endif +struct pic_escape { + jmp_buf jmp; + + bool valid; + + struct pic_winder *wind; + + ptrdiff_t sp_offset; + ptrdiff_t ci_offset; + ptrdiff_t xp_offset; + int arena_idx; + + pic_code *ip; + + pic_value results; +}; + void pic_wind(pic_state *, struct pic_winder *, struct pic_winder *); pic_value pic_dynamic_wind(pic_state *, struct pic_proc *, struct pic_proc *, struct pic_proc *); From 07f24db66f02c3e7e138dc323111fc5bde985567 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 14:57:49 +0900 Subject: [PATCH 02/13] add make_escape --- cont.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/cont.c b/cont.c index 496503cc..1066dd89 100644 --- a/cont.c +++ b/cont.c @@ -109,10 +109,26 @@ escape_call(pic_state *pic) load_point(pic, e->data); } +static struct pic_proc * +make_escape(pic_state *pic, struct pic_escape *escape) +{ + static const pic_data_type escape_type = { "escape", pic_free, NULL }; + struct pic_proc *cont; + struct pic_data *e; + + cont = pic_make_proc(pic, escape_call, ""); + + e = pic_data_alloc(pic, &escape_type, escape); + + /* save the escape continuation in proc */ + pic_attr_set(pic, cont, "@@escape", pic_obj_value(e)); + + return cont; +} + pic_value pic_escape(pic_state *pic, struct pic_proc *proc) { - static const pic_data_type escape_type = { "escape", pic_free, NULL }; struct pic_escape *escape; escape = pic_alloc(pic, sizeof(struct pic_escape)); @@ -121,18 +137,9 @@ pic_escape(pic_state *pic, struct pic_proc *proc) return pic_values_by_list(pic, escape->results); } else { - struct pic_proc *c; pic_value val; - struct pic_data *e; - c = pic_make_proc(pic, escape_call, ""); - - e = pic_data_alloc(pic, &escape_type, escape); - - /* save the escape continuation in proc */ - pic_attr_set(pic, c, "@@escape", pic_obj_value(e)); - - val = pic_apply1(pic, proc, pic_obj_value(c)); + val = pic_apply1(pic, proc, pic_obj_value(make_escape(pic, escape))); escape->valid = false; From c965f254cb05ca49ab32d18f37838cb50831ddf5 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 15:33:21 +0900 Subject: [PATCH 03/13] missing validation flag change --- cont.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cont.c b/cont.c index 1066dd89..bc1a6c17 100644 --- a/cont.c +++ b/cont.c @@ -92,6 +92,8 @@ load_point(pic_state *pic, struct pic_escape *escape) pic->arena_idx = escape->arena_idx; pic->ip = escape->ip; + escape->valid = false; + longjmp(escape->jmp, 1); } From e38732995e14bd7e89f12a8a3a830213934f06e1 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 15:34:46 +0900 Subject: [PATCH 04/13] publish continuation internal APIs --- cont.c | 18 +++++++++--------- include/picrin/cont.h | 5 +++++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cont.c b/cont.c index bc1a6c17..2c109c67 100644 --- a/cont.c +++ b/cont.c @@ -57,8 +57,8 @@ pic_dynamic_wind(pic_state *pic, struct pic_proc *in, struct pic_proc *thunk, st return val; } -static int -save_point(pic_state *pic, struct pic_escape *escape) +int +pic_save_point(pic_state *pic, struct pic_escape *escape) { escape->valid = true; @@ -75,8 +75,8 @@ save_point(pic_state *pic, struct pic_escape *escape) return setjmp(escape->jmp); } -noreturn static void -load_point(pic_state *pic, struct pic_escape *escape) +noreturn void +pic_load_point(pic_state *pic, struct pic_escape *escape) { if (! escape->valid) { pic_errorf(pic, "calling dead escape continuation"); @@ -108,11 +108,11 @@ escape_call(pic_state *pic) e = pic_data_ptr(pic_attr_ref(pic, pic_get_proc(pic), "@@escape")); - load_point(pic, e->data); + pic_load_point(pic, e->data); } -static struct pic_proc * -make_escape(pic_state *pic, struct pic_escape *escape) +struct pic_proc * +pic_make_cont(pic_state *pic, struct pic_escape *escape) { static const pic_data_type escape_type = { "escape", pic_free, NULL }; struct pic_proc *cont; @@ -135,13 +135,13 @@ pic_escape(pic_state *pic, struct pic_proc *proc) escape = pic_alloc(pic, sizeof(struct pic_escape)); - if (save_point(pic, escape)) { + if (pic_save_point(pic, escape)) { return pic_values_by_list(pic, escape->results); } else { pic_value val; - val = pic_apply1(pic, proc, pic_obj_value(make_escape(pic, escape))); + val = pic_apply1(pic, proc, pic_obj_value(pic_make_cont(pic, escape))); escape->valid = false; diff --git a/include/picrin/cont.h b/include/picrin/cont.h index f49d6595..6fd6fda8 100644 --- a/include/picrin/cont.h +++ b/include/picrin/cont.h @@ -26,6 +26,11 @@ struct pic_escape { pic_value results; }; +int pic_save_point(pic_state *, struct pic_escape *); +noreturn void pic_load_point(pic_state *, struct pic_escape *); + +struct pic_proc *pic_make_cont(pic_state *, struct pic_escape *); + void pic_wind(pic_state *, struct pic_winder *, struct pic_winder *); pic_value pic_dynamic_wind(pic_state *, struct pic_proc *, struct pic_proc *, struct pic_proc *); From c7c771c861ff656b96086e4f7c8cb230d5cd20e7 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 15:35:00 +0900 Subject: [PATCH 05/13] refactor pic_push_try. use raw continuation API --- error.c | 54 ++++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/error.c b/error.c index 978ff962..aa2e8e42 100644 --- a/error.c +++ b/error.c @@ -85,39 +85,37 @@ native_exception_handler(pic_state *pic) UNREACHABLE(); } -static pic_value -native_push_try(pic_state *pic) -{ - struct pic_proc *cont, *handler; - size_t xp_len, xp_offset; - - pic_get_args(pic, "l", &cont); - - handler = pic_make_proc(pic, native_exception_handler, "(native-exception-handler)"); - - pic_attr_set(pic, handler, "@@escape", pic_obj_value(cont)); - - if (pic->xp >= pic->xpend) { - xp_len = (pic->xpend - pic->xpbase) * 2; - xp_offset = pic->xp - pic->xpbase; - pic->xpbase = pic_realloc(pic, pic->xpbase, sizeof(struct pic_proc *) * xp_len); - pic->xp = pic->xpbase + xp_offset; - pic->xpend = pic->xpbase + xp_len; - } - - *pic->xp++ = handler; - - return pic_true_value(); -} - bool pic_push_try(pic_state *pic) { - pic_value val; + struct pic_escape *escape; - val = pic_escape(pic, pic_make_proc(pic, native_push_try, "(native-push-try)")); + escape = pic_alloc(pic, sizeof(struct pic_escape)); - return pic_test(val); + if (pic_save_point(pic, escape)) { + return false; + } else { + struct pic_proc *cont, *handler; + size_t xp_len, xp_offset; + + cont = pic_make_cont(pic, escape); + + handler = pic_make_proc(pic, native_exception_handler, "(native-exception-handler)"); + + pic_attr_set(pic, handler, "@@escape", pic_obj_value(cont)); + + if (pic->xp >= pic->xpend) { + xp_len = (pic->xpend - pic->xpbase) * 2; + xp_offset = pic->xp - pic->xpbase; + pic->xpbase = pic_realloc(pic, pic->xpbase, sizeof(struct pic_proc *) * xp_len); + pic->xp = pic->xpbase + xp_offset; + pic->xpend = pic->xpbase + xp_len; + } + + *pic->xp++ = handler; + + return true; + } } void From 7c5fb70e735078e4dc9d61cf9bc631982e758bc9 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 15:59:23 +0900 Subject: [PATCH 06/13] mark invalid flag --- error.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/error.c b/error.c index aa2e8e42..02ec75a6 100644 --- a/error.c +++ b/error.c @@ -10,6 +10,7 @@ #include "picrin/pair.h" #include "picrin/proc.h" #include "picrin/cont.h" +#include "picrin/data.h" #include "picrin/string.h" #include "picrin/error.h" @@ -121,7 +122,13 @@ pic_push_try(pic_state *pic) void pic_pop_try(pic_state *pic) { - --pic->xp; + struct pic_data *e; + + assert(pic->xp > pic->xpbase); + + e = pic_data_ptr(pic_attr_ref(pic, pic_proc_ptr(pic_attr_ref(pic, *--pic->xp, "@@escape")), "@@escape")); + + ((struct pic_escape *)e->data)->valid = false; } struct pic_error * From cb2157bbaee2fcded4feebaa46c10551426e10d7 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 18:43:20 +0900 Subject: [PATCH 07/13] s/pic_make_cont/pic_make_econt/g --- cont.c | 4 ++-- error.c | 2 +- include/picrin/cont.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cont.c b/cont.c index 2c109c67..214602e5 100644 --- a/cont.c +++ b/cont.c @@ -112,7 +112,7 @@ escape_call(pic_state *pic) } struct pic_proc * -pic_make_cont(pic_state *pic, struct pic_escape *escape) +pic_make_econt(pic_state *pic, struct pic_escape *escape) { static const pic_data_type escape_type = { "escape", pic_free, NULL }; struct pic_proc *cont; @@ -141,7 +141,7 @@ pic_escape(pic_state *pic, struct pic_proc *proc) else { pic_value val; - val = pic_apply1(pic, proc, pic_obj_value(pic_make_cont(pic, escape))); + val = pic_apply1(pic, proc, pic_obj_value(pic_make_econt(pic, escape))); escape->valid = false; diff --git a/error.c b/error.c index 02ec75a6..92aa4710 100644 --- a/error.c +++ b/error.c @@ -99,7 +99,7 @@ pic_push_try(pic_state *pic) struct pic_proc *cont, *handler; size_t xp_len, xp_offset; - cont = pic_make_cont(pic, escape); + cont = pic_make_econt(pic, escape); handler = pic_make_proc(pic, native_exception_handler, "(native-exception-handler)"); diff --git a/include/picrin/cont.h b/include/picrin/cont.h index 6fd6fda8..fd7bfea4 100644 --- a/include/picrin/cont.h +++ b/include/picrin/cont.h @@ -29,7 +29,7 @@ struct pic_escape { int pic_save_point(pic_state *, struct pic_escape *); noreturn void pic_load_point(pic_state *, struct pic_escape *); -struct pic_proc *pic_make_cont(pic_state *, struct pic_escape *); +struct pic_proc *pic_make_econt(pic_state *, struct pic_escape *); void pic_wind(pic_state *, struct pic_winder *, struct pic_winder *); pic_value pic_dynamic_wind(pic_state *, struct pic_proc *, struct pic_proc *, struct pic_proc *); From d6b2fe05ceed53ce96e1db14017e097749d3e1a7 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 19:24:02 +0900 Subject: [PATCH 08/13] add many many assertions (pic_pop_try) --- error.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/error.c b/error.c index 92aa4710..be1e2337 100644 --- a/error.c +++ b/error.c @@ -122,13 +122,21 @@ pic_push_try(pic_state *pic) void pic_pop_try(pic_state *pic) { - struct pic_data *e; + pic_value cont, escape; assert(pic->xp > pic->xpbase); - e = pic_data_ptr(pic_attr_ref(pic, pic_proc_ptr(pic_attr_ref(pic, *--pic->xp, "@@escape")), "@@escape")); + cont = pic_attr_ref(pic, *--pic->xp, "@@escape"); - ((struct pic_escape *)e->data)->valid = false; + assert(pic_proc_p(cont)); + + escape = pic_attr_ref(pic, pic_proc_ptr(cont), "@@escape"); + + assert(pic_data_p(escape)); + + ((struct pic_escape *)pic_data_ptr(escape)->data)->valid = false; + + puts("pop_try done;"); } struct pic_error * From 44c1debbbeae665ac118c34883d25b14e32cddff Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 19:24:19 +0900 Subject: [PATCH 09/13] don't do pop_try when an error was raised --- include/picrin/error.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/picrin/error.h b/include/picrin/error.h index 5be65502..151cef12 100644 --- a/include/picrin/error.h +++ b/include/picrin/error.h @@ -29,8 +29,7 @@ struct pic_error *pic_make_error(pic_state *, pic_sym, const char *, pic_list); do #define pic_catch \ while (pic_pop_try(pic), 0); \ - else \ - if (pic_pop_try(pic), 1) + else bool pic_push_try(pic_state *); void pic_pop_try(pic_state *); From d6104b8b25860c78e7719066e898a29e9fabc26a Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 20:01:21 +0900 Subject: [PATCH 10/13] add noreturn mark --- error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error.c b/error.c index be1e2337..e5dfd340 100644 --- a/error.c +++ b/error.c @@ -69,7 +69,7 @@ pic_errmsg(pic_state *pic) return pic_str_cstr(str); } -static pic_value +noreturn static pic_value native_exception_handler(pic_state *pic) { pic_value err; From eb1e01d000dbdc607a2dc210cc737a1e7dbde4b6 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 20:06:14 +0900 Subject: [PATCH 11/13] don't setjmp in pic_save_point --- cont.c | 10 ++++------ error.c | 8 +++++--- include/picrin/cont.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cont.c b/cont.c index 214602e5..a560fa72 100644 --- a/cont.c +++ b/cont.c @@ -57,7 +57,7 @@ pic_dynamic_wind(pic_state *pic, struct pic_proc *in, struct pic_proc *thunk, st return val; } -int +void pic_save_point(pic_state *pic, struct pic_escape *escape) { escape->valid = true; @@ -71,8 +71,6 @@ pic_save_point(pic_state *pic, struct pic_escape *escape) escape->ip = pic->ip; escape->results = pic_undef_value(); - - return setjmp(escape->jmp); } noreturn void @@ -131,11 +129,11 @@ pic_make_econt(pic_state *pic, struct pic_escape *escape) pic_value pic_escape(pic_state *pic, struct pic_proc *proc) { - struct pic_escape *escape; + struct pic_escape *escape = pic_alloc(pic, sizeof(struct pic_escape)); - escape = pic_alloc(pic, sizeof(struct pic_escape)); + pic_save_point(pic, escape); - if (pic_save_point(pic, escape)) { + if (setjmp(escape->jmp)) { return pic_values_by_list(pic, escape->results); } else { diff --git a/error.c b/error.c index e5dfd340..a0c811d2 100644 --- a/error.c +++ b/error.c @@ -89,11 +89,13 @@ native_exception_handler(pic_state *pic) bool pic_push_try(pic_state *pic) { - struct pic_escape *escape; + struct pic_escape *escape = pic_alloc(pic, sizeof(struct pic_escape)); - escape = pic_alloc(pic, sizeof(struct pic_escape)); + pic_save_point(pic, escape); + + if (setjmp(escape->jmp)) { + puts("escaping"); - if (pic_save_point(pic, escape)) { return false; } else { struct pic_proc *cont, *handler; diff --git a/include/picrin/cont.h b/include/picrin/cont.h index fd7bfea4..0b29cfda 100644 --- a/include/picrin/cont.h +++ b/include/picrin/cont.h @@ -26,7 +26,7 @@ struct pic_escape { pic_value results; }; -int pic_save_point(pic_state *, struct pic_escape *); +void pic_save_point(pic_state *, struct pic_escape *); noreturn void pic_load_point(pic_state *, struct pic_escape *); struct pic_proc *pic_make_econt(pic_state *, struct pic_escape *); From d6c6427ff77faf93d2168ff09eac95aebb80769f Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 20:21:28 +0900 Subject: [PATCH 12/13] don't setjmp in pic_push_try --- error.c | 44 ++++++++++++++---------------------------- include/picrin/error.h | 18 ++++++++++++----- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/error.c b/error.c index a0c811d2..90d74572 100644 --- a/error.c +++ b/error.c @@ -86,39 +86,27 @@ native_exception_handler(pic_state *pic) UNREACHABLE(); } -bool -pic_push_try(pic_state *pic) +void +pic_push_try(pic_state *pic, struct pic_escape *escape) { - struct pic_escape *escape = pic_alloc(pic, sizeof(struct pic_escape)); + struct pic_proc *cont, *handler; + size_t xp_len, xp_offset; - pic_save_point(pic, escape); + cont = pic_make_econt(pic, escape); - if (setjmp(escape->jmp)) { - puts("escaping"); + handler = pic_make_proc(pic, native_exception_handler, "(native-exception-handler)"); - return false; - } else { - struct pic_proc *cont, *handler; - size_t xp_len, xp_offset; + pic_attr_set(pic, handler, "@@escape", pic_obj_value(cont)); - cont = pic_make_econt(pic, escape); - - handler = pic_make_proc(pic, native_exception_handler, "(native-exception-handler)"); - - pic_attr_set(pic, handler, "@@escape", pic_obj_value(cont)); - - if (pic->xp >= pic->xpend) { - xp_len = (pic->xpend - pic->xpbase) * 2; - xp_offset = pic->xp - pic->xpbase; - pic->xpbase = pic_realloc(pic, pic->xpbase, sizeof(struct pic_proc *) * xp_len); - pic->xp = pic->xpbase + xp_offset; - pic->xpend = pic->xpbase + xp_len; - } - - *pic->xp++ = handler; - - return true; + if (pic->xp >= pic->xpend) { + xp_len = (pic->xpend - pic->xpbase) * 2; + xp_offset = pic->xp - pic->xpbase; + pic->xpbase = pic_realloc(pic, pic->xpbase, sizeof(struct pic_proc *) * xp_len); + pic->xp = pic->xpbase + xp_offset; + pic->xpend = pic->xpbase + xp_len; } + + *pic->xp++ = handler; } void @@ -137,8 +125,6 @@ pic_pop_try(pic_state *pic) assert(pic_data_p(escape)); ((struct pic_escape *)pic_data_ptr(escape)->data)->valid = false; - - puts("pop_try done;"); } struct pic_error * diff --git a/include/picrin/error.h b/include/picrin/error.h index 151cef12..784b95f8 100644 --- a/include/picrin/error.h +++ b/include/picrin/error.h @@ -9,6 +9,8 @@ extern "C" { #endif +#include "picrin/cont.h" + struct pic_error { PIC_OBJECT_HEADER pic_sym type; @@ -25,13 +27,19 @@ struct pic_error *pic_make_error(pic_state *, pic_sym, const char *, pic_list); /* do not return from try block! */ #define pic_try \ - if (pic_push_try(pic)) \ + pic_try_(GENSYM(escape)) +#define pic_try_(escape) \ + struct pic_escape *escape = pic_alloc(pic, sizeof(struct pic_escape)); \ + pic_save_point(pic, escape); \ + if (setjmp(escape->jmp) == 0) { \ + pic_push_try(pic, escape); \ do -#define pic_catch \ - while (pic_pop_try(pic), 0); \ - else +#define pic_catch \ + while (0); \ + pic_pop_try(pic); \ + } else -bool pic_push_try(pic_state *); +void pic_push_try(pic_state *, struct pic_escape *); void pic_pop_try(pic_state *); pic_value pic_raise_continuable(pic_state *, pic_value); From a6d2491338ed4467077b21bbfd3bf2e5c2ab3ffc Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Wed, 24 Sep 2014 20:27:16 +0900 Subject: [PATCH 13/13] don't perform longjmp in pic_load_point (for the symmetry) --- cont.c | 6 +++--- include/picrin/cont.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cont.c b/cont.c index a560fa72..56e6263e 100644 --- a/cont.c +++ b/cont.c @@ -73,7 +73,7 @@ pic_save_point(pic_state *pic, struct pic_escape *escape) escape->results = pic_undef_value(); } -noreturn void +void pic_load_point(pic_state *pic, struct pic_escape *escape) { if (! escape->valid) { @@ -91,8 +91,6 @@ pic_load_point(pic_state *pic, struct pic_escape *escape) pic->ip = escape->ip; escape->valid = false; - - longjmp(escape->jmp, 1); } noreturn static pic_value @@ -107,6 +105,8 @@ escape_call(pic_state *pic) e = pic_data_ptr(pic_attr_ref(pic, pic_get_proc(pic), "@@escape")); pic_load_point(pic, e->data); + + longjmp(((struct pic_escape *)e->data)->jmp, 1); } struct pic_proc * diff --git a/include/picrin/cont.h b/include/picrin/cont.h index 0b29cfda..3e948f73 100644 --- a/include/picrin/cont.h +++ b/include/picrin/cont.h @@ -27,7 +27,7 @@ struct pic_escape { }; void pic_save_point(pic_state *, struct pic_escape *); -noreturn void pic_load_point(pic_state *, struct pic_escape *); +void pic_load_point(pic_state *, struct pic_escape *); struct pic_proc *pic_make_econt(pic_state *, struct pic_escape *);