~ chicken-core (chicken-5) 84391f76b2be6833c11bcf1d8e86f339ddc11d1b


commit 84391f76b2be6833c11bcf1d8e86f339ddc11d1b
Author:     Peter Bex <peter@more-magic.net>
AuthorDate: Sat Mar 28 20:02:11 2015 +0100
Commit:     Peter Bex <peter@more-magic.net>
CommitDate: Sun May 31 14:55:24 2015 +0200

    Re-implement variadic * in C, in order to avoid consing up rest lists.

diff --git a/c-platform.scm b/c-platform.scm
index b9b5b05a..c3c42bf3 100644
--- a/c-platform.scm
+++ b/c-platform.scm
@@ -654,6 +654,7 @@
 (rewrite '>= 13 #f "C_greater_or_equal_p" #t)
 (rewrite '<= 13 #f "C_less_or_equal_p" #t)
 
+(rewrite '* 13 #f "C_times" #t)
 (rewrite '+ 13 #f "C_plus" #t)
 (rewrite '- 13 '(1 . #f) "C_minus" #t)
 
diff --git a/library.scm b/library.scm
index 27ddfdd6..3be55736 100644
--- a/library.scm
+++ b/library.scm
@@ -954,6 +954,7 @@ EOF
 
 (define + (##core#primitive "C_plus"))
 (define - (##core#primitive "C_minus"))
+(define * (##core#primitive "C_times"))
 (define (add1 n) (+ n 1))
 (define (sub1 n) (- n 1))
 
@@ -1112,23 +1113,6 @@ EOF
 
 (define (abs x) (##core#inline_allocate ("C_s_a_i_abs" 10) x))
 
-(define (* . args)
-  (if (null? args) 
-      1
-      (let ((x (##sys#slot args 0))
-	    (args (##sys#slot args 1)))
-	(if (null? args)
-            (if (number? x) x (##sys#error-bad-number x '*))
-            (let loop ((args (##sys#slot args 1))
-                       (x (##core#inline_allocate
-			   ("C_s_a_i_times" 40) x (##sys#slot args 0))))
-              (if (null? args)
-                  x
-                  (loop (##sys#slot args 1)
-			(##core#inline_allocate
-			 ("C_s_a_i_times" 40)
-			 x (##sys#slot args 0))) ) )  ) ) ) )
-
 (define (/ arg1 . args)
   (if (null? args) 
       (##sys#/-2 1 arg1)
diff --git a/runtime.c b/runtime.c
index 65b92b0e..b0a728b9 100644
--- a/runtime.c
+++ b/runtime.c
@@ -7848,53 +7848,26 @@ bignum_times_bignum_karatsuba(C_word **ptr, C_word x, C_word y, C_word negp)
    return n;
 }
 
-
 void C_ccall C_times(C_word c, C_word closure, C_word k, ...)
 {
+  C_word next_val, result = C_fix(1), prev_result = result;
+  C_word ab[2][C_SIZEOF_STRUCTURE(3) * 3 + C_SIZEOF_BIGNUM(2) * 4], *a;
   va_list v;
-  C_word x, y;
-  C_word iresult = C_fix(1);
-  double fresult;
-  C_alloc_flonum;
 
+  c -= 2; 
   va_start(v, k);
-  c -= 2;
-
-  while(c--) {
-    x = va_arg(v, C_word);
-    
-    if(x & C_FIXNUM_BIT) {
-      y = C_i_o_fixnum_times(iresult, x);
-
-      if(y == C_SCHEME_FALSE) {
-	fresult = (double)C_unfix(iresult) * (double)C_unfix(x);
-	goto flonum_result;
-      }
-      else iresult = y;
-    }
-    else if(!C_immediatep(x) && C_block_header(x) == C_FLONUM_TAG) {
-      fresult = (double)C_unfix(iresult) * C_flonum_magnitude(x);
-      goto flonum_result;
-    }
-    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "*", x);
-  }
 
-  va_end(v);
-  C_kontinue(k, iresult);
-
- flonum_result:
-  while(c--) {
-    x = va_arg(v, C_word);
-
-    if(x & C_FIXNUM_BIT)
-      fresult *= (double)C_unfix(x);
-    else if(!C_immediatep(x) && C_block_header(x) == C_FLONUM_TAG)
-      fresult *= C_flonum_magnitude(x);
-    else barf(C_BAD_ARGUMENT_TYPE_ERROR, "*", x);
+  while (c--) {
+    next_val = va_arg(v, C_word);
+    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
+    result = C_s_a_i_times(&a, 2, result, next_val);
+    result = move_buffer_object(&a, ab[(c+1)&1], result);
+    clear_buffer_object(ab[(c+1)&1], prev_result);
+    prev_result = result;
   }
 
   va_end(v);
-  C_kontinue_flonum(k, fresult);
+  C_kontinue(k, result);
 }
 
 
Trap