I think Cristophe is on the right path. But it is possible that there is another Bug concerning primitive functions.
Consider the following two functions:
(defn fib ^long [^long n]
(if (<= n 1) 1 (+ (fib (dec n)) (fib (- n 2)))))
(defn fib2 ^double [^double n]
(if (<= n 1) 1 (+ (fib2 (dec n)) (fib2 (- n 2)))))
The bytecode of `fib` ends as expected with
42 invokestatic 81; /* long clojure.lang.Numbers.minus(long arg0, long arg1) */
45 invokeinterface 77 3; /* long invokePrim(long arg0) */
50 invokestatic 84; /* long clojure.lang.Numbers.add(long arg0, long arg1) */
53 lreturn;
But `fib2` boxes and unboxes again:
45 invokestatic 83; /* double clojure.lang.Numbers.minus(double arg0, long arg1) */
48 invokeinterface 79 3; /* double invokePrim(double arg0) */
53 invokestatic 87; /* double clojure.lang.Numbers.add(double arg0, double arg1) */
56 invokestatic 92; /* java.lang.Double java.lang.Double.valueOf(double arg0) */
59 checkcast 94; /* java.lang.Number */
62 invokevirtual 98; /* double doubleValue() */
65 dreturn;
I also rewrote the multiply-and-square algorithm so that it does not use `loop`:
(defn multiply-and-square
^double [^double result, ^double factor, ^long c]
(if (> c 0)
(recur
(if (first-bit? c)
(* result factor)
result),
(* factor factor),
(bit-shift-right c 1))
result))
(defn exp-int2
^double [^double x, ^long c]
(multiply-and-square 1.0, x, c))
Here the bytecode of `exp-int2` looks fine, but the recursive function `multiply-and-square` performs the boxing and unboxing again:
43 dload_1; /* result */
44 invokestatic 70; /* java.lang.Double java.lang.Double.valueOf(double factor) */
47 checkcast 72; /* java.lang.Number */
50 invokevirtual 76; /* double doubleValue() */
53 dreturn;
Christophe, can you try `fib2` with your patched Clojure?