summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-06-19 23:25:33 -0700
committerKaz Kylheku <kaz@kylheku.com>2019-06-19 23:27:48 -0700
commitbd7a10e8fd6fda00f5119db6d9a3bf8bffee1210 (patch)
treeea03ae6d487d38f173d5c34019f3504fe56dc48c
parent9cf992835c8a0f2e6c4ace07b67fea2acb762cc5 (diff)
downloadtxr-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.c62
1 files changed, 38 insertions, 24 deletions
diff --git a/arith.c b/arith.c
index f374ddf4..db9b2deb 100644
--- a/arith.c
+++ b/arith.c
@@ -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;
}