diff --git a/ChangeLog b/ChangeLog index fc9216507..898caa9de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2012-12-18 Paulo Andrade + + * check/stack.ok, check/stack.tst: New files to test data + integrity on a deep chain of stack frames. + + * lib/jit_arm.c, lib/jit_arm-cpu.c, lib/jit_mips.c, + lib/jit_mips-cpu.c, lib/jit_ppc.c, lib/jit_ppc-cpu.c, + lib/jit_x86.c, lib/jit_x86-cpu.c: Calculate _jit->function->stack + in the emit stage, otherwise it will calculate it wrong if + need to jit_allocai space to spill registers. + + * lib/lightning.c: Correct wrong offset when updating the + "current" jit function pointer in the code that may need to + allocate stack space to spill registers. + + * check/lightning.c: Correct off by one data space check. + + * check/Makefile.am: Update for new test case. + 2012-12-17 Paulo Andrade * check/fop_abs.ok, check/fop_abs.tst, check/fop_sqrt.ok, diff --git a/check/Makefile.am b/check/Makefile.am index 890284418..3c3ed0419 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -60,6 +60,7 @@ EXTRA_DIST = \ fop_abs.tst fop_abs.ok \ fop_sqrt.tst fop_sqrt.ok \ varargs.tst varargs.ok \ + stack.tst stack.ok \ check.sh \ check.x87.sh \ check.arm.sh check.swf.sh \ @@ -79,7 +80,7 @@ base_TESTS = \ alu_lsh alu_rsh \ alu_com alu_neg \ fop_abs fop_sqrt \ - varargs + varargs stack $(base_TESTS): check.sh $(LN_S) $(srcdir)/check.sh $@ diff --git a/check/lightning.c b/check/lightning.c index 6c1180264..a336f94ba 100644 --- a/check/lightning.c +++ b/check/lightning.c @@ -37,7 +37,7 @@ #define check_data(length) \ do { \ - if (data_offset + length >= data_length) \ + if (data_offset + length > data_length) \ error(".data too small (%ld < %ld)", \ data_length, data_offset + length); \ } while (0) diff --git a/check/stack.ok b/check/stack.ok new file mode 100644 index 000000000..9766475a4 --- /dev/null +++ b/check/stack.ok @@ -0,0 +1 @@ +ok diff --git a/check/stack.tst b/check/stack.tst new file mode 100644 index 000000000..3870953c5 --- /dev/null +++ b/check/stack.tst @@ -0,0 +1,326 @@ +#define szof_c 1 +#define szof_uc szof_c +#define szof_s 2 +#define szof_us szof_s +#define szof_i 4 +#if __WORDSIZE == 64 +# define szof_ui szof_i +# define szof_l 8 +#endif +#define szof_f 4 +#define szof_d 8 + +#define FILL(T) \ +fill##T: \ + prolog \ + arg $argp \ + getarg %v0 $argp \ + arg $argi \ + getarg %r0 $argi \ + muli %r0 %r0 szof##T \ + addr %v1 %v0 %r0 \ + movi %r0 0 \ +fill##T##loop: \ + bger fill##T##done %v0 %v1 \ + str##T %v0 %r0 \ + addi %r0 %r0 1 \ + addi %v0 %v0 szof##T \ + jmpi fill##T##loop \ +fill##T##done: \ + ret \ + epilog +#define FILLF(T) \ +fill##T: \ + prolog \ + arg $argp \ + getarg %v0 $argp \ + arg $argi \ + getarg %r0 $argi \ + muli %r0 %r0 szof##T \ + addr %v1 %v0 %r0 \ + movi##T %f0 0.0 \ +fill##T##loop: \ + bger fill##T##done %v0 %v1 \ + str##T %v0 %f0 \ + addi##T %f0 %f0 1.0 \ + addi %v0 %v0 szof##T \ + jmpi fill##T##loop \ +fill##T##done: \ + ret \ + epilog + +#define fill_uc fill_c +#define fill_us fill_s +#define fill_ui fill_i + +#define ARG( T, N) arg $arg##T##N +#define ARGF( T, N) arg##T $arg##T##N +#define ARG1( K, T) ARG##K(T, 0) +#define ARG2( K, T) ARG1( K, T) ARG##K(T, 1) +#define ARG3( K, T) ARG2( K, T) ARG##K(T, 2) +#define ARG4( K, T) ARG3( K, T) ARG##K(T, 3) +#define ARG5( K, T) ARG4( K, T) ARG##K(T, 4) +#define ARG6( K, T) ARG5( K, T) ARG##K(T, 5) +#define ARG7( K, T) ARG6( K, T) ARG##K(T, 6) +#define ARG8( K, T) ARG7( K, T) ARG##K(T, 7) +#define ARG9( K, T) ARG8( K, T) ARG##K(T, 8) +#define ARG10(K, T) ARG9( K, T) ARG##K(T, 9) +#define ARG11(K, T) ARG10(K, T) ARG##K(T, 10) +#define ARG12(K, T) ARG11(K, T) ARG##K(T, 11) +#define ARG13(K, T) ARG12(K, T) ARG##K(T, 12) +#define ARG14(K, T) ARG13(K, T) ARG##K(T, 13) +#define ARG15(K, T) ARG14(K, T) ARG##K(T, 14) +#define ARG16(K, T) ARG15(K, T) ARG##K(T, 15) +#define ARG_c(N) ARG##N( , _c) +#define ARG_uc(N) ARG##N( , _uc) +#define ARG_s(N) ARG##N( , _s) +#define ARG_us(N) ARG##N( , _us) +#define ARG_i(N) ARG##N( , _i) +#define ARG_ui(N) ARG##N( , _ui) +#define ARG_l(N) ARG##N( , _l) +#define ARG_f(N) ARG##N(F, _f) +#define ARG_d(N) ARG##N(F, _d) + +#define CHK(N, T, V) \ + getarg %r0 $arg##T##V \ + ldxi##T %r1 %v0 $(V * szof##T) \ + beqr N##T##V %r0 %r1 \ + calli @abort \ +N##T##V: +#define CHKF(N, T, V) \ + getarg##T %f0 $arg##T##V \ + ldxi##T %f1 %v0 $(V * szof##T) \ + beqr##T N##T##V %f0 %f1 \ + calli @abort \ +N##T##V: + +#define GET1( K, N, T, V) CHK##K(N, T, 0) +#define GET2( K, N, T, V) GET1( K, N, T, V) CHK##K(N, T, 1) +#define GET3( K, N, T, V) GET2( K, N, T, V) CHK##K(N, T, 2) +#define GET4( K, N, T, V) GET3( K, N, T, V) CHK##K(N, T, 3) +#define GET5( K, N, T, V) GET4( K, N, T, V) CHK##K(N, T, 4) +#define GET6( K, N, T, V) GET5( K, N, T, V) CHK##K(N, T, 5) +#define GET7( K, N, T, V) GET6( K, N, T, V) CHK##K(N, T, 6) +#define GET8( K, N, T, V) GET7( K, N, T, V) CHK##K(N, T, 7) +#define GET9( K, N, T, V) GET8( K, N, T, V) CHK##K(N, T, 8) +#define GET10(K, N, T, V) GET9( K, N, T, V) CHK##K(N, T, 9) +#define GET11(K, N, T, V) GET10(K, N, T, V) CHK##K(N, T, 10) +#define GET12(K, N, T, V) GET11(K, N, T, V) CHK##K(N, T, 11) +#define GET13(K, N, T, V) GET12(K, N, T, V) CHK##K(N, T, 12) +#define GET14(K, N, T, V) GET13(K, N, T, V) CHK##K(N, T, 13) +#define GET15(K, N, T, V) GET14(K, N, T, V) CHK##K(N, T, 14) +#define GET16(K, N, T, V) GET15(K, N, T, V) CHK##K(N, T, 15) + +#define GET_c(N, M) GET##N( , c##N, _c, M) +#define GET_uc(N, M) GET##N( , uc##N, _uc, M) +#define GET_s(N, M) GET##N( , s##N, _s, M) +#define GET_us(N, M) GET##N( , us##N, _us, M) +#define GET_i(N, M) GET##N( , i##N, _i, M) +#define GET_ui(N, M) GET##N( , ui##N, _ui, M) +#define GET_l(N, M) GET##N( , l##N, _l, M) +#define GET_f(N, M) GET##N(F, f##N, _f, M) +#define GET_d(N, M) GET##N(F, d##N, _d, M) + +#define PUSH( T, V) pushargi V +#define PUSHF( T, V) pushargi##T V +#define PUSH0( K, T) /**/ +#define PUSH1( K, T) PUSH##K(T, 0) +#define PUSH2( K, T) PUSH1( K, T) PUSH##K(T, 1) +#define PUSH3( K, T) PUSH2( K, T) PUSH##K(T, 2) +#define PUSH4( K, T) PUSH3( K, T) PUSH##K(T, 3) +#define PUSH5( K, T) PUSH4( K, T) PUSH##K(T, 4) +#define PUSH6( K, T) PUSH5( K, T) PUSH##K(T, 5) +#define PUSH7( K, T) PUSH6( K, T) PUSH##K(T, 6) +#define PUSH8( K, T) PUSH7( K, T) PUSH##K(T, 7) +#define PUSH9( K, T) PUSH8( K, T) PUSH##K(T, 8) +#define PUSH10(K, T) PUSH9( K, T) PUSH##K(T, 9) +#define PUSH11(K, T) PUSH10(K, T) PUSH##K(T, 10) +#define PUSH12(K, T) PUSH11(K, T) PUSH##K(T, 11) +#define PUSH13(K, T) PUSH12(K, T) PUSH##K(T, 12) +#define PUSH14(K, T) PUSH13(K, T) PUSH##K(T, 13) +#define PUSH15(K, T) PUSH14(K, T) PUSH##K(T, 14) +#define PUSH16(K, T) PUSH15(K, T) PUSH##K(T, 15) + +#define PUSH_c( N) PUSH##N( , _c) +#define PUSH_uc(N) PUSH##N( , _uc) +#define PUSH_s( N) PUSH##N( , _s) +#define PUSH_us(N) PUSH##N( , _us) +#define PUSH_i( N) PUSH##N( , _i) +#define PUSH_ui(N) PUSH##N( , _ui) +#define PUSH_l( N) PUSH##N( , _l) +#define PUSH_f( N) PUSH##N(F, _f) +#define PUSH_d( N) PUSH##N(F, _d) + +/* bottom function */ +#define DEF0(T) \ +test##T##_0: \ + prolog \ + ret \ + epilog + +#define DEFN(N, M, T) \ +test##T##_##N: \ + prolog \ + arg $argp \ + /* stack buffer in %v0 */ \ + getarg %v0 $argp \ + ARG##T(N) \ + /* validate arguments */ \ + GET##T(N, M) \ + /* heap buffer in %v1 */ \ + prepare \ + pushargi $(N * szof##T) \ + finishi @malloc \ + retval %v1 \ + /* copy stack bufer to heap buffer */ \ + prepare \ + pushargr %v1 \ + pushargr %v0 \ + pushargi $(N * szof##T) \ + finishi @memcpy \ + /* stack buffer for next function in %v2 */ \ + allocai $(M * szof##T) $index \ + addi %v2 %fp $index \ + /* fill stack buffer for next function */ \ + prepare \ + pushargr %v2 \ + pushargi M \ + finishi fill##T \ + /* call next function */ \ + prepare \ + pushargr %v2 \ + PUSH##T(M) \ + finishi test##T##_##M \ + /* validate stack buffer */ \ + prepare \ + pushargr %v1 \ + pushargr %v0 \ + pushargi $(N * szof##T) \ + finishi @memcmp \ + retval %r0 \ + beqi test##T##_##N##_done %r0 0 \ + calli @abort \ +test##T##_##N##_done: \ + /* release heap bufer */ \ + prepare \ + pushargr %v1 \ + finishi @free \ + ret \ + epilog + +/* top function */ +#define DEFX(T) \ +test##T##_17: \ + prolog \ + /* heap buffer in %v1 */ \ + prepare \ + pushargi $(16 * szof##T) \ + finishi @malloc \ + retval %v1 \ + /* stack buffer for next function in %v2 */ \ + allocai $(16 * szof##T) $index \ + addi %v2 %fp $index \ + /* fill stack buffer for next function */ \ + prepare \ + pushargr %v2 \ + pushargi 16 \ + finishi fill##T \ + /* copy stack buffer to heap buffer */ \ + prepare \ + pushargr %v1 \ + pushargr %v2 \ + pushargi $(16 * szof##T) \ + finishi @memcpy \ + /* call next function */ \ + prepare \ + pushargr %v2 \ + PUSH##T(16) \ + finishi test##T##_16 \ + /* validate stack buffer */ \ + prepare \ + pushargr %v1 \ + pushargr %v2 \ + pushargi $(16 * szof##T) \ + finishi @memcmp \ + retval %r0 \ + beqi test##T##_17_done %r0 0 \ + calli @abort \ +test##T##_17_done: \ + /* release heap bufer */ \ + prepare \ + pushargr %v1 \ + finishi @free \ + ret \ + epilog + +#define DEF( T) \ + DEF0( T) \ + DEFN( 1, 0, T) \ + DEFN( 2, 1, T) \ + DEFN( 3, 2, T) \ + DEFN( 4, 3, T) \ + DEFN( 5, 4, T) \ + DEFN( 6, 5, T) \ + DEFN( 7, 6, T) \ + DEFN( 8, 7, T) \ + DEFN( 9, 8, T) \ + DEFN(10, 9, T) \ + DEFN(11, 10, T) \ + DEFN(12, 11, T) \ + DEFN(13, 12, T) \ + DEFN(14, 13, T) \ + DEFN(15, 14, T) \ + DEFN(16, 15, T) \ + DEFX(T) + +#define CALL(T) calli test##T##_17 + +.data 16 +ok: +.c "ok\n" +.code + jmpi main + + FILL(_c) + FILL(_s) + FILL(_i) +#if __WORDSIZE == 64 + FILL(_l) +#endif + FILLF(_f) + FILLF(_d) + + DEF(_c) + DEF(_uc) + DEF(_s) + DEF(_us) + DEF(_i) +#if __WORDSIZE == 64 + DEF(_ui) + DEF(_l) +#endif + DEF(_f) + DEF(_d) + +main: + prolog + + CALL(_c) + CALL(_uc) + CALL(_s) + CALL(_us) + CALL(_i) +#if __WORDSIZE == 64 + CALL(_ui) + CALL(_l) +#endif + CALL(_f) + CALL(_d) + + prepare + pushargi ok + ellipsis + finishi @printf + + ret + epilog diff --git a/lib/jit_arm-cpu.c b/lib/jit_arm-cpu.c index 1922a6cbb..cf1be0fae 100644 --- a/lib/jit_arm-cpu.c +++ b/lib/jit_arm-cpu.c @@ -3564,6 +3564,10 @@ _calli_p(jit_state_t *_jit, jit_word_t i0) static void _prolog(jit_state_t *_jit, jit_node_t *node) { + _jit->function->stack = ((_jit->function->self.alen - + /* align stack at 8 bytes */ + _jit->function->self.aoff) + 7) & -8; + if (jit_thumb_p()) { /* switch to thumb mode (better approach would be to * ORR 1 address being called, but no clear distinction diff --git a/lib/jit_arm.c b/lib/jit_arm.c index 1c66b223c..fab42aa1b 100644 --- a/lib/jit_arm.c +++ b/lib/jit_arm.c @@ -322,9 +322,6 @@ void _jit_epilog(jit_state_t *_jit) { assert(_jit->function); - _jit->function->stack = ((_jit->function->self.alen - - /* align stack at 8 bytes */ - _jit->function->self.aoff) + 7) & -8; assert(_jit->function->epilog->next == NULL); jit_link(_jit->function->epilog); _jit->function = NULL; diff --git a/lib/jit_mips-cpu.c b/lib/jit_mips-cpu.c index 87493005c..5e5c598db 100644 --- a/lib/jit_mips-cpu.c +++ b/lib/jit_mips-cpu.c @@ -2697,6 +2697,11 @@ _calli(jit_state_t *_jit, jit_word_t i0) static void _prolog(jit_state_t *_jit, jit_node_t *node) { + _jit->function->stack = ((/* first 16 bytes must be allocated */ + (_jit->function->self.alen > 16 ? + _jit->function->self.alen : 16) - + /* align stack at 8 bytes */ + _jit->function->self.aoff) + 7) & -8; /* callee save registers */ subi(_SP_REGNO, _SP_REGNO, stack_framesize); #if __WORDSIZE == 32 diff --git a/lib/jit_mips.c b/lib/jit_mips.c index d3cca00cb..1773b5db1 100644 --- a/lib/jit_mips.c +++ b/lib/jit_mips.c @@ -224,12 +224,6 @@ void _jit_epilog(jit_state_t *_jit) { assert(_jit->function); - - _jit->function->stack = ((/* first 16 bytes must be allocated */ - (_jit->function->self.alen > 16 ? - _jit->function->self.alen : 16) - - /* align stack at 8 bytes */ - _jit->function->self.aoff) + 7) & -8; assert(_jit->function->epilog->next == NULL); jit_link(_jit->function->epilog); _jit->function = NULL; @@ -266,13 +260,20 @@ _jit_arg_f(jit_state_t *_jit) assert(_jit->function); offset = (_jit->function->self.size - stack_framesize) >> 2; - if (offset < 4) { + if (offset < 3) { if (!_jit->function->self.argi) { offset += 4; _jit->function->self.argf += 2; + assert(!(offset & 1)); } - else + else { _jit->function->self.argi += 2; + if (offset & 1) { + ++_jit->function->self.argi; + ++offset; + _jit->function->self.size += sizeof(jit_float32_t); + } + } } else offset = _jit->function->self.size; @@ -395,7 +396,7 @@ void _jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_int32_t v) { if (v < 4) - jit_new_node_ww(jit_code_getarg_f, u, _A0 - (v >> 1)); + jit_new_node_ww(jit_code_getarg_f, u, _A0 - v); else if (v < 8) jit_movr_f(u, _F12 - ((v - 4) >> 1)); else @@ -406,7 +407,7 @@ void _jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_int32_t v) { if (v < 4) - jit_new_node_ww(jit_code_getarg_d, u, _A0 - (v >> 1)); + jit_new_node_ww(jit_code_getarg_d, u, _A0 - v); else if (v < 8) jit_movr_d(u, _F12 - ((v - 4) >> 1)); else diff --git a/lib/jit_ppc-cpu.c b/lib/jit_ppc-cpu.c index 05bebf2bc..0f9b34348 100644 --- a/lib/jit_ppc-cpu.c +++ b/lib/jit_ppc-cpu.c @@ -2363,6 +2363,9 @@ _prolog(jit_state_t *_jit, jit_node_t *node) { unsigned long regno; + _jit->function->stack = ((_jit->function->self.alen - + _jit->function->self.aoff) + 15) & -16; + /* return address */ MFLR(_R0_REGNO); diff --git a/lib/jit_ppc.c b/lib/jit_ppc.c index df6007ebd..9fdc10d29 100644 --- a/lib/jit_ppc.c +++ b/lib/jit_ppc.c @@ -230,8 +230,6 @@ void _jit_epilog(jit_state_t *_jit) { assert(_jit->function); - _jit->function->stack = ((_jit->function->self.alen - - _jit->function->self.aoff) + 15) & -16; assert(_jit->function->epilog->next == NULL); jit_link(_jit->function->epilog); _jit->function = NULL; diff --git a/lib/jit_x86-cpu.c b/lib/jit_x86-cpu.c index ed02008aa..197f7800a 100644 --- a/lib/jit_x86-cpu.c +++ b/lib/jit_x86-cpu.c @@ -20,8 +20,6 @@ #if PROTO # if __WORDSIZE == 32 -# define stack_alignment 4 -# define stack_framesize 20 # define ldi(u, v) ldi_i(u, v) # define ldxi(u, v, w) ldxi_i(u, v, w) # define sti(u, v) sti_i(u, v) @@ -32,8 +30,6 @@ # define reg8_p(rn) \ ((rn) >= _RAX_REGNO && (rn) <= _RBX_REGNO) # else -# define stack_alignment 8 -# define stack_framesize 56 # define ldi(u, v) ldi_l(u, v) # define ldxi(u, v, w) ldxi_l(u, v, w) # define sti(u, v) sti_l(u, v) @@ -3070,6 +3066,14 @@ _jmpi(jit_state_t *_jit, jit_word_t i0) static void _prolog(jit_state_t *_jit, jit_node_t *node) { +#if __WORDSIZE == 32 + _jit->function->stack = (((_jit->function->self.alen - + _jit->function->self.aoff) + 15) & -16) + 12; +#else + _jit->function->stack = (((_jit->function->self.alen - + _jit->function->self.aoff) + 15) & -16) + 8; +#endif + /* callee save registers */ subi(_RSP_REGNO, _RSP_REGNO, stack_framesize - sizeof(jit_word_t)); #if __WORDSIZE == 32 diff --git a/lib/jit_x86.c b/lib/jit_x86.c index a06bf908a..dad35c432 100644 --- a/lib/jit_x86.c +++ b/lib/jit_x86.c @@ -268,8 +268,10 @@ jit_get_cpu(void) void _jit_init(jit_state_t *_jit) { +#if __WORDSIZE == 32 jit_int32_t regno; static jit_bool_t first = 1; +#endif _jit->reglen = jit_size(_rvs) - 1; #if __WORDSIZE == 32 @@ -400,13 +402,6 @@ void _jit_epilog(jit_state_t *_jit) { assert(_jit->function); -#if __WORDSIZE == 32 - _jit->function->stack = (((_jit->function->self.alen - - _jit->function->self.aoff) + 15) & -16) + 12; -#else - _jit->function->stack = (((_jit->function->self.alen - - _jit->function->self.aoff) + 15) & -16) + 8; -#endif assert(_jit->function->epilog->next == NULL); jit_link(_jit->function->epilog); _jit->function = NULL; @@ -448,7 +443,11 @@ _jit_arg_f(jit_state_t *_jit) return (_jit->function->self.argf++); #endif offset = _jit->function->self.size; +#if __WORDSIZE == 32 _jit->function->self.size += sizeof(jit_float32_t); +#else + _jit->function->self.size += sizeof(jit_float64_t); +#endif return (offset); } diff --git a/lib/lightning.c b/lib/lightning.c index dc9dcd9dc..b9db321a9 100644 --- a/lib/lightning.c +++ b/lib/lightning.c @@ -2298,7 +2298,7 @@ _patch_registers(jit_state_t *_jit) node->link = NULL; break; case jit_code_prolog: - _jit->function = _jit->functions.ptr + node->u.w; + _jit->function = _jit->functions.ptr + node->w.w; break; case jit_code_epilog: _jit->function = NULL;