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.
This commit is contained in:
Matthew Flatt 2011-12-06 08:36:49 -07:00
parent 7a5e90f48f
commit 958352eefc
6 changed files with 32 additions and 31 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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) {

View File

@ -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;