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:
parent
c5e9aced2b
commit
392a8219ae
|
@ -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)))))
|
||||
|
||||
)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user