futures: fix rest-arg list creation

Also, make rest-arg list creation safe for futures (and slightly
faster in general).

Closes PR 13832
This commit is contained in:
Matthew Flatt 2013-08-26 19:57:31 -06:00
parent c5e9aced2b
commit 392a8219ae
7 changed files with 199 additions and 71 deletions

View File

@ -889,6 +889,15 @@ We should also test deep continuations.
(check-exn exn:fail:contract? (λ () (touch fb)))
(check-exn exn:fail:contract? (λ () (touch fc)))
(check-exn exn:fail:contract? (λ () (touch fd))))
;; Check rest args
(let ([g #f])
(set! g (lambda x x))
(define f (for/list ([i 10])
(future (lambda () (g 1 2 3)))))
(check-true (andmap (lambda (v) (equal? '(1 2 3) v))
(for/list ([f (in-list f)]) (touch f)))))
)

View File

@ -3321,7 +3321,6 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data)
/* If runstack == argv and argc == cnt, then we didn't
copy args down, and we need to make room for scheme_null. */
GC_CAN_IGNORE jit_insn *ref, *ref2, *ref3;
GC_CAN_IGNORE jit_insn *refrts USED_ONLY_FOR_FUTURES;
CHECK_LIMIT();
@ -3331,14 +3330,12 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data)
ref = jit_bner_p(jit_forward(), JIT_RUNSTACK, JIT_R2);
/* check whether we have at least one rest arg: */
ref3 = jit_bgti_p(jit_forward(), JIT_R1, cnt);
/* yes and yes: make room for the copy */
jit_subi_p(JIT_RUNSTACK, JIT_RUNSTACK, WORDS_TO_BYTES(cnt+1));
/* yes and no: make room for the scheme_null */
jit_subi_p(JIT_RUNSTACK, JIT_RUNSTACK, WORDS_TO_BYTES(1));
CHECK_RUNSTACK_OVERFLOW();
for (i = cnt; i--; ) {
jit_ldxi_p(JIT_V1, JIT_R2, WORDS_TO_BYTES(i));
for (i = 0; i < cnt; i++) {
jit_ldxi_p(JIT_V1, JIT_RUNSTACK, WORDS_TO_BYTES(i+1));
jit_stxi_p(WORDS_TO_BYTES(i), JIT_RUNSTACK, JIT_V1);
/* space safety: */
jit_stxi_p(WORDS_TO_BYTES(i), JIT_R2, JIT_RUNSTACK);
CHECK_LIMIT();
}
(void)jit_movi_p(JIT_V1, scheme_null);
@ -3350,40 +3347,16 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data)
mz_patch_branch(ref);
mz_patch_branch(ref3);
CHECK_LIMIT();
#ifndef JIT_PRECISE_GC
if (data->closure_size)
#endif
{
mz_pushr_p(JIT_R0);
mz_rs_sync();
}
JIT_UPDATE_THREAD_RSPTR();
CHECK_LIMIT();
jit_movi_i(JIT_V1, cnt);
if ((SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_NEED_REST_CLEAR)) {
/* negative count => clear argv */
GC_CAN_IGNORE jit_insn *ref;
__START_INNER_TINY__(cnt < 100);
ref = jit_bner_p(jit_forward(), JIT_RUNSTACK, JIT_R2);
jit_negr_i(JIT_R1, JIT_R1);
mz_patch_branch(ref);
__END_INNER_TINY__(cnt < 100);
}
mz_prepare(3);
jit_pusharg_i(JIT_V1);
jit_pusharg_p(JIT_R2);
jit_pusharg_i(JIT_R1);
CHECK_LIMIT();
(void)mz_finish_lwe(ts_scheme_build_list_offset, refrts);
jit_retval(JIT_V1);
#ifndef JIT_PRECISE_GC
if (data->closure_size)
#endif
{
mz_popr_p(JIT_R0);
mz_rs_sync();
}
mz_set_local_p(JIT_V1, JIT_LOCAL3);
mz_rs_sync();
if ((SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_NEED_REST_CLEAR))
(void)jit_calli(sjc.make_rest_list_clear_code);
else
(void)jit_calli(sjc.make_rest_list_code);
jit_stxi_p(WORDS_TO_BYTES(cnt), JIT_RUNSTACK, JIT_V1);
mz_patch_ucbranch(ref2); /* jump here if we copied and produced null */
__END_SHORT_JUMPS__(cnt < 100);

View File

@ -359,6 +359,7 @@ struct scheme_jit_common_record {
void *retry_alloc_code_keep_extfpr1;
# endif
#endif
void *make_rest_list_code, *make_rest_list_clear_code;
Continuation_Apply_Indirect continuation_apply_indirect_code;
#ifdef MZ_USE_LWC

View File

@ -29,7 +29,6 @@ define_ts_n_s(scheme_make_native_case_closure, FSRC_OTHER)
# ifndef CAN_INLINE_ALLOC
define_ts_s_s(scheme_make_envunbox, FSRC_OTHER)
# endif
define_ts_iSi_s(scheme_build_list_offset, FSRC_OTHER)
#endif
#ifdef JITARITH_TS_PROCS
@ -104,6 +103,9 @@ define_ts_iS_s(scheme_box_cas, FSRC_MARKS)
define_ts__v(chaperone_set_mark, FSRC_MARKS)
define_ts_iS_s(scheme_checked_char_to_integer, FSRC_MARKS)
define_ts_iS_s(scheme_checked_integer_to_char, FSRC_MARKS)
# ifndef CAN_INLINE_ALLOC
define_ts_iSi_s(scheme_build_list_offset, FSRC_OTHER)
# endif
#endif
#ifdef JITCALL_TS_PROCS

View File

@ -2146,6 +2146,64 @@ static int common4c(mz_jit_state *jitter, void *_data)
return 1;
}
#ifdef CAN_INLINE_ALLOC
static int generate_make_list(mz_jit_state *jitter, int star, int clear,
int offset_pos, int base_pos)
/* R2 has length; args are on runstack; if offset_pos, offset is on runstack
result is in R0; uses R1, R2, and V1 */
{
GC_CAN_IGNORE jit_insn *ref, *refnext;
jit_lshi_l(JIT_R2, JIT_R2, JIT_LOG_WORD_SIZE);
if (!star)
(void)jit_movi_p(JIT_R0, &scheme_null);
else {
jit_subi_l(JIT_R2, JIT_R2, JIT_WORD_SIZE);
jit_ldxr_p(JIT_R0, JIT_RUNSTACK, JIT_R2);
}
__START_SHORT_JUMPS__(1);
ref = jit_beqi_l(jit_forward(), JIT_R2, 0);
refnext = jit_get_ip();
__END_SHORT_JUMPS__(1);
CHECK_LIMIT();
jit_subi_l(JIT_R2, JIT_R2, JIT_WORD_SIZE);
if (offset_pos >= 0) {
jit_ldxi_p(JIT_V1, JIT_RUNSTACK, WORDS_TO_BYTES(offset_pos));
jit_rshi_l(JIT_V1, JIT_V1, 1);
jit_addr_l(JIT_V1, JIT_V1, JIT_R2);
if (base_pos >= 0) {
jit_ldxi_p(JIT_R1, JIT_RUNSTACK, WORDS_TO_BYTES(base_pos));
jit_ldxr_p(JIT_R1, JIT_R1, JIT_V1);
} else {
jit_ldxr_p(JIT_R1, JIT_RUNSTACK, JIT_V1);
if (clear)
jit_stxr_p(JIT_V1, JIT_RUNSTACK, JIT_RUNSTACK);
}
} else {
jit_ldxr_p(JIT_R1, JIT_RUNSTACK, JIT_R2);
if (clear)
jit_stxr_p(JIT_R2, JIT_RUNSTACK, JIT_RUNSTACK);
}
mz_set_local_p(JIT_R2, JIT_LOCAL3);
scheme_generate_cons_alloc(jitter, 1, 1, !star, JIT_R0);
CHECK_LIMIT();
mz_get_local_p(JIT_R2, JIT_LOCAL3);
__START_SHORT_JUMPS__(1);
(void)jit_bnei_l(refnext, JIT_R2, 0);
mz_patch_branch(ref);
__END_SHORT_JUMPS__(1);
return 1;
}
#endif
static int common5(mz_jit_state *jitter, void *_data)
{
int i, ii, iii;
@ -2182,45 +2240,130 @@ static int common5(mz_jit_state *jitter, void *_data)
/* *** make_list_code *** */
/* R2 has length, args are on runstack */
for (i = 0; i < 2; i++) {
GC_CAN_IGNORE jit_insn *ref, *refnext;
if (i == 0)
sjc.make_list_code = jit_get_ip();
else
sjc.make_list_star_code = jit_get_ip();
mz_prolog(JIT_R1);
jit_lshi_l(JIT_R2, JIT_R2, JIT_LOG_WORD_SIZE);
if (i == 0)
(void)jit_movi_p(JIT_R0, &scheme_null);
else {
jit_subi_l(JIT_R2, JIT_R2, JIT_WORD_SIZE);
jit_ldxr_p(JIT_R0, JIT_RUNSTACK, JIT_R2);
}
__START_SHORT_JUMPS__(1);
ref = jit_beqi_l(jit_forward(), JIT_R2, 0);
refnext = jit_get_ip();
__END_SHORT_JUMPS__(1);
generate_make_list(jitter, i, 0, -1, -1);
CHECK_LIMIT();
jit_subi_l(JIT_R2, JIT_R2, JIT_WORD_SIZE);
jit_ldxr_p(JIT_R1, JIT_RUNSTACK, JIT_R2);
mz_set_local_p(JIT_R2, JIT_LOCAL3);
scheme_generate_cons_alloc(jitter, 1, 1, !i, JIT_R0);
CHECK_LIMIT();
mz_get_local_p(JIT_R2, JIT_LOCAL3);
__START_SHORT_JUMPS__(1);
(void)jit_bnei_l(refnext, JIT_R2, 0);
mz_patch_branch(ref);
__END_SHORT_JUMPS__(1);
mz_epilog(JIT_R1);
}
#endif
/* *** make_rest_list[_clear]_code *** */
/* R1 (int) has count, local3 has offset, R2 has argv, R0 should be preserved */
for (i = 0; i < 2; i++) {
/* Save R0 on runstack. If argv is the runstack, we need to
pretend that the saved R0 is an argument, so that things
work out right with futures (where argv must match runstack
if argv is in the runstack). */
GC_CAN_IGNORE jit_insn *ref;
if (i == 0)
sjc.make_rest_list_code = jit_get_ip();
else
sjc.make_rest_list_clear_code = jit_get_ip();
mz_prolog(JIT_V1);
mz_get_local_p(JIT_V1, JIT_LOCAL3);
#ifdef CAN_INLINE_ALLOC
{
GC_CAN_IGNORE jit_insn *ref2;
jit_subr_i(JIT_R1, JIT_R1, JIT_V1);
jit_lshi_l(JIT_V1, JIT_V1, JIT_LOG_WORD_SIZE);
__START_SHORT_JUMPS__(1);
ref = jit_bner_p(jit_forward(), JIT_RUNSTACK, JIT_R2);
__END_SHORT_JUMPS__(1);
/* runstack mode */
mz_pushr_p(JIT_R0);
jit_extr_i_l(JIT_R2, JIT_R1);
jit_addi_l(JIT_V1, JIT_V1, WORDS_TO_BYTES(2)); /* skip r0 and v1 */
jit_fixnum_l(JIT_V1, JIT_V1);
mz_pushr_p(JIT_V1);
mz_rs_sync();
generate_make_list(jitter, 0, i, 0, -1);
CHECK_LIMIT();
jit_movr_p(JIT_V1, JIT_R0);
mz_popr_p(JIT_R0);
mz_popr_p(JIT_R0);
mz_rs_sync();
__START_SHORT_JUMPS__(1);
ref2 = jit_jmpi(jit_forward());
mz_patch_branch(ref);
__END_SHORT_JUMPS__(1);
CHECK_LIMIT();
/* V2 (not on runstack) mode */
mz_pushr_p(JIT_R0);
jit_fixnum_l(JIT_V1, JIT_V1);
mz_pushr_p(JIT_V1);
mz_pushr_p(JIT_R2);
mz_rs_sync();
jit_extr_i_l(JIT_R2, JIT_R1);
generate_make_list(jitter, 0, 0, 1, 0);
CHECK_LIMIT();
jit_movr_p(JIT_V1, JIT_R0);
mz_popr_p(JIT_R0);
mz_popr_p(JIT_R0);
mz_popr_p(JIT_R0);
mz_rs_sync();
__START_SHORT_JUMPS__(1);
mz_patch_branch(ref2);
__END_SHORT_JUMPS__(1);
CHECK_LIMIT();
}
#else
{
GC_CAN_IGNORE jit_insn *refrts USED_ONLY_FOR_FUTURES;
/* Save R0 on runstack. If argv is the runstack, we need to
pretend that the saved R0 is an argument, so that things
work out right with futures (where argv must match runstack
if argv is in the runstack). */
__START_TINY_JUMPS__(1);
ref = jit_bner_p(jit_forward(), JIT_RUNSTACK, JIT_R2);
# ifdef MZ_USE_FUTURES
jit_addi_i(JIT_R1, JIT_R1, 1);
jit_addi_i(JIT_V1, JIT_V1, 1);
jit_subi_p(JIT_R2, JIT_R2, WORDS_TO_BYTES(1));
# endif
if (i) {
/* negative count tells build_list_offset to clear argv */
jit_negr_i(JIT_R1, JIT_R1);
}
mz_patch_branch(ref);
__END_TINY_JUMPS__(1);
mz_pushr_p(JIT_R0);
mz_rs_sync();
JIT_UPDATE_THREAD_RSPTR();
CHECK_LIMIT();
mz_prepare(3);
jit_pusharg_i(JIT_V1);
jit_pusharg_p(JIT_R2); /* for futures, must match JIT_RUNSTACK if argv is on runstack */
jit_pusharg_i(JIT_R1);
CHECK_LIMIT();
(void)mz_finish_lwe(ts_scheme_build_list_offset, refrts);
jit_retval(JIT_V1);
mz_popr_p(JIT_R0);
mz_rs_sync();
}
#endif
mz_epilog(JIT_R2);
}
/* *** box_flonum_from_stack_code *** */
/* R0 has offset from frame pointer to double on stack */
{

View File

@ -245,7 +245,7 @@ static jit_state _jit;
# if defined(JIT_X86_64)
# define jit_extr_i_l(d, rs) (jit_lshi_l((d), (rs), 32), jit_rshi_l((d), (d), 32))
# else
# define jit_extr_i_l(d, rs) /* empty */
# define jit_extr_i_l(d, rs) jit_movr_i(d, rs)
# endif
#endif
#ifndef jit_extr_c_ul
@ -258,7 +258,7 @@ static jit_state _jit;
# if defined(JIT_X86_64)
# define jit_extr_i_ul(d, rs) jit_andi_l((d), (rs), 0xFFFFFFFFUL)
# else
# define jit_extr_i_ul(d, rs) /* empty */
# define jit_extr_i_ul(d, rs) jit_movr_i(d, rs)
# endif
#endif
#endif

View File

@ -910,7 +910,7 @@ Scheme_Object *scheme_build_list(int size, Scheme_Object **argv)
}
Scheme_Object *scheme_build_list_offset(int size, Scheme_Object **argv, int delta)
/* clears originals in argv for space safety! */
/* if size < 0, clears originals in argv for space safety */
{
Scheme_Object *pair = scheme_null;
int i;