From 958352eefcee7d479d90ed3fa20a21bd532c1e83 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Tue, 6 Dec 2011 08:36:49 -0700 Subject: [PATCH] fix futures bug related to GC When a future is blocked on JIT generation, a lightweight closure is captured, and then the future moves on, the runtime thread would correctly shift the on-demand JIT argument to the captured copy of the runstack. However, it would also add 2 to that pointer to use as the argv array, and the captured runstack is not allocated to allow interior pointers, so a GC during on-demand JIT could crash. The solution is to keep an offset alongside the argv pointer during JITting. --- src/racket/src/future.c | 27 ++++++++++++--------------- src/racket/src/future.h | 5 +++-- src/racket/src/jit.c | 23 +++++++++++++---------- src/racket/src/jit.h | 4 ++-- src/racket/src/jitcall.c | 2 +- src/racket/src/schpriv.h | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/racket/src/future.c b/src/racket/src/future.c index 3bae38dfab..42160e091c 100644 --- a/src/racket/src/future.c +++ b/src/racket/src/future.c @@ -1180,7 +1180,7 @@ static Scheme_Object *make_future(Scheme_Object *lambda) /* JIT the code if not already JITted */ if (ncd) { if (ncd->code == scheme_on_demand_jit_code) - scheme_on_demand_generate_lambda(nc, 0, NULL); + scheme_on_demand_generate_lambda(nc, 0, NULL, 0); if (ncd->max_let_depth > FUTURE_RUNSTACK_SIZE * sizeof(void*)) { /* Can't even call it in a future thread */ @@ -2139,24 +2139,24 @@ static Scheme_Object *_apply_future_lw(future_t *ft) { struct Scheme_Lightweight_Continuation *lw = ft->suspended_lw; Scheme_Object *v; - int result_is_rs_argv; + int result_is_rs_plus_two; ft->suspended_lw = NULL; v = ft->retval_s; - if (ft->retval_is_rs_argv) { - result_is_rs_argv = 1; - ft->retval_is_rs_argv = 0; + if (ft->retval_is_rs_plus_two) { + result_is_rs_plus_two = 1; + ft->retval_is_rs_plus_two = 0; } else { ft->retval_s = NULL; receive_special_result(ft, v, 1); - result_is_rs_argv = 0; + result_is_rs_plus_two = 0; } - FUTURE_ASSERT((ft->prim_protocol != SIG_ON_DEMAND) == !result_is_rs_argv); + FUTURE_ASSERT((ft->prim_protocol != SIG_ON_DEMAND) == !result_is_rs_plus_two); FUTURE_ASSERT(v || (ft->prim_protocol != SIG_ALLOC)); - v = scheme_apply_lightweight_continuation(lw, v, result_is_rs_argv, + v = scheme_apply_lightweight_continuation(lw, v, result_is_rs_plus_two, FUTURE_RUNSTACK_SIZE); if (SAME_OBJ(v, SCHEME_TAIL_CALL_WAITING)) { @@ -2568,10 +2568,7 @@ Scheme_Object **scheme_rtcall_on_demand(const char *who, int src_type, prim_on_d future->prim_protocol = SIG_ON_DEMAND; - if ((MZ_RUNSTACK + 2) != argv) { - fprintf(stderr, "internal error: expected arguments on runstack"); - abort(); - } + FUTURE_ASSERT(argv == (MZ_RUNSTACK + 2)); future->arg_S0 = MZ_RUNSTACK; @@ -2585,7 +2582,7 @@ Scheme_Object **scheme_rtcall_on_demand(const char *who, int src_type, prim_on_d future = fts->thread->current_ft; future->arg_S0 = NULL; - future->retval_is_rs_argv = 0; + future->retval_is_rs_plus_two = 0; return MZ_RUNSTACK + 2; } @@ -2898,9 +2895,9 @@ static void do_invoke_rtcall(Scheme_Future_State *fs, future_t *future, int is_a ADJUST_RS_ARG(future, arg_S0); - func(arg_S0, arg_S0 + 2); + func(arg_S0, arg_S0, 2); - future->retval_is_rs_argv = 1; + future->retval_is_rs_plus_two = 1; break; } diff --git a/src/racket/src/future.h b/src/racket/src/future.h index d185f75cd3..c0806c68d1 100644 --- a/src/racket/src/future.h +++ b/src/racket/src/future.h @@ -3,7 +3,7 @@ #ifdef MZ_USE_FUTURES -typedef Scheme_Object **(*prim_on_demand_t)(Scheme_Object **, Scheme_Object **); +typedef Scheme_Object **(*prim_on_demand_t)(Scheme_Object **, Scheme_Object **, int); typedef Scheme_Object* (*prim_obj_int_pobj_obj_t)(Scheme_Object*, int, Scheme_Object**); typedef Scheme_Object* (*prim_int_pobj_obj_t)(int, Scheme_Object**); typedef Scheme_Object* (*prim_int_pobj_obj_obj_t)(int, Scheme_Object**, Scheme_Object*); @@ -144,7 +144,8 @@ typedef struct future_t { void *retval_p; /* use only with conservative GC */ MZ_MARK_STACK_TYPE retval_m; int retval_i; - int no_retval, retval_is_rs_argv; + char no_retval; + char retval_is_rs_plus_two; /* => special result handling for on-demand JIT */ Scheme_Object **multiple_array; int multiple_count; diff --git a/src/racket/src/jit.c b/src/racket/src/jit.c index ba751ed172..8a9b0e5993 100644 --- a/src/racket/src/jit.c +++ b/src/racket/src/jit.c @@ -483,7 +483,7 @@ Scheme_Object *scheme_extract_closure_local(Scheme_Object *obj, mz_jit_state *ji a closure element into an argument */ pos -= jitter->closure_to_args_delta; if (pos < jitter->example_argc) - return jitter->example_argv[pos]; + return jitter->example_argv[pos + jitter->example_argv_delta]; } } @@ -3042,7 +3042,7 @@ typedef struct { void *arity_code, *code, *tail_code, *code_end, **patch_depth; int max_extra, max_depth, max_tail_depth; Scheme_Native_Closure *nc; - int argc; + int argc, argv_delta; Scheme_Object **argv; } Generate_Closure_Data; @@ -3051,7 +3051,7 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data) Generate_Closure_Data *gdata = (Generate_Closure_Data *)_data; Scheme_Closure_Data *data = gdata->data; void *code, *tail_code, *code_end, *arity_code; - int i, r, cnt, has_rest, is_method, num_params, to_args, argc; + int i, r, cnt, has_rest, is_method, num_params, to_args, argc, argv_delta; Scheme_Object **argv; code = jit_get_ip().ptr; @@ -3060,6 +3060,7 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data) argc = gdata->argc; argv = gdata->argv; + argv_delta = gdata->argv_delta; generate_function_prolog(jitter, code, /* max_extra_pushed may be wrong the first time around, @@ -3347,6 +3348,7 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data) jitter->closure_to_args_delta = to_args; jitter->example_argc = argc; jitter->example_argv = argv; + jitter->example_argv_delta = argv_delta; /* Generate code for the body: */ jitter->need_set_rs = 1; @@ -3380,7 +3382,7 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data) return 1; } -static void on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv) +static void on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv, int argv_delta) { Scheme_Native_Closure_Data *ndata = nc->code; Scheme_Closure_Data *data; @@ -3394,6 +3396,7 @@ static void on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Schem gdata.nc = nc; gdata.argc = argc; gdata.argv = argv; + gdata.argv_delta = argv_delta; /* This action is not atomic: */ scheme_delay_load_closure(data); @@ -3461,28 +3464,28 @@ static void on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Schem ndata->max_let_depth = max_depth; } -void scheme_on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv) +void scheme_on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv, int argv_delta) { - on_demand_generate_lambda(nc, argc, argv); + on_demand_generate_lambda(nc, argc, argv, argv_delta); } -Scheme_Object **scheme_on_demand_with_args(Scheme_Object **in_argv, Scheme_Object **argv) +Scheme_Object **scheme_on_demand_with_args(Scheme_Object **in_argv, Scheme_Object **argv, int argv_delta) { - /* On runstack: closure (nearest), argc, argv (deepest) */ + /* On runstack: closure (nearest), argc, probably argv (deepest) */ Scheme_Object *c, *argc; c = in_argv[0]; argc = in_argv[1]; if (((Scheme_Native_Closure *)c)->code->code == scheme_on_demand_jit_code) - scheme_on_demand_generate_lambda((Scheme_Native_Closure *)c, SCHEME_INT_VAL(argc), argv); + scheme_on_demand_generate_lambda((Scheme_Native_Closure *)c, SCHEME_INT_VAL(argc), argv, argv_delta); return argv; } Scheme_Object **scheme_on_demand(Scheme_Object **rs) { - return scheme_on_demand_with_args(MZ_RUNSTACK, rs); + return scheme_on_demand_with_args(MZ_RUNSTACK, rs, 0); } static Scheme_Native_Closure_Data *create_native_lambda(Scheme_Closure_Data *data, int clear_code_after_jit, diff --git a/src/racket/src/jit.h b/src/racket/src/jit.h index b36def5c0b..cbf61a2677 100644 --- a/src/racket/src/jit.h +++ b/src/racket/src/jit.h @@ -313,7 +313,7 @@ typedef struct mz_jit_state { int self_pos, self_closure_size, self_toplevel_pos; int self_to_closure_delta, closure_to_args_delta; int closure_self_on_runstack; - int example_argc; + int example_argc, example_argv_delta; Scheme_Object **example_argv; void *self_restart_code; void *self_nontail_code; @@ -1242,7 +1242,7 @@ int scheme_generate_non_tail_mark_pos_prefix(mz_jit_state *jitter); void scheme_generate_non_tail_mark_pos_suffix(mz_jit_state *jitter); Scheme_Object **scheme_on_demand(Scheme_Object **argv); -Scheme_Object **scheme_on_demand_with_args(Scheme_Object **in_argv, Scheme_Object **argv); +Scheme_Object **scheme_on_demand_with_args(Scheme_Object **in_argv, Scheme_Object **argv, int argv_delta); void scheme_prepare_branch_jump(mz_jit_state *jitter, Branch_Info *for_branch); void scheme_branch_for_true(mz_jit_state *jitter, Branch_Info *for_branch); diff --git a/src/racket/src/jitcall.c b/src/racket/src/jitcall.c index b7f7197a33..7f3e475d80 100644 --- a/src/racket/src/jitcall.c +++ b/src/racket/src/jitcall.c @@ -1455,7 +1455,7 @@ int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_ nc = (Scheme_Native_Closure *)scheme_jit_closure((Scheme_Object *)data, NULL); if (nc->code->code == scheme_on_demand_jit_code) { if (nc->code->arity_code != sjc.in_progress_on_demand_jit_arity_code) { - scheme_on_demand_generate_lambda(nc, 0, NULL); + scheme_on_demand_generate_lambda(nc, 0, NULL, 0); } } if (nc->code->code != scheme_on_demand_jit_code) { diff --git a/src/racket/src/schpriv.h b/src/racket/src/schpriv.h index 42747cbebc..d097cb134c 100644 --- a/src/racket/src/schpriv.h +++ b/src/racket/src/schpriv.h @@ -2691,7 +2691,7 @@ Scheme_Object *scheme_jit_closure(Scheme_Object *, Scheme_Object *context); void scheme_jit_fill_threadlocal_table(); #ifdef MZ_USE_JIT -void scheme_on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv); +void scheme_on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv, int delta); #endif struct Start_Module_Args;