more consistently clear the tail-call and multiple-values buffers
More consistent clearing avoids a kind of space unsafety. There's just one buffer per thread, so it's difficult to turn non-clearing into a detectable leak (I wasn't abel to construct an example), but it might be possible. More practically, failing to clear the buffer can make it difficult to debug memory use.
This commit is contained in:
parent
7ee6a814e5
commit
eaf1fd1fe5
|
@ -180,6 +180,7 @@ EXPORTS
|
|||
scheme_set_tail_buffer_size
|
||||
scheme_force_value
|
||||
scheme_force_one_value
|
||||
scheme_ignore_result
|
||||
scheme_set_cont_mark
|
||||
scheme_push_continuation_frame
|
||||
scheme_pop_continuation_frame
|
||||
|
|
|
@ -180,6 +180,7 @@ EXPORTS
|
|||
scheme_set_tail_buffer_size
|
||||
scheme_force_value
|
||||
scheme_force_one_value
|
||||
scheme_ignore_result
|
||||
scheme_set_cont_mark
|
||||
scheme_push_continuation_frame
|
||||
scheme_pop_continuation_frame
|
||||
|
|
|
@ -188,6 +188,7 @@ scheme_tail_eval_expr
|
|||
scheme_set_tail_buffer_size
|
||||
scheme_force_value
|
||||
scheme_force_one_value
|
||||
scheme_ignore_result
|
||||
scheme_set_cont_mark
|
||||
scheme_push_continuation_frame
|
||||
scheme_pop_continuation_frame
|
||||
|
|
|
@ -188,6 +188,7 @@ scheme_tail_eval_expr
|
|||
scheme_set_tail_buffer_size
|
||||
scheme_force_value
|
||||
scheme_force_one_value
|
||||
scheme_ignore_result
|
||||
scheme_set_cont_mark
|
||||
scheme_push_continuation_frame
|
||||
scheme_pop_continuation_frame
|
||||
|
|
|
@ -371,6 +371,18 @@ void scheme_init_eval_places()
|
|||
#endif
|
||||
}
|
||||
|
||||
XFORM_NONGCING static void ignore_result(Scheme_Object *v)
|
||||
{
|
||||
if (SAME_OBJ(v, SCHEME_MULTIPLE_VALUES)) {
|
||||
scheme_current_thread->ku.multiple.array = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void scheme_ignore_result(Scheme_Object *v)
|
||||
{
|
||||
ignore_result(v);
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* C stack and Scheme stack handling */
|
||||
/*========================================================================*/
|
||||
|
@ -1903,9 +1915,9 @@ define_execute_with_dynamic_state(Scheme_Object *vec, int delta, int defmacro,
|
|||
int is_st;
|
||||
|
||||
values = scheme_current_thread->ku.multiple.array;
|
||||
scheme_current_thread->ku.multiple.array = NULL;
|
||||
if (SAME_OBJ(values, scheme_current_thread->values_buffer))
|
||||
scheme_current_thread->values_buffer = NULL;
|
||||
scheme_current_thread->ku.multiple.array = NULL;
|
||||
|
||||
if (dm_env)
|
||||
is_st = 0;
|
||||
|
@ -1946,10 +1958,10 @@ define_execute_with_dynamic_state(Scheme_Object *vec, int delta, int defmacro,
|
|||
scheme_pop_prefix(save_runstack);
|
||||
|
||||
return scheme_void;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (SAME_OBJ(scheme_current_thread->ku.multiple.array, scheme_current_thread->values_buffer))
|
||||
scheme_current_thread->values_buffer = NULL;
|
||||
}
|
||||
} else if (SCHEME_VEC_SIZE(vec) == delta + 1) { /* => single var */
|
||||
var = SCHEME_VEC_ELS(vec)[delta];
|
||||
if (dm_env) {
|
||||
|
@ -2096,6 +2108,7 @@ static Scheme_Object *apply_values_execute(Scheme_Object *data)
|
|||
v = _scheme_eval_linked_expr_multi(SCHEME_PTR2_VAL(data));
|
||||
if (SAME_OBJ(v, SCHEME_MULTIPLE_VALUES)) {
|
||||
Scheme_Thread *p = scheme_current_thread;
|
||||
Scheme_Object **rands;
|
||||
int num_rands = p->ku.multiple.count;
|
||||
|
||||
if (num_rands > p->tail_buffer_size) {
|
||||
|
@ -2103,7 +2116,9 @@ static Scheme_Object *apply_values_execute(Scheme_Object *data)
|
|||
if (SAME_OBJ(p->ku.multiple.array, p->values_buffer))
|
||||
p->values_buffer = NULL;
|
||||
}
|
||||
return scheme_tail_apply(f, num_rands, p->ku.multiple.array);
|
||||
rands = p->ku.multiple.array;
|
||||
p->ku.multiple.array = NULL;
|
||||
return scheme_tail_apply(f, num_rands, rands);
|
||||
} else {
|
||||
Scheme_Object *a[1];
|
||||
a[0] = v;
|
||||
|
@ -2223,7 +2238,7 @@ static Scheme_Object *begin0_execute(Scheme_Object *obj)
|
|||
|
||||
apos = 1;
|
||||
while (i--) {
|
||||
(void)_scheme_eval_linked_expr_multi(((Scheme_Sequence *)obj)->array[apos++]);
|
||||
ignore_result(_scheme_eval_linked_expr_multi(((Scheme_Sequence *)obj)->array[apos++]));
|
||||
}
|
||||
|
||||
if (mv) {
|
||||
|
@ -2247,7 +2262,7 @@ static Scheme_Object *splice_execute(Scheme_Object *data)
|
|||
int i, cnt = seq->count - 1;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
(void)_scheme_call_with_prompt_multi(splice_one_expr, seq->array[i]);
|
||||
ignore_result(_scheme_call_with_prompt_multi(splice_one_expr, seq->array[i]));
|
||||
}
|
||||
|
||||
return _scheme_eval_linked_expr_multi(seq->array[cnt]);
|
||||
|
@ -2327,7 +2342,7 @@ do_define_syntaxes_execute(Scheme_Object *form, Scheme_Env *dm_env)
|
|||
save_runstack = scheme_push_prefix(dm_env->exp_env, rp, NULL, NULL, 1, 1, NULL, scheme_false);
|
||||
|
||||
while (!SCHEME_NULLP(form)) {
|
||||
(void)scheme_eval_linked_expr_multi_with_dynamic_state(SCHEME_CAR(form), &dyn_state);
|
||||
ignore_result(scheme_eval_linked_expr_multi_with_dynamic_state(SCHEME_CAR(form), &dyn_state));
|
||||
form = SCHEME_CDR(form);
|
||||
}
|
||||
|
||||
|
@ -3407,7 +3422,7 @@ scheme_do_eval(Scheme_Object *obj, int num_rands, Scheme_Object **rands,
|
|||
|
||||
UPDATE_THREAD_RSPTR();
|
||||
for (i = 0; i < cnt; i++) {
|
||||
(void)_scheme_eval_linked_expr_multi_wp(((Scheme_Sequence *)obj)->array[i], p);
|
||||
ignore_result(_scheme_eval_linked_expr_multi_wp(((Scheme_Sequence *)obj)->array[i], p));
|
||||
}
|
||||
|
||||
obj = ((Scheme_Sequence *)obj)->array[cnt];
|
||||
|
@ -5192,6 +5207,7 @@ static Scheme_Object *do_eval_string_all(Scheme_Object *port, const char *str, S
|
|||
if (SAME_OBJ(p->ku.multiple.array, p->values_buffer))
|
||||
p->values_buffer = NULL;
|
||||
a = p->ku.multiple.array;
|
||||
p->ku.multiple.array = NULL;
|
||||
cnt = p->ku.multiple.count;
|
||||
} else {
|
||||
_a[0] = result;
|
||||
|
|
|
@ -3402,7 +3402,8 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
|
|||
GC_CAN_IGNORE Scheme_Thread *p = scheme_current_thread;
|
||||
c = p->ku.multiple.count;
|
||||
argv2 = p->ku.multiple.array;
|
||||
if (SAME_OBJ(p->ku.multiple.array, p->values_buffer)) {
|
||||
p->ku.multiple.array = NULL;
|
||||
if (SAME_OBJ(argv2, p->values_buffer)) {
|
||||
if (c <= MAX_QUICK_CHAP_ARGV) {
|
||||
for (i = 0; i < c; i++) {
|
||||
a2[i] = argv2[i];
|
||||
|
@ -3544,6 +3545,7 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
|
|||
p->values_buffer = NULL;
|
||||
c = p->ku.multiple.count;
|
||||
argv = p->ku.multiple.array;
|
||||
p->ku.multiple.array = NULL;
|
||||
} else {
|
||||
c = 1;
|
||||
a[0] = v;
|
||||
|
@ -3575,6 +3577,7 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
|
|||
p->values_buffer = NULL;
|
||||
argc = p->ku.multiple.count;
|
||||
argv2 = p->ku.multiple.array;
|
||||
p->ku.multiple.array = NULL;
|
||||
} else {
|
||||
argc = 1;
|
||||
a2[0] = v;
|
||||
|
@ -3713,9 +3716,9 @@ static Scheme_Object *call_with_values(int argc, Scheme_Object *argv[])
|
|||
Scheme_Object **a;
|
||||
if (SAME_OBJ(p->ku.multiple.array, p->values_buffer))
|
||||
p->values_buffer = NULL;
|
||||
/* Beware: the fields overlap! */
|
||||
n = p->ku.multiple.count;
|
||||
a = p->ku.multiple.array;
|
||||
p->ku.multiple.array = NULL;
|
||||
p->ku.apply.tail_num_rands = n;
|
||||
p->ku.apply.tail_rands = a;
|
||||
} else {
|
||||
|
@ -5110,6 +5113,7 @@ static void restore_continuation(Scheme_Cont *cont, Scheme_Thread *p, int for_pr
|
|||
mc = p->ku.multiple.count;
|
||||
if (SAME_OBJ(mv, p->values_buffer))
|
||||
p->values_buffer = NULL;
|
||||
p->ku.multiple.array = NULL;
|
||||
} else {
|
||||
mv = NULL;
|
||||
mc = 0;
|
||||
|
@ -6394,6 +6398,7 @@ static Scheme_Object **chaperone_do_control(const char *name, int mode,
|
|||
p->values_buffer = NULL;
|
||||
num_args = p->ku.multiple.count;
|
||||
vals = p->ku.multiple.array;
|
||||
p->ku.multiple.array = NULL;
|
||||
} else {
|
||||
num_args = 1;
|
||||
vals = MALLOC_N(Scheme_Object *, 1);
|
||||
|
@ -6470,6 +6475,7 @@ static Scheme_Object *do_cc_guard(Scheme_Object *v, Scheme_Object *cc_guard, Sch
|
|||
p->values_buffer = NULL;
|
||||
argc = p->ku.multiple.count;
|
||||
argv = p->ku.multiple.array;
|
||||
p->ku.multiple.array = NULL;
|
||||
} else {
|
||||
a[0] = v;
|
||||
argv = a;
|
||||
|
@ -8591,7 +8597,7 @@ static void pre_post_dyn_wind(Scheme_Object *prepost)
|
|||
scheme_push_break_enable(&cframe, 0, 0);
|
||||
|
||||
/* Here's the main call: */
|
||||
(void)_scheme_apply_multi(prepost, 0, NULL);
|
||||
scheme_ignore_result(_scheme_apply_multi(prepost, 0, NULL));
|
||||
|
||||
scheme_pop_break_enable(&cframe, 0);
|
||||
|
||||
|
@ -9441,10 +9447,12 @@ static Scheme_Object *time_apply(int argc, Scheme_Object *argv[])
|
|||
|
||||
if (v == SCHEME_MULTIPLE_VALUES) {
|
||||
Scheme_Thread *cp = scheme_current_thread;
|
||||
Scheme_Object **args;
|
||||
if (SAME_OBJ(cp->ku.multiple.array, cp->values_buffer))
|
||||
cp->values_buffer = NULL;
|
||||
v = scheme_build_list(cp->ku.multiple.count,
|
||||
cp->ku.multiple.array);
|
||||
args = cp->ku.multiple.array;
|
||||
cp->ku.multiple.array = NULL;
|
||||
v = scheme_build_list(cp->ku.multiple.count, args);
|
||||
} else
|
||||
v = scheme_make_pair(v, scheme_null);
|
||||
|
||||
|
|
|
@ -2276,8 +2276,12 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w
|
|||
(void)jit_jmpi(refloop);
|
||||
CHECK_LIMIT();
|
||||
mz_patch_branch(ref3);
|
||||
/* clear array pointer and re-laod argc: */
|
||||
(void)mz_tl_ldi_p(JIT_R0, tl_scheme_current_thread);
|
||||
(void)jit_movi_p(JIT_R1, NULL);
|
||||
jit_stxi_l(&((Scheme_Thread *)0x0)->ku.multiple.array, JIT_R0, JIT_R1);
|
||||
jit_ldxi_l(JIT_R0, JIT_R0, &((Scheme_Thread *)0x0)->ku.multiple.count);
|
||||
CHECK_LIMIT();
|
||||
|
||||
/* Perform call --------------------- */
|
||||
/* Function is in V1, argc in R0, args on RUNSTACK */
|
||||
|
@ -2286,16 +2290,18 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w
|
|||
|
||||
if (is_tail) {
|
||||
if (!sjc.shared_tail_argc_code) {
|
||||
sjc.shared_tail_argc_code = scheme_generate_shared_call(-1, jitter, 1, 1, 0, 0, 0, 0);
|
||||
sjc.shared_tail_argc_code = scheme_generate_shared_call(-1, jitter, 1, 0, 1, 0, 0, 0, 0);
|
||||
}
|
||||
mz_set_local_p(JIT_R0, JIT_LOCAL2);
|
||||
(void)jit_jmpi(sjc.shared_tail_argc_code);
|
||||
} else {
|
||||
int mo = multi_ok ? 1 : 0;
|
||||
int mo = (multi_ok
|
||||
? (result_ignored ? SHARED_RESULT_IGNORED_CASE : SHARED_MULTI_OK_CASE)
|
||||
: SHARED_SINGLE_VALUE_CASE);
|
||||
void *code;
|
||||
if (!sjc.shared_non_tail_argc_code[mo]) {
|
||||
scheme_ensure_retry_available(jitter, multi_ok);
|
||||
code = scheme_generate_shared_call(-2, jitter, multi_ok, 0, 0, 0, 0, 0);
|
||||
scheme_ensure_retry_available(jitter, multi_ok, result_ignored);
|
||||
code = scheme_generate_shared_call(-2, jitter, multi_ok, result_ignored, 0, 0, 0, 0, 0);
|
||||
sjc.shared_non_tail_argc_code[mo] = code;
|
||||
}
|
||||
code = sjc.shared_non_tail_argc_code[mo];
|
||||
|
@ -2438,7 +2444,7 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w
|
|||
return r;
|
||||
}
|
||||
|
||||
r = scheme_generate_app(app, NULL, app->num_args, jitter, is_tail, multi_ok, 0);
|
||||
r = scheme_generate_app(app, NULL, app->num_args, jitter, is_tail, multi_ok, result_ignored, 0);
|
||||
|
||||
CHECK_LIMIT();
|
||||
if (target != JIT_R0)
|
||||
|
@ -2468,7 +2474,7 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w
|
|||
args[0] = app->rator;
|
||||
args[1] = app->rand;
|
||||
|
||||
r = scheme_generate_app(NULL, args, 1, jitter, is_tail, multi_ok, 0);
|
||||
r = scheme_generate_app(NULL, args, 1, jitter, is_tail, multi_ok, result_ignored, 0);
|
||||
|
||||
CHECK_LIMIT();
|
||||
if (target != JIT_R0)
|
||||
|
@ -2499,7 +2505,7 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w
|
|||
args[1] = app->rand1;
|
||||
args[2] = app->rand2;
|
||||
|
||||
r = scheme_generate_app(NULL, args, 2, jitter, is_tail, multi_ok, 0);
|
||||
r = scheme_generate_app(NULL, args, 2, jitter, is_tail, multi_ok, result_ignored, 0);
|
||||
|
||||
CHECK_LIMIT();
|
||||
if (target != JIT_R0)
|
||||
|
@ -2601,9 +2607,9 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w
|
|||
/* Did we get multiple results? If not, go to error: */
|
||||
ref = jit_bnei_p(jit_forward(), JIT_R0, SCHEME_MULTIPLE_VALUES);
|
||||
/* Load count and result array: */
|
||||
mz_tl_ldi_p(JIT_R2, tl_scheme_current_thread);
|
||||
jit_ldxi_l(JIT_R1, JIT_R2, &((Scheme_Thread *)0x0)->ku.multiple.count);
|
||||
jit_ldxi_p(JIT_R2, JIT_R2, &((Scheme_Thread *)0x0)->ku.multiple.array);
|
||||
mz_tl_ldi_p(JIT_V1, tl_scheme_current_thread);
|
||||
jit_ldxi_p(JIT_R2, JIT_V1, &((Scheme_Thread *)0x0)->ku.multiple.array);
|
||||
jit_ldxi_l(JIT_R1, JIT_V1, &((Scheme_Thread *)0x0)->ku.multiple.count);
|
||||
CHECK_LIMIT();
|
||||
/* If we got the expected count, jump to installing values: */
|
||||
ref2 = jit_beqi_i(jit_forward(), JIT_R1, lv->count);
|
||||
|
@ -2630,9 +2636,11 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w
|
|||
(void)mz_finish_lwe(ts_lexical_binding_wrong_return_arity, ref);
|
||||
CHECK_LIMIT();
|
||||
|
||||
/* Continue with expected values; R2 has value array: */
|
||||
/* Continue with expected values; R2 has values and V1 has thread pointer: */
|
||||
mz_patch_branch(ref2);
|
||||
__END_SHORT_JUMPS__(1);
|
||||
(void)jit_movi_p(JIT_R0, NULL);
|
||||
jit_stxi_p(&((Scheme_Thread *)0x0)->ku.multiple.array, JIT_V1, JIT_R0);
|
||||
for (i = 0; i < lv->count; i++) {
|
||||
jit_ldxi_p(JIT_R1, JIT_R2, WORDS_TO_BYTES(i));
|
||||
if (ab) {
|
||||
|
|
|
@ -210,9 +210,13 @@ struct scheme_jit_common_record {
|
|||
|
||||
#define MAX_SHARED_CALL_RANDS 25
|
||||
void *shared_tail_code[4][MAX_SHARED_CALL_RANDS];
|
||||
void *shared_non_tail_code[5][MAX_SHARED_CALL_RANDS][2];
|
||||
void *shared_non_tail_retry_code[2];
|
||||
void *shared_non_tail_argc_code[2];
|
||||
# define SHARED_SINGLE_VALUE_CASE 0
|
||||
# define SHARED_MULTI_OK_CASE 1
|
||||
# define SHARED_RESULT_IGNORED_CASE 2
|
||||
# define SHARED_NUM_NONTAIL_CASES 3
|
||||
void *shared_non_tail_code[5][MAX_SHARED_CALL_RANDS][SHARED_NUM_NONTAIL_CASES];
|
||||
void *shared_non_tail_retry_code[SHARED_NUM_NONTAIL_CASES];
|
||||
void *shared_non_tail_argc_code[SHARED_NUM_NONTAIL_CASES];
|
||||
void *shared_tail_argc_code;
|
||||
|
||||
#define MAX_SHARED_ARITY_CHECK 25
|
||||
|
@ -1228,15 +1232,17 @@ int scheme_generate_arith(mz_jit_state *jitter, Scheme_Object *rator, Scheme_Obj
|
|||
|
||||
typedef struct jit_direct_arg jit_direct_arg;
|
||||
|
||||
void *scheme_generate_shared_call(int num_rands, mz_jit_state *old_jitter, int multi_ok, int is_tail,
|
||||
int direct_prim, int direct_native, int nontail_self, int unboxed_args);
|
||||
void scheme_ensure_retry_available(mz_jit_state *jitter, int multi_ok);
|
||||
void *scheme_generate_shared_call(int num_rands, mz_jit_state *old_jitter, int multi_ok, int result_ignored,
|
||||
int is_tail, int direct_prim, int direct_native, int nontail_self, int unboxed_args);
|
||||
void scheme_ensure_retry_available(mz_jit_state *jitter, int multi_ok, int result_ignored);
|
||||
int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_rands,
|
||||
mz_jit_state *jitter, int is_tail, int multi_ok, int no_call);
|
||||
mz_jit_state *jitter, int is_tail, int multi_ok, int ignored_result,
|
||||
int no_call);
|
||||
int scheme_generate_tail_call(mz_jit_state *jitter, int num_rands, int direct_native, int need_set_rs,
|
||||
int is_inline, Scheme_Native_Closure *direct_to_code, jit_direct_arg *direct_arg);
|
||||
int scheme_generate_non_tail_call(mz_jit_state *jitter, int num_rands, int direct_native, int need_set_rs,
|
||||
int multi_ok, int nontail_self, int pop_and_jump, int is_inlined, int unboxed_args);
|
||||
int multi_ok, int result_ignored, int nontail_self, int pop_and_jump,
|
||||
int is_inlined, int unboxed_args);
|
||||
int scheme_generate_finish_tail_call(mz_jit_state *jitter, int direct_native);
|
||||
int scheme_generate_finish_apply(mz_jit_state *jitter);
|
||||
int scheme_generate_finish_multi_apply(mz_jit_state *jitter);
|
||||
|
|
|
@ -1920,7 +1920,7 @@ int scheme_generate_nary_arith(mz_jit_state *jitter, Scheme_App_Rec *app,
|
|||
}
|
||||
|
||||
if (stack_c)
|
||||
scheme_generate_app(app, alt_args, stack_c, jitter, 0, 0, 2);
|
||||
scheme_generate_app(app, alt_args, stack_c, jitter, 0, 0, 0, 2);
|
||||
CHECK_LIMIT();
|
||||
mz_rs_sync();
|
||||
|
||||
|
|
|
@ -604,7 +604,8 @@ static int generate_direct_prim_non_tail_call(mz_jit_state *jitter, int num_rand
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int generate_retry_call(mz_jit_state *jitter, int num_rands, int multi_ok, GC_CAN_IGNORE jit_insn *reftop)
|
||||
static int generate_retry_call(mz_jit_state *jitter, int num_rands, int multi_ok, int result_ignored,
|
||||
GC_CAN_IGNORE jit_insn *reftop)
|
||||
/* If num_rands < 0, original argc is in V1, and we should
|
||||
pop argc arguments off runstack before pushing more.
|
||||
This function is called with short jumps enabled. */
|
||||
|
@ -612,7 +613,10 @@ static int generate_retry_call(mz_jit_state *jitter, int num_rands, int multi_ok
|
|||
GC_CAN_IGNORE jit_insn *ref, *ref2, *refloop;
|
||||
|
||||
if (!reftop) {
|
||||
reftop = sjc.shared_non_tail_retry_code[multi_ok ? 1 : 0];
|
||||
int mo = (multi_ok
|
||||
? (result_ignored ? SHARED_RESULT_IGNORED_CASE : SHARED_MULTI_OK_CASE)
|
||||
: SHARED_SINGLE_VALUE_CASE);
|
||||
reftop = sjc.shared_non_tail_retry_code[mo];
|
||||
}
|
||||
|
||||
/* Get new argc: */
|
||||
|
@ -637,7 +641,7 @@ static int generate_retry_call(mz_jit_state *jitter, int num_rands, int multi_ok
|
|||
|
||||
/* Copy arguments to runstack, then jump to reftop. */
|
||||
jit_ldxi_l(JIT_R2, JIT_R1, &((Scheme_Thread *)0x0)->ku.apply.tail_num_rands);
|
||||
jit_ldxi_l(JIT_V1, JIT_R1, &((Scheme_Thread *)0x0)->ku.apply.tail_rands);
|
||||
jit_ldxi_p(JIT_V1, JIT_R1, &((Scheme_Thread *)0x0)->ku.apply.tail_rands);
|
||||
jit_lshi_l(JIT_R2, JIT_R2, JIT_LOG_WORD_SIZE);
|
||||
CHECK_LIMIT();
|
||||
refloop = _jit.x.pc;
|
||||
|
@ -648,10 +652,15 @@ static int generate_retry_call(mz_jit_state *jitter, int num_rands, int multi_ok
|
|||
(void)jit_jmpi(refloop);
|
||||
CHECK_LIMIT();
|
||||
|
||||
/* Clear tail-call arguments pointer: */
|
||||
(void)jit_movi_p(JIT_V1, NULL);
|
||||
jit_stxi_p(&((Scheme_Thread *)0x0)->ku.apply.tail_rands, JIT_R1, JIT_V1);
|
||||
CHECK_LIMIT();
|
||||
|
||||
/* R1 is still the thread.
|
||||
Put procedure and argc in place, then jump to apply: */
|
||||
mz_patch_branch(ref2);
|
||||
jit_ldxi_l(JIT_V1, JIT_R1, &((Scheme_Thread *)0x0)->ku.apply.tail_rator);
|
||||
jit_ldxi_p(JIT_V1, JIT_R1, &((Scheme_Thread *)0x0)->ku.apply.tail_rator);
|
||||
jit_ldxi_l(JIT_R0, JIT_R1, &((Scheme_Thread *)0x0)->ku.apply.tail_num_rands);
|
||||
__END_SHORT_JUMPS__(1);
|
||||
(void)jit_jmpi(reftop);
|
||||
|
@ -690,9 +699,28 @@ static int generate_clear_slow_previous_args(mz_jit_state *jitter)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int generate_ignored_result_check(mz_jit_state *jitter)
|
||||
{
|
||||
/* if multiple results, need to clear ignored result in thread */
|
||||
GC_CAN_IGNORE jit_insn *refm;
|
||||
|
||||
__START_INNER_TINY__(1);
|
||||
|
||||
refm = jit_bnei_p(jit_forward(), JIT_R0, SCHEME_MULTIPLE_VALUES);
|
||||
mz_tl_ldi_p(JIT_R1, tl_scheme_current_thread);
|
||||
(void)jit_movi_p(JIT_R0, NULL);
|
||||
jit_stxi_p(&((Scheme_Thread *)0x0)->ku.multiple.array, JIT_R1, JIT_R0);
|
||||
(void)jit_movi_p(JIT_R0, scheme_void);
|
||||
mz_patch_branch(refm);
|
||||
|
||||
__END_INNER_TINY__(1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int scheme_generate_non_tail_call(mz_jit_state *jitter, int num_rands, int direct_native, int need_set_rs,
|
||||
int multi_ok, int nontail_self, int pop_and_jump, int is_inlined,
|
||||
int unboxed_args)
|
||||
int multi_ok, int result_ignored, int nontail_self, int pop_and_jump,
|
||||
int is_inlined, int unboxed_args)
|
||||
{
|
||||
/* Non-tail call.
|
||||
Proc is in V1, args are at RUNSTACK.
|
||||
|
@ -876,7 +904,7 @@ int scheme_generate_non_tail_call(mz_jit_state *jitter, int num_rands, int direc
|
|||
CHECK_LIMIT();
|
||||
if (pop_and_jump) {
|
||||
/* Expects argc in V1 if num_rands < 0: */
|
||||
generate_retry_call(jitter, num_rands, multi_ok, reftop);
|
||||
generate_retry_call(jitter, num_rands, multi_ok, result_ignored, reftop);
|
||||
}
|
||||
CHECK_LIMIT();
|
||||
if (need_set_rs) {
|
||||
|
@ -939,7 +967,7 @@ int scheme_generate_non_tail_call(mz_jit_state *jitter, int num_rands, int direc
|
|||
CHECK_LIMIT();
|
||||
if (pop_and_jump) {
|
||||
/* Expects argc in V1 if num_rands < 0: */
|
||||
generate_retry_call(jitter, num_rands, multi_ok, reftop);
|
||||
generate_retry_call(jitter, num_rands, multi_ok, result_ignored, reftop);
|
||||
}
|
||||
CHECK_LIMIT();
|
||||
if (num_rands < 0) {
|
||||
|
@ -1023,6 +1051,10 @@ int scheme_generate_non_tail_call(mz_jit_state *jitter, int num_rands, int direc
|
|||
mz_patch_branch(ref6);
|
||||
if (!direct_native) {
|
||||
mz_patch_branch(ref10);
|
||||
if (result_ignored) {
|
||||
generate_ignored_result_check(jitter);
|
||||
CHECK_LIMIT();
|
||||
}
|
||||
}
|
||||
/* Note: same return code is above for faster common-case return */
|
||||
if (num_rands < 0) {
|
||||
|
@ -1237,6 +1269,7 @@ typedef struct {
|
|||
int num_rands;
|
||||
mz_jit_state *old_jitter;
|
||||
int multi_ok;
|
||||
int result_ignored;
|
||||
int is_tail;
|
||||
int direct_prim, direct_native, nontail_self, unboxed_args;
|
||||
} Generate_Call_Data;
|
||||
|
@ -1295,7 +1328,8 @@ static int do_generate_shared_call(mz_jit_state *jitter, void *_data)
|
|||
ok = generate_direct_prim_non_tail_call(jitter, data->num_rands, data->multi_ok, 1);
|
||||
else
|
||||
ok = scheme_generate_non_tail_call(jitter, data->num_rands, data->direct_native, 1,
|
||||
data->multi_ok, data->nontail_self, 1, 0, data->unboxed_args);
|
||||
data->multi_ok, data->result_ignored, data->nontail_self,
|
||||
1, 0, data->unboxed_args);
|
||||
|
||||
scheme_jit_register_sub_func(jitter, code, scheme_false);
|
||||
|
||||
|
@ -1303,14 +1337,16 @@ static int do_generate_shared_call(mz_jit_state *jitter, void *_data)
|
|||
}
|
||||
}
|
||||
|
||||
void *scheme_generate_shared_call(int num_rands, mz_jit_state *old_jitter, int multi_ok, int is_tail,
|
||||
int direct_prim, int direct_native, int nontail_self, int unboxed_args)
|
||||
void *scheme_generate_shared_call(int num_rands, mz_jit_state *old_jitter, int multi_ok, int result_ignored,
|
||||
int is_tail, int direct_prim, int direct_native, int nontail_self,
|
||||
int unboxed_args)
|
||||
{
|
||||
Generate_Call_Data data;
|
||||
|
||||
data.num_rands = num_rands;
|
||||
data.old_jitter = old_jitter;
|
||||
data.multi_ok = multi_ok;
|
||||
data.result_ignored = result_ignored;
|
||||
data.is_tail = is_tail;
|
||||
data.direct_prim = direct_prim;
|
||||
data.direct_native = direct_native;
|
||||
|
@ -1320,12 +1356,14 @@ void *scheme_generate_shared_call(int num_rands, mz_jit_state *old_jitter, int m
|
|||
return scheme_generate_one(old_jitter, do_generate_shared_call, &data, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
void scheme_ensure_retry_available(mz_jit_state *jitter, int multi_ok)
|
||||
void scheme_ensure_retry_available(mz_jit_state *jitter, int multi_ok, int result_ignored)
|
||||
{
|
||||
int mo = multi_ok ? 1 : 0;
|
||||
int mo = (multi_ok
|
||||
? (result_ignored ? SHARED_RESULT_IGNORED_CASE : SHARED_MULTI_OK_CASE)
|
||||
: SHARED_SINGLE_VALUE_CASE);
|
||||
if (!sjc.shared_non_tail_retry_code[mo]) {
|
||||
void *code;
|
||||
code = scheme_generate_shared_call(-1, jitter, multi_ok, 0, 0, 0, 0, 0);
|
||||
code = scheme_generate_shared_call(-1, jitter, multi_ok, result_ignored, 0, 0, 0, 0, 0);
|
||||
sjc.shared_non_tail_retry_code[mo] = code;
|
||||
}
|
||||
}
|
||||
|
@ -1586,7 +1624,8 @@ static int generate_call_path_with_unboxes(mz_jit_state *jitter, int direct_flos
|
|||
#endif
|
||||
|
||||
int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_rands,
|
||||
mz_jit_state *jitter, int is_tail, int multi_ok, int no_call)
|
||||
mz_jit_state *jitter, int is_tail, int multi_ok, int result_ignored,
|
||||
int no_call)
|
||||
/* de-sync'd ok
|
||||
If no_call is 2, then rator is not necssarily evaluated.
|
||||
If no_call is 1, then rator is left in V1 and arguments are on runstack. */
|
||||
|
@ -1624,6 +1663,8 @@ int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
|||
if ((num_rands >= 2) && SAME_OBJ(rator, scheme_apply_proc))
|
||||
apply_to_list = 1;
|
||||
}
|
||||
if (!(((Scheme_Primitive_Proc *)rator)->pp.flags & SCHEME_PRIM_IS_MULTI_RESULT))
|
||||
result_ignored = 0; /* don't need to check for multiple values to ignore */
|
||||
} else {
|
||||
Scheme_Type t;
|
||||
t = SCHEME_TYPE(rator);
|
||||
|
@ -1970,7 +2011,7 @@ int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
|||
generate_nontail_self_setup(jitter);
|
||||
}
|
||||
scheme_generate_non_tail_call(jitter, num_rands, direct_native, jitter->need_set_rs,
|
||||
multi_ok, nontail_self, 0, 1, 0);
|
||||
multi_ok, result_ignored, nontail_self, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1981,7 +2022,8 @@ int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
|||
|
||||
if (is_tail) {
|
||||
if (!sjc.shared_tail_code[dp][num_rands]) {
|
||||
code = scheme_generate_shared_call(num_rands, jitter, multi_ok, is_tail, direct_prim, direct_native, 0, 0);
|
||||
code = scheme_generate_shared_call(num_rands, jitter, multi_ok, result_ignored, is_tail,
|
||||
direct_prim, direct_native, 0, 0);
|
||||
sjc.shared_tail_code[dp][num_rands] = code;
|
||||
}
|
||||
code = sjc.shared_tail_code[dp][num_rands];
|
||||
|
@ -2024,7 +2066,9 @@ int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
|||
}
|
||||
}
|
||||
} else {
|
||||
int mo = (multi_ok ? 1 : 0);
|
||||
int mo = (multi_ok
|
||||
? (result_ignored ? SHARED_RESULT_IGNORED_CASE : SHARED_MULTI_OK_CASE)
|
||||
: SHARED_SINGLE_VALUE_CASE);
|
||||
#ifdef USE_FLONUM_UNBOXING
|
||||
void *unboxed_code;
|
||||
#endif
|
||||
|
@ -2035,8 +2079,9 @@ int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
|||
#ifdef USE_FLONUM_UNBOXING
|
||||
if (unboxed_non_tail_args) {
|
||||
if (!sjc.shared_non_tail_code[4][num_rands][mo]) {
|
||||
scheme_ensure_retry_available(jitter, multi_ok);
|
||||
code = scheme_generate_shared_call(num_rands, jitter, multi_ok, is_tail, direct_prim, direct_native, nontail_self, 1);
|
||||
scheme_ensure_retry_available(jitter, multi_ok, result_ignored);
|
||||
code = scheme_generate_shared_call(num_rands, jitter, multi_ok, result_ignored, is_tail,
|
||||
direct_prim, direct_native, nontail_self, 1);
|
||||
sjc.shared_non_tail_code[4][num_rands][mo] = code;
|
||||
}
|
||||
unboxed_code = sjc.shared_non_tail_code[4][num_rands][mo];
|
||||
|
@ -2045,8 +2090,9 @@ int scheme_generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
|||
#endif
|
||||
|
||||
if (!sjc.shared_non_tail_code[dp][num_rands][mo]) {
|
||||
scheme_ensure_retry_available(jitter, multi_ok);
|
||||
code = scheme_generate_shared_call(num_rands, jitter, multi_ok, is_tail, direct_prim, direct_native, nontail_self, 0);
|
||||
scheme_ensure_retry_available(jitter, multi_ok, result_ignored);
|
||||
code = scheme_generate_shared_call(num_rands, jitter, multi_ok, result_ignored, is_tail,
|
||||
direct_prim, direct_native, nontail_self, 0);
|
||||
sjc.shared_non_tail_code[dp][num_rands][mo] = code;
|
||||
}
|
||||
LOG_IT(("<-non-tail %d %d %d\n", dp, num_rands, mo));
|
||||
|
|
|
@ -979,7 +979,7 @@ static int generate_apply_proxy(mz_jit_state *jitter, int setter)
|
|||
CHECK_LIMIT();
|
||||
JIT_UPDATE_THREAD_RSPTR();
|
||||
__END_SHORT_JUMPS__(1);
|
||||
scheme_generate_non_tail_call(jitter, 3, 0, 0, 0, 0, 0, 1, 0);
|
||||
scheme_generate_non_tail_call(jitter, 3, 0, 0, 0, 0, 0, 0, 1, 0);
|
||||
__START_SHORT_JUMPS__(1);
|
||||
CHECK_LIMIT();
|
||||
if (setter) {
|
||||
|
@ -3041,7 +3041,7 @@ static int more_common0(mz_jit_state *jitter, void *_data)
|
|||
mz_rs_sync();
|
||||
|
||||
__END_SHORT_JUMPS__(1);
|
||||
scheme_generate_non_tail_call(jitter, 2, 0, 1, 0, 0, 0, 0, 0);
|
||||
scheme_generate_non_tail_call(jitter, 2, 0, 1, 0, 0, 0, 0, 0, 0);
|
||||
CHECK_LIMIT();
|
||||
__START_SHORT_JUMPS__(1);
|
||||
|
||||
|
@ -3476,7 +3476,7 @@ static int more_common1(mz_jit_state *jitter, void *_data)
|
|||
|
||||
__END_SHORT_JUMPS__(1);
|
||||
|
||||
scheme_generate_non_tail_call(jitter, -1, 0, 1, multi_ok, 0, 1, 0, 0);
|
||||
scheme_generate_non_tail_call(jitter, -1, 0, 1, multi_ok, 0, 0, 1, 0, 0);
|
||||
|
||||
scheme_jit_register_sub_func(jitter, code, scheme_false);
|
||||
}
|
||||
|
|
|
@ -383,7 +383,7 @@ static int generate_inlined_struct_op(int kind, mz_jit_state *jitter,
|
|||
args[0] = rator;
|
||||
args[1] = rand;
|
||||
args[2] = rand2;
|
||||
scheme_generate_app(NULL, args, 2, jitter, 0, 0, 1); /* sync'd below */
|
||||
scheme_generate_app(NULL, args, 2, jitter, 0, 0, 0, 1); /* sync'd below */
|
||||
CHECK_LIMIT();
|
||||
jit_movr_p(JIT_R0, JIT_V1);
|
||||
mz_rs_ldr(JIT_R1);
|
||||
|
@ -600,7 +600,7 @@ static int generate_inlined_nary_struct_op(int kind, mz_jit_state *jitter,
|
|||
/* de-sync'd ok; for branch, sync'd before */
|
||||
{
|
||||
/* generate code to evaluate the arguments */
|
||||
scheme_generate_app(app, NULL, app->num_args, jitter, 0, 0, 1);
|
||||
scheme_generate_app(app, NULL, app->num_args, jitter, 0, 0, 0, 1);
|
||||
CHECK_LIMIT();
|
||||
mz_rs_sync();
|
||||
|
||||
|
@ -3165,7 +3165,7 @@ int scheme_generate_inlined_binary(mz_jit_state *jitter, Scheme_App3_Rec *app, i
|
|||
args[1] = app->rand1;
|
||||
args[2] = app->rand2;
|
||||
|
||||
scheme_generate_app(NULL, args, 2, jitter, 0, 0, 2);
|
||||
scheme_generate_app(NULL, args, 2, jitter, 0, 0, 0, 2);
|
||||
|
||||
CHECK_LIMIT();
|
||||
mz_rs_sync();
|
||||
|
@ -3271,7 +3271,7 @@ int scheme_generate_inlined_nary(mz_jit_state *jitter, Scheme_App_Rec *app, int
|
|||
}
|
||||
|
||||
/* generate code to evaluate the arguments */
|
||||
scheme_generate_app(app, NULL, 3, jitter, 0, 0, 2);
|
||||
scheme_generate_app(app, NULL, 3, jitter, 0, 0, 0, 2);
|
||||
CHECK_LIMIT();
|
||||
mz_rs_sync();
|
||||
|
||||
|
@ -3680,7 +3680,7 @@ int scheme_generate_inlined_nary(mz_jit_state *jitter, Scheme_App_Rec *app, int
|
|||
} else {
|
||||
got_two = 1;
|
||||
mz_runstack_skipped(jitter, 1);
|
||||
scheme_generate_app(app, NULL, 2, jitter, 0, 0, 2);
|
||||
scheme_generate_app(app, NULL, 2, jitter, 0, 0, 0, 2);
|
||||
}
|
||||
|
||||
if (scheme_can_unbox_inline(app->args[3], 5, JIT_FPR_NUM-1, 1))
|
||||
|
@ -3737,7 +3737,7 @@ int scheme_generate_inlined_nary(mz_jit_state *jitter, Scheme_App_Rec *app, int
|
|||
star = IS_NAMED_PRIM(rator, "list*");
|
||||
|
||||
if (c)
|
||||
scheme_generate_app(app, NULL, c, jitter, 0, 0, 2);
|
||||
scheme_generate_app(app, NULL, c, jitter, 0, 0, 0, 2);
|
||||
CHECK_LIMIT();
|
||||
mz_rs_sync();
|
||||
|
||||
|
@ -3775,7 +3775,7 @@ int scheme_generate_inlined_nary(mz_jit_state *jitter, Scheme_App_Rec *app, int
|
|||
if (!multi_ok) return 0;
|
||||
|
||||
if (c) {
|
||||
scheme_generate_app(app, NULL, c, jitter, 0, 0, 2);
|
||||
scheme_generate_app(app, NULL, c, jitter, 0, 0, 0, 2);
|
||||
CHECK_LIMIT();
|
||||
mz_rs_sync();
|
||||
|
||||
|
@ -3812,7 +3812,7 @@ int scheme_generate_inlined_nary(mz_jit_state *jitter, Scheme_App_Rec *app, int
|
|||
} else if (IS_NAMED_PRIM(rator, "max")) {
|
||||
return scheme_generate_nary_arith(jitter, app, ARITH_MAX, 0, NULL, 1);
|
||||
} else if (IS_NAMED_PRIM(rator, "checked-procedure-check-and-extract")) {
|
||||
scheme_generate_app(app, NULL, 5, jitter, 0, 0, 2); /* sync'd below */
|
||||
scheme_generate_app(app, NULL, 5, jitter, 0, 0, 0, 2); /* sync'd below */
|
||||
CHECK_LIMIT();
|
||||
mz_rs_sync();
|
||||
|
||||
|
@ -3893,7 +3893,7 @@ static int generate_vector_alloc(mz_jit_state *jitter, Scheme_Object *rator,
|
|||
} else {
|
||||
c = app->num_args;
|
||||
if (c)
|
||||
scheme_generate_app(app, NULL, c, jitter, 0, 0, 2); /* sync'd below */
|
||||
scheme_generate_app(app, NULL, c, jitter, 0, 0, 0, 2); /* sync'd below */
|
||||
}
|
||||
CHECK_LIMIT();
|
||||
|
||||
|
|
|
@ -5536,7 +5536,9 @@ static Scheme_Object *body_one_expr(void *prefix_plus_expr, int argc, Scheme_Obj
|
|||
v = _scheme_eval_linked_expr_multi(SCHEME_CDR((Scheme_Object *)prefix_plus_expr));
|
||||
scheme_suspend_prefix(saved_runstack);
|
||||
|
||||
return v;
|
||||
scheme_ignore_result(v);
|
||||
|
||||
return scheme_void;
|
||||
}
|
||||
|
||||
static int needs_prompt(Scheme_Object *e)
|
||||
|
@ -5632,7 +5634,7 @@ void *scheme_module_run_finish(Scheme_Env *menv, Scheme_Env *env)
|
|||
scheme_make_raw_pair(save_prefix, body));
|
||||
scheme_resume_prefix(save_prefix);
|
||||
} else
|
||||
(void)_scheme_eval_linked_expr_multi(body);
|
||||
scheme_ignore_result(_scheme_eval_linked_expr_multi(body));
|
||||
}
|
||||
|
||||
if (scheme_module_demand_hook) {
|
||||
|
|
|
@ -361,6 +361,8 @@ MZ_EXTERN void scheme_set_tail_buffer_size(int s);
|
|||
MZ_EXTERN Scheme_Object *scheme_force_value(Scheme_Object *);
|
||||
MZ_EXTERN Scheme_Object *scheme_force_one_value(Scheme_Object *);
|
||||
|
||||
XFORM_NONGCING MZ_EXTERN void scheme_ignore_result(Scheme_Object *);
|
||||
|
||||
MZ_EXTERN MZ_MARK_STACK_TYPE scheme_set_cont_mark(Scheme_Object *key, Scheme_Object *val);
|
||||
MZ_EXTERN void scheme_push_continuation_frame(Scheme_Cont_Frame_Data *);
|
||||
MZ_EXTERN void scheme_pop_continuation_frame(Scheme_Cont_Frame_Data *);
|
||||
|
|
|
@ -278,6 +278,7 @@ Scheme_Object *(*scheme_tail_eval_expr)(Scheme_Object *obj);
|
|||
void (*scheme_set_tail_buffer_size)(int s);
|
||||
Scheme_Object *(*scheme_force_value)(Scheme_Object *);
|
||||
Scheme_Object *(*scheme_force_one_value)(Scheme_Object *);
|
||||
void (*scheme_ignore_result)(Scheme_Object *);
|
||||
MZ_MARK_STACK_TYPE (*scheme_set_cont_mark)(Scheme_Object *key, Scheme_Object *val);
|
||||
void (*scheme_push_continuation_frame)(Scheme_Cont_Frame_Data *);
|
||||
void (*scheme_pop_continuation_frame)(Scheme_Cont_Frame_Data *);
|
||||
|
|
|
@ -196,6 +196,7 @@
|
|||
scheme_extension_table->scheme_set_tail_buffer_size = scheme_set_tail_buffer_size;
|
||||
scheme_extension_table->scheme_force_value = scheme_force_value;
|
||||
scheme_extension_table->scheme_force_one_value = scheme_force_one_value;
|
||||
scheme_extension_table->scheme_ignore_result = scheme_ignore_result;
|
||||
scheme_extension_table->scheme_set_cont_mark = scheme_set_cont_mark;
|
||||
scheme_extension_table->scheme_push_continuation_frame = scheme_push_continuation_frame;
|
||||
scheme_extension_table->scheme_pop_continuation_frame = scheme_pop_continuation_frame;
|
||||
|
|
|
@ -196,6 +196,7 @@
|
|||
#define scheme_set_tail_buffer_size (scheme_extension_table->scheme_set_tail_buffer_size)
|
||||
#define scheme_force_value (scheme_extension_table->scheme_force_value)
|
||||
#define scheme_force_one_value (scheme_extension_table->scheme_force_one_value)
|
||||
#define scheme_ignore_result (scheme_extension_table->scheme_ignore_result)
|
||||
#define scheme_set_cont_mark (scheme_extension_table->scheme_set_cont_mark)
|
||||
#define scheme_push_continuation_frame (scheme_extension_table->scheme_push_continuation_frame)
|
||||
#define scheme_pop_continuation_frame (scheme_extension_table->scheme_pop_continuation_frame)
|
||||
|
|
Loading…
Reference in New Issue
Block a user