~ chicken-core (chicken-5) a04069e4a4f44412931574cba3efcd82a33eea13


commit a04069e4a4f44412931574cba3efcd82a33eea13
Author:     Peter Bex <peter@more-magic.net>
AuthorDate: Tue Apr 7 22:29:01 2015 +0200
Commit:     Peter Bex <peter@more-magic.net>
CommitDate: Sun May 31 14:55:25 2015 +0200

    Convert the final procedure that uses C_bignum_allocate to use the scratch space.
    
    This allows us to can get rid of C_bignum_allocate.  The converted
    procedure was C_u_flo_to_int, (converted to C_s_a_u_i_flo_to_int).
    This function was duplicated as flo_to_tmp_bignum to be used
    internally inline - this is now converted to also make use of
    C_s_a_u_i_flo_to_int, reducing quite a bit of code bloat.

diff --git a/chicken.h b/chicken.h
index 5fc43756..4a278ff4 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1955,7 +1955,6 @@ C_fctexport void C_ccall C_minus(C_word c, C_word closure, C_word k, C_word n1,
 C_fctexport void C_ccall C_divide(C_word c, C_word closure, C_word k, C_word n1, ...) C_noret;
 C_fctexport void C_ccall C_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret;
 C_fctexport void C_ccall C_u_integer_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret;
-C_fctexport void C_ccall C_u_flo_to_int(C_word c, C_word self, C_word k, C_word x) C_noret;
 C_fctexport void C_ccall C_bitwise_and(C_word c, C_word closure, C_word k, ...) C_noret;
 C_fctexport void C_ccall C_bitwise_ior(C_word c, C_word closure, C_word k, ...) C_noret;
 C_fctexport void C_ccall C_bitwise_xor(C_word c, C_word closure, C_word k, ...) C_noret;
@@ -1968,7 +1967,6 @@ C_fctexport void C_ccall C_less_or_equal_p(C_word c, C_word closure, C_word k, .
 C_fctexport void C_ccall C_gc(C_word c, C_word closure, C_word k, ...) C_noret;
 C_fctexport void C_ccall C_open_file_port(C_word c, C_word closure, C_word k, C_word port, C_word channel, C_word mode) C_noret;
 C_fctexport void C_ccall C_allocate_vector(C_word c, C_word closure, C_word k, C_word size, C_word type, C_word init, C_word align8) C_noret;
-C_fctexport void C_ccall C_allocate_bignum(C_word c, C_word self, C_word k, C_word size, C_word negp, C_word initp) C_noret;
 C_fctexport void C_ccall C_string_to_symbol(C_word c, C_word closure, C_word k, C_word string) C_noret;
 C_fctexport void C_ccall C_build_symbol(C_word c, C_word closure, C_word k, C_word string) C_noret;
 /* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */
@@ -2184,6 +2182,8 @@ C_fctexport C_word C_fcall C_s_a_i_bitwise_ior(C_word **ptr, C_word n, C_word x,
 C_fctexport C_word C_fcall C_s_a_i_bitwise_xor(C_word **ptr, C_word n, C_word x, C_word y) C_regparm;
 C_fctexport C_word C_fcall C_s_a_i_bitwise_not(C_word **ptr, C_word n, C_word x) C_regparm;
 C_fctexport C_word C_fcall C_s_a_i_digits_to_integer(C_word **ptr, C_word n, C_word str, C_word start, C_word end, C_word radix, C_word negp) C_regparm;
+C_fctexport C_word C_fcall C_s_a_u_i_flo_to_int(C_word **ptr, C_word n, C_word x) C_regparm;
+
 
 C_fctexport C_word C_fcall C_i_foreign_char_argumentp(C_word x) C_regparm;
 C_fctexport C_word C_fcall C_i_foreign_fixnum_argumentp(C_word x) C_regparm;
diff --git a/library.scm b/library.scm
index 3ec0f6ed..be457081 100644
--- a/library.scm
+++ b/library.scm
@@ -1068,6 +1068,9 @@ EOF
 
 (define signum (##core#primitive "C_signum"))
 
+(define-inline (%flo->int x)
+  (##core#inline_allocate ("C_s_a_u_i_flo_to_int" 6) x))
+
 (define (flonum->ratnum x)
   ;; Try to multiply by two until we reach an integer
   (define (float-fraction-length x)
@@ -1079,7 +1082,7 @@ EOF
     (let* ((q (##sys#integer-power 2 (float-fraction-length y)))
            (scaled-y (* y (exact->inexact q))))
       (if (finite? scaled-y)          ; Shouldn't this always be true?
-          (##sys#/-2 (##sys#/-2 ((##core#primitive "C_u_flo_to_int") scaled-y) q) d)
+          (##sys#/-2 (##sys#/-2 (%flo->int scaled-y) q) d)
           (##sys#error-bad-inexact x 'inexact->exact))))
 
   (if (and (fp< x 1.0)         ; Watch out for denormalized numbers
@@ -1093,10 +1096,8 @@ EOF
 (define (inexact->exact x)
   (cond ((exact? x) x)
         ((##core#inline "C_i_flonump" x)
-         (cond ((##core#inline "C_u_i_fpintegerp" x)
-                ((##core#primitive "C_u_flo_to_int") x))
-               ((##core#inline "C_u_i_flonum_finitep" x)
-                (flonum->ratnum x))
+         (cond ((##core#inline "C_u_i_fpintegerp" x) (%flo->int x))
+               ((##core#inline "C_u_i_flonum_finitep" x) (flonum->ratnum x))
                (else (##sys#error-bad-inexact x 'inexact->exact))))
         ((cplxnum? x)
          (make-complex (inexact->exact (%cplxnum-real x))
diff --git a/runtime.c b/runtime.c
index bfb530d7..e1f5c00c 100644
--- a/runtime.c
+++ b/runtime.c
@@ -530,7 +530,6 @@ static C_regparm void bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q,
 static C_word rat_cmp(C_word x, C_word y);
 static void flo_to_int_2(C_word c, C_word self, C_word result) C_noret;
 static void fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan);
-static C_word flo_to_tmp_bignum(C_word x);
 static C_word int_flo_cmp(C_word intnum, C_word flonum);
 static C_word flo_int_cmp(C_word flonum, C_word intnum);
 static C_word rat_flo_cmp(C_word ratnum, C_word flonum);
@@ -556,7 +555,6 @@ static C_ccall void call_cc_wrapper(C_word c, C_word closure, C_word k, C_word r
 static C_ccall void call_cc_values_wrapper(C_word c, C_word closure, C_word k, ...) C_noret;
 static void gc_2(void *dummy) C_noret;
 static void allocate_vector_2(void *dummy) C_noret;
-static void allocate_bignum_2(void *dummy) C_noret;
 static C_word allocate_tmp_bignum(C_word size, C_word negp, C_word initp);
 static C_word allocate_scratch_bignum(C_word **ptr, C_word size, C_word negp, C_word initp);
 static void bignum_digits_destructive_negate(C_word bignum);
@@ -8612,7 +8610,7 @@ static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y)
 void C_ccall
 C_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_word y)
 {
-  C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, q, r,
+  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, q, r,
          nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 
   if (c != 4) C_bad_argc_2(c, 4, self);
@@ -8631,12 +8629,10 @@ C_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_word y)
       r = C_flonum(&a, dx - tmp * dy);
       C_values(4, C_SCHEME_UNDEFINED, k, q, r);
     }
-    nx = flo_to_tmp_bignum(x);
-    x = C_bignum_simplify(nx);
+    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
   }
   if (C_truep(C_i_flonump(y))) {
-    ny = flo_to_tmp_bignum(y);
-    y = C_bignum_simplify(ny);
+    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
   }
 
   integer_divrem(&a, x, y, &q, &r);
@@ -8650,8 +8646,8 @@ C_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_word y)
     q = newq;
     r = newr;
 
-    if (C_truep(nx)) free_tmp_bignum(nx);
-    if (C_truep(ny)) free_tmp_bignum(ny);
+    clear_buffer_object(ab, nx);
+    clear_buffer_object(ab, ny);
   }
   C_values(4, C_SCHEME_UNDEFINED, k, q, r);
 }
@@ -8668,7 +8664,7 @@ C_u_integer_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_
 C_regparm C_word C_fcall
 C_s_a_i_remainder(C_word **ptr, C_word n, C_word x, C_word y)
 {
-  C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, r,
+  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, r,
          nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 
   if (!C_truep(C_i_integerp(x)))
@@ -8684,12 +8680,10 @@ C_s_a_i_remainder(C_word **ptr, C_word n, C_word x, C_word y)
       C_modf(dx / dy, &tmp);
       return C_flonum(ptr, dx - tmp * dy);
     }
-    nx = flo_to_tmp_bignum(x);
-    x = C_bignum_simplify(nx);
+    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
   }
   if (C_truep(C_i_flonump(y))) {
-    ny = flo_to_tmp_bignum(y);
-    y = C_bignum_simplify(ny);
+    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
   }
 
   integer_divrem(&a, x, y, NULL, &r);
@@ -8699,8 +8693,8 @@ C_s_a_i_remainder(C_word **ptr, C_word n, C_word x, C_word y)
     clear_buffer_object(ab, r);
     r = newr;
 
-    if (C_truep(nx)) free_tmp_bignum(nx);
-    if (C_truep(ny)) free_tmp_bignum(ny);
+    clear_buffer_object(ab, nx);
+    clear_buffer_object(ab, ny);
   }
   return move_buffer_object(ptr, ab, r);
 }
@@ -8755,7 +8749,7 @@ C_s_a_u_i_integer_modulo(C_word **ptr, C_word n, C_word x, C_word y)
 C_regparm C_word C_fcall
 C_s_a_i_quotient(C_word **ptr, C_word n, C_word x, C_word y)
 {
-  C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, q,
+  C_word ab[C_SIZEOF_FIX_BIGNUM*4+C_SIZEOF_FLONUM*2], *a = ab, q,
          nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
 
   if (!C_truep(C_i_integerp(x)))
@@ -8771,12 +8765,10 @@ C_s_a_i_quotient(C_word **ptr, C_word n, C_word x, C_word y)
       C_modf(dx / dy, &tmp);
       return C_flonum(ptr, tmp);
     }
-    nx = flo_to_tmp_bignum(x);
-    x = C_bignum_simplify(nx);
+    x = nx = C_s_a_u_i_flo_to_int(&a, 1, x);
   }
   if (C_truep(C_i_flonump(y))) {
-    ny = flo_to_tmp_bignum(y);
-    y = C_bignum_simplify(ny);
+    y = ny = C_s_a_u_i_flo_to_int(&a, 1, y);
   }
 
   integer_divrem(&a, x, y, &q, NULL);
@@ -8786,8 +8778,8 @@ C_s_a_i_quotient(C_word **ptr, C_word n, C_word x, C_word y)
     clear_buffer_object(ab, q);
     q = newq;
 
-    if (C_truep(nx)) free_tmp_bignum(nx);
-    if (C_truep(ny)) free_tmp_bignum(ny);
+    clear_buffer_object(ab, nx);
+    clear_buffer_object(ab, ny);
   }
   return move_buffer_object(ptr, ab, q);
 }
@@ -8969,7 +8961,8 @@ C_regparm double C_fcall C_bignum_to_double(C_word bignum)
   return(C_bignum_negativep(bignum) ? -accumulator : accumulator);
 }
 
-void C_ccall C_u_flo_to_int(C_word c, C_word self, C_word k, C_word x)
+C_regparm C_word C_fcall
+C_s_a_u_i_flo_to_int(C_word **ptr, C_word n, C_word x)
 {
   int exponent;
   double significand = frexp(C_flonum_magnitude(x), &exponent);
@@ -8977,31 +8970,22 @@ void C_ccall C_u_flo_to_int(C_word c, C_word self, C_word k, C_word x)
   assert(C_truep(C_u_i_fpintegerp(x)));
 
   if (exponent <= 0) {
-    C_kontinue(k, C_fix(0));
+    return C_fix(0);
   } else if (exponent == 1) { /* TODO: check significand * 2^exp fits fixnum? */
-    C_kontinue(k, significand < 0.0 ? C_fix(-1) : C_fix(1));
+    return significand < 0.0 ? C_fix(-1) : C_fix(1);
   } else {
-    C_word kab[C_SIZEOF_CLOSURE(4) + C_SIZEOF_FLONUM], *ka = kab, k2, size,
-           negp = C_mk_bool(C_flonum_magnitude(x) < 0.0),
-           sign = C_flonum(&ka, fabs(significand));
-
-    k2 = C_closure(&ka, 4, (C_word)flo_to_int_2, k, C_fix(exponent), sign);
+    C_word size, negp = C_mk_bool(C_flonum_magnitude(x) < 0.0), result;
+    C_uword *start, *end;
 
     size = C_fix(C_BIGNUM_BITS_TO_DIGITS(exponent));
-    C_allocate_bignum(5, (C_word)NULL, k2, size, negp, C_SCHEME_FALSE);
-  }
-}
+    result = C_allocate_scratch_bignum(ptr, size, negp, C_SCHEME_FALSE);
 
-static void flo_to_int_2(C_word c, C_word self, C_word result)
-{
-  C_word k = C_block_item(self, 1);
-  C_uword exponent = C_unfix(C_block_item(self, 2)),
-          *start = C_bignum_digits(result),
-          *scan = start + C_bignum_size(result);
-  double significand = C_flonum_magnitude(C_block_item(self, 3));
+    start = C_bignum_digits(result);
+    end = start + C_bignum_size(result);
 
-  fabs_frexp_to_digits(exponent, significand, start, scan);
-  C_kontinue(k, C_bignum_simplify(result));
+    fabs_frexp_to_digits(exponent, fabs(significand), start, end);
+    return C_bignum_simplify(result);
+  }
 }
 
 static void
@@ -9032,47 +9016,13 @@ fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan)
     (*--scan) = 0;
 }
 
-static C_word flo_to_tmp_bignum(C_word x)
-{
-  /* TODO: allocating and initialising the bignum is pointless if we
-   * already know the number of limbs in the comparand.  In fact,
-   * bignum_cmp will first check the number of limbs and *then*
-   * compare.  Instead, we can check beforehand and check the limbs
-   * directly against the generated limbs, without allocating at all!
-   */
-  C_word tmp_big, negp = C_mk_bool(C_flonum_magnitude(x) < 0.0);
-  int exponent;
-  double significand = frexp(C_flonum_magnitude(x), &exponent);
-
-  assert(C_u_i_fpintegerp(x));
-
-  if (exponent <= 0) {
-    tmp_big = allocate_tmp_bignum(C_fix(0), C_SCHEME_FALSE, C_SCHEME_FALSE);
-  } else if (exponent == 1) { /* TODO: check significand * 2^exp fits fixnum? */
-    /* Don't use fix_to_big to simplify caller code: it can just free this */
-    tmp_big = allocate_tmp_bignum(C_fix(1), negp, C_SCHEME_FALSE);
-    C_bignum_digits(tmp_big)[0] = 1;
-  } else {
-    C_uword size, *start, *end;
-
-    size = C_fix(C_BIGNUM_BITS_TO_DIGITS(exponent));
-
-    tmp_big = allocate_tmp_bignum(size, negp, C_SCHEME_FALSE);
-    start = C_bignum_digits(tmp_big);
-    end = start + C_bignum_size(tmp_big);
-
-    fabs_frexp_to_digits(exponent, fabs(significand), start, end);
-  }
-  return tmp_big;
-}
-
 /* This is a bit weird: We have to compare flonums as bignums due to
  * precision loss on 64-bit platforms.  For simplicity, we convert
  * fixnums to bignums here.
  */
 static C_word int_flo_cmp(C_word intnum, C_word flonum)
 {
-  C_word ab[C_SIZEOF_FIX_BIGNUM + C_SIZEOF_FLONUM], *a = ab, x, y, res;
+  C_word ab[C_SIZEOF_FIX_BIGNUM + C_SIZEOF_FLONUM], *a = ab, flo_int, res;
   double i, f;
 
   f = C_flonum_magnitude(flonum);
@@ -9084,11 +9034,10 @@ static C_word int_flo_cmp(C_word intnum, C_word flonum)
   } else {
     f = modf(f, &i);
 
-    x = (intnum & C_FIXNUM_BIT) ? C_a_u_i_fix_to_big(&a, intnum) : intnum;
-    y = flo_to_tmp_bignum(C_flonum(&a, i));
+    flo_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 
-    res = C_i_bignum_cmp(x, y);
-    free_tmp_bignum(y);
+    res = basic_cmp(intnum, flo_int, "int_flo_cmp", 0);
+    clear_buffer_object(ab, flo_int);
 
     if (res == C_fix(0)) /* Use fraction to break tie. If f > 0, x is smaller */
       return C_fix((f > 0.0) ? -1 : ((f < 0.0) ? 1 : 0));
@@ -9111,8 +9060,8 @@ static C_word flo_int_cmp(C_word flonum, C_word intnum)
 /* This code is a bit tedious, but it makes inline comparisons possible! */
 static C_word rat_flo_cmp(C_word ratnum, C_word flonum)
 {
-  C_word ab[C_SIZEOF_FIX_BIGNUM * 2 + C_SIZEOF_FLONUM], *a = ab,
-         num, denom, ibig, res, nscaled, iscaled, negp, shift_amount;
+  C_word ab[C_SIZEOF_FIX_BIGNUM * 4 + C_SIZEOF_FLONUM], *a = ab,
+         num, denom, i_int, res, nscaled, iscaled, negp, shift_amount;
   C_uword *scan;
   double i, f;
 
@@ -9145,19 +9094,18 @@ static C_word rat_flo_cmp(C_word ratnum, C_word flonum)
       return C_fix(1);
     } else {
       denom = C_block_item(ratnum, 2);
-      ibig = flo_to_tmp_bignum(C_flonum(&a, i));
-
-      /* Now, multiply the scaled flonum by the denominator, so we can
-       * compare it directly to the scaled numerator. */
-      iscaled = C_s_a_u_i_integer_times(&a, 2, C_bignum_simplify(ibig), denom);
-      free_tmp_bignum(ibig);
+      i_int = C_s_a_u_i_flo_to_int(&a, 1, C_flonum(&a, i));
 
+      /* Multiply the scaled flonum integer by the denominator, and
+       * shift the numerator so that they may be directly compared. */
+      iscaled = C_s_a_u_i_integer_times(&a, 2, i_int, denom);
       nscaled = C_s_a_i_arithmetic_shift(&a, 2, num, C_fix(shift_amount));
 
       /* Finally, we're ready to compare them! */
       res = basic_cmp(nscaled, iscaled, "rat_flo_cmp", 0);
       clear_buffer_object(ab, nscaled);
       clear_buffer_object(ab, iscaled);
+      clear_buffer_object(ab, i_int);
 
       return res;
     }
@@ -9731,72 +9679,6 @@ void allocate_vector_2(void *dummy)
   C_kontinue(k, v);
 }
 
-
-void C_ccall
-C_allocate_bignum(C_word c, C_word self, C_word k, C_word size, C_word negp, C_word initp)
-{
-  C_uword bytes = C_wordstobytes(C_SIZEOF_INTERNAL_BIGNUM_VECTOR(C_unfix(size)));
-
-  if(bytes > C_HEADER_SIZE_MASK)
-    barf(C_OUT_OF_RANGE_ERROR, NULL, size, C_fix(C_HEADER_SIZE_MASK));
-
-  bytes += C_wordstobytes(C_SIZEOF_STRUCTURE(2)); /* Add wrapper struct */
-
-  C_save(k);
-  C_save(negp);
-  C_save(initp);
-  C_save(C_fix(bytes));
-
-  if(!C_demand(C_bytestowords(bytes))) {
-    /* Allocate on heap: */
-    if((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size * 2))
-      C_fromspace_top = C_fromspace_limit; /* trigger major GC */
-  
-    C_save(C_SCHEME_TRUE);
-    C_reclaim((void *)allocate_bignum_2, NULL);
-  }
-
-  C_save(C_SCHEME_FALSE);
-  allocate_bignum_2(NULL);
-}
-
-static void allocate_bignum_2(void *dummy)
-{
-  C_word  mode = C_restore;
-  C_uword bytes = C_unfix(C_restore);
-  C_word  initp = C_restore;
-  C_word  negp = C_restore;
-  C_word  k = C_restore;
-  C_word  *v0, *v1, bigvec;
-
-  if(C_truep(mode)) {
-    while((C_uword)(C_fromspace_limit - C_fromspace_top) < (bytes + stack_size)) {
-      if(C_heap_size_is_fixed)
-	panic(C_text("out of memory - cannot allocate bignum (heap resizing disabled)"));
-
-      C_save(k);
-      C_rereclaim2(percentage(heap_size, C_heap_growth) + (C_uword)bytes, 0);
-      k = C_restore;
-    }
-
-    v0 = (C_word *)C_align((C_word)C_fromspace_top);
-    C_fromspace_top += C_align(bytes);
-  }
-  else v0 = C_alloc(C_bytestowords(bytes));
-
-  v1 = v0 + C_SIZEOF_STRUCTURE(2);
-  bigvec = (C_word)v1;
-  bytes -= C_wordstobytes(C_SIZEOF_STRUCTURE(2));
-  bytes -= sizeof(C_word); /* internal bignum vector's header */
-
-  *(v1++) = C_STRING_TYPE | bytes;
-
-  *(v1++) = C_truep(negp);
-  if(C_truep(initp)) C_memset(v1, '\0', bytes - sizeof(C_word));
-
-  C_kontinue(k, C_a_i_record2(&v0, 2, C_bignum_type_tag, bigvec));
-}
-
 static C_word allocate_tmp_bignum(C_word size, C_word negp, C_word initp)
 {
   C_word *mem = C_malloc(C_wordstobytes(C_SIZEOF_BIGNUM(C_unfix(size)))),
Trap