diff --git a/pkgs/racket-pkgs/racket-test/tests/future/future.rkt b/pkgs/racket-pkgs/racket-test/tests/future/future.rkt index 41b6674268..72d3f3a603 100644 --- a/pkgs/racket-pkgs/racket-test/tests/future/future.rkt +++ b/pkgs/racket-pkgs/racket-test/tests/future/future.rkt @@ -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))))) ) diff --git a/racket/src/racket/src/jit.c b/racket/src/racket/src/jit.c index fcfdc2ef3f..ac2a5cba29 100644 --- a/racket/src/racket/src/jit.c +++ b/racket/src/racket/src/jit.c @@ -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); diff --git a/racket/src/racket/src/jit.h b/racket/src/racket/src/jit.h index 762360933e..3ed6a9170d 100644 --- a/racket/src/racket/src/jit.h +++ b/racket/src/racket/src/jit.h @@ -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 diff --git a/racket/src/racket/src/jit_ts.c b/racket/src/racket/src/jit_ts.c index 5cee7b486c..6d30b865ea 100644 --- a/racket/src/racket/src/jit_ts.c +++ b/racket/src/racket/src/jit_ts.c @@ -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 diff --git a/racket/src/racket/src/jitcommon.c b/racket/src/racket/src/jitcommon.c index 6fdca91c20..07b5e3a94e 100644 --- a/racket/src/racket/src/jitcommon.c +++ b/racket/src/racket/src/jitcommon.c @@ -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 */ { diff --git a/racket/src/racket/src/lightning/i386/core-common.h b/racket/src/racket/src/lightning/i386/core-common.h index bf936a5c5f..590b075998 100644 --- a/racket/src/racket/src/lightning/i386/core-common.h +++ b/racket/src/racket/src/lightning/i386/core-common.h @@ -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 diff --git a/racket/src/racket/src/list.c b/racket/src/racket/src/list.c index 07c0db1abd..fd83ecbfcd 100644 --- a/racket/src/racket/src/list.c +++ b/racket/src/racket/src/list.c @@ -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;