diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-06-19 23:25:33 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-06-19 23:27:48 -0700 |
commit | bd7a10e8fd6fda00f5119db6d9a3bf8bffee1210 (patch) | |
tree | ea03ae6d487d38f173d5c34019f3504fe56dc48c | |
parent | 9cf992835c8a0f2e6c4ace07b67fea2acb762cc5 (diff) | |
download | txr-bd7a10e8fd6fda00f5119db6d9a3bf8bffee1210.tar.gz txr-bd7a10e8fd6fda00f5119db6d9a3bf8bffee1210.tar.bz2 txr-bd7a10e8fd6fda00f5119db6d9a3bf8bffee1210.zip |
ash: refactor in light of gc bug.
* arith.c (ash): Introduce smaller scopes and move variable
initializations close to their use. The NUM case of argument
a no longer falls through to the BGNUM case, and doesn't
cons up a bignum object. Rather, a temporary mp_int is
allocated, used and freed. The gc_hint added in the previous
commit is now gone.
-rw-r--r-- | arith.c | 62 |
1 files changed, 38 insertions, 24 deletions
@@ -3198,9 +3198,7 @@ val ash(val a, val bits) { val self = ash_s; type_t ta = type(a); - cnum an, bn; - val b; - int hb; + cnum bn; const int num_bits = CHAR_BIT * sizeof (cnum) - TAG_SHIFT; mp_err mpe = MP_OKAY; @@ -3223,36 +3221,52 @@ val ash(val a, val bits) } else if (bn > 0) { switch (ta) { case NUM: - an = c_n(a); - hb = highest_significant_bit(an); - if (bn + hb < num_bits) - return num_fast(an << bn); - a = bignum(an); - /* fallthrough */ + { + cnum an = c_n(a); + int hb = highest_significant_bit(an); + if (bn + hb < num_bits) { + return num_fast(an << bn); + } else { + val b = make_bignum(); + mp_int tmp; + mp_init(&tmp); + mp_set_intptr(&tmp, an); + mpe = mp_shift(&tmp, mp(b), bn); + mp_clear(&tmp); + if (mpe != MP_OKAY) + break; + return normalize(b); + } + } case BGNUM: - if (bn < INT_MIN || bn > INT_MAX) + if (bn < INT_MIN || bn > INT_MAX) { goto bad4; - b = make_bignum(); - if ((mpe = mp_shift(mp(a), mp(b), bn)) != MP_OKAY) - break; - gc_hint(a); - return normalize(b); + } else { + val b = make_bignum(); + if ((mpe = mp_shift(mp(a), mp(b), bn)) != MP_OKAY) + break; + return normalize(b); + } default: goto bad3; } } else { switch (ta) { case NUM: - bn = -bn; - an = c_n(a); - if (bn <= num_bits) - return num_fast(an >> bn); - return num_fast(an >> num_bits); + { + cnum an = c_n(a); + bn = -bn; + if (bn <= num_bits) + return num_fast(an >> bn); + return num_fast(an >> num_bits); + } case BGNUM: - b = make_bignum(); - if ((mpe = mp_shift(mp(a), mp(b), bn)) != MP_OKAY) - break; - return normalize(b); + { + val b = make_bignum(); + if ((mpe = mp_shift(mp(a), mp(b), bn)) != MP_OKAY) + break; + return normalize(b); + } default: goto bad3; } |