summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2010-06-15 23:13:05 -0400
committerRich Hickey <richhickey@gmail.com>2010-06-15 23:13:05 -0400
commit6ab3e4cd672092823a04c944210a23c29142785d (patch)
treef54d634e3fb26e623e21692879f4cd94f261e7fb
parent8fbafa92faacb92a9bd49fa1e9b7e2c8c0747c07 (diff)
Unify numeric semantics around longs, with throw on overflow. Allow numeric literals to be primitive initializers. Canonicalize boxing of integers, if it fits in int, is Integer, else Long, thus primitive coercions can't be used to get particular boxed types, use Long/valueOf etc. Ask for BigIntegers if you want arbitrary precision, new literal number format - append 'N' for BigInteger. BigIntegers do not reduce automatically, are contagious. New particular names for unchecked ops - unchecked-xxx-int or unchecked-xxx-long. You should need far fewer hints for primitive perf, and avoid int casts and any casting of numeric literals, see:
http://gist.github.com/440102
-rw-r--r--src/clj/clojure/core.clj140
-rw-r--r--src/clj/clojure/genclass.clj6
-rw-r--r--src/clj/clojure/gvec.clj6
-rw-r--r--src/jvm/clojure/lang/Compiler.java483
-rw-r--r--src/jvm/clojure/lang/LispReader.java2
-rw-r--r--src/jvm/clojure/lang/Numbers.java1258
-rw-r--r--src/jvm/clojure/lang/Reflector.java21
-rw-r--r--test/clojure/test_clojure/java_interop.clj2
-rw-r--r--test/clojure/test_clojure/numbers.clj57
9 files changed, 1075 insertions, 900 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 3ec651f0..157b25d7 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -970,61 +970,117 @@
:added "1.0"}
[x] (. clojure.lang.Numbers (dec x)))
-(defn unchecked-inc
- "Returns a number one greater than x, an int or long.
+(defn unchecked-inc-int
+ "Returns a number one greater than x, an int.
Note - uses a primitive operator subject to overflow."
- {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_inc ~x)))
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_inc ~x)))
:added "1.0"}
- [x] (. clojure.lang.Numbers (unchecked_inc x)))
+ [x] (. clojure.lang.Numbers (unchecked_int_inc x)))
-(defn unchecked-dec
- "Returns a number one less than x, an int or long.
+(defn unchecked-inc-long
+ "Returns a number one greater than x, a long.
Note - uses a primitive operator subject to overflow."
- {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_dec ~x)))
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_long_inc ~x)))
:added "1.0"}
- [x] (. clojure.lang.Numbers (unchecked_dec x)))
+ [x] (. clojure.lang.Numbers (unchecked_long_inc x)))
-(defn unchecked-negate
- "Returns the negation of x, an int or long.
+(defn unchecked-dec-int
+ "Returns a number one less than x, an int.
Note - uses a primitive operator subject to overflow."
- {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_negate ~x)))
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_dec ~x)))
:added "1.0"}
- [x] (. clojure.lang.Numbers (unchecked_negate x)))
+ [x] (. clojure.lang.Numbers (unchecked_int_dec x)))
-(defn unchecked-add
- "Returns the sum of x and y, both int or long.
+(defn unchecked-dec-long
+ "Returns a number one less than x, a long.
Note - uses a primitive operator subject to overflow."
- {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_add ~x ~y)))
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_long_dec ~x)))
:added "1.0"}
- [x y] (. clojure.lang.Numbers (unchecked_add x y)))
+ [x] (. clojure.lang.Numbers (unchecked_long_dec x)))
-(defn unchecked-subtract
- "Returns the difference of x and y, both int or long.
+(defn unchecked-negate-int
+ "Returns the negation of x, an int.
Note - uses a primitive operator subject to overflow."
- {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_subtract ~x ~y)))
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_negate ~x)))
:added "1.0"}
- [x y] (. clojure.lang.Numbers (unchecked_subtract x y)))
+ [x] (. clojure.lang.Numbers (unchecked_int_negate x)))
-(defn unchecked-multiply
- "Returns the product of x and y, both int or long.
+(defn unchecked-negate-long
+ "Returns the negation of x, a long.
Note - uses a primitive operator subject to overflow."
- {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_multiply ~x ~y)))
+ {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_long_negate ~x)))
:added "1.0"}
- [x y] (. clojure.lang.Numbers (unchecked_multiply x y)))
+ [x] (. clojure.lang.Numbers (unchecked_long_negate x)))
-(defn unchecked-divide
- "Returns the division of x by y, both int or long.
+(defn unchecked-add-int
+ "Returns the sum of x and y, both int.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_add ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_int_add x y)))
+
+(defn unchecked-add-long
+ "Returns the sum of x and y, both long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_add ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_long_add x y)))
+
+(defn unchecked-subtract-int
+ "Returns the difference of x and y, both int.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_subtract ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_int_subtract x y)))
+
+(defn unchecked-subtract-long
+ "Returns the difference of x and y, both long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_subtract ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_long_subtract x y)))
+
+(defn unchecked-multiply-int
+ "Returns the product of x and y, both int.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_multiply ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_int_multiply x y)))
+
+(defn unchecked-multiply-long
+ "Returns the product of x and y, both long.
+ Note - uses a primitive operator subject to overflow."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_multiply ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_long_multiply x y)))
+
+(defn unchecked-divide-int
+ "Returns the division of x by y, both int.
+ Note - uses a primitive operator subject to truncation."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_divide ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_int_divide x y)))
+
+(defn unchecked-divide-long
+ "Returns the division of x by y, both long.
+ Note - uses a primitive operator subject to truncation."
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_divide ~x ~y)))
+ :added "1.0"}
+ [x y] (. clojure.lang.Numbers (unchecked_long_divide x y)))
+
+(defn unchecked-remainder-int
+ "Returns the remainder of division of x by y, both int.
Note - uses a primitive operator subject to truncation."
- {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_divide ~x ~y)))
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_remainder ~x ~y)))
:added "1.0"}
- [x y] (. clojure.lang.Numbers (unchecked_divide x y)))
+ [x y] (. clojure.lang.Numbers (unchecked_int_remainder x y)))
-(defn unchecked-remainder
- "Returns the remainder of division of x by y, both int or long.
+(defn unchecked-remainder-long
+ "Returns the remainder of division of x by y, both long.
Note - uses a primitive operator subject to truncation."
- {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_remainder ~x ~y)))
+ {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_remainder ~x ~y)))
:added "1.0"}
- [x y] (. clojure.lang.Numbers (unchecked_remainder x y)))
+ [x y] (. clojure.lang.Numbers (unchecked_long_remainder x y)))
(defn pos?
"Returns true if num is greater than zero, else false"
@@ -2183,11 +2239,11 @@
[bindings & body]
(let [i (first bindings)
n (second bindings)]
- `(let [n# (int ~n)]
+ `(let [n# ~n]
(loop [~i (int 0)]
(when (< ~i n#)
~@body
- (recur (inc ~i)))))))
+ (recur (unchecked-inc-long ~i)))))))
(defn map
"Returns a lazy sequence consisting of the result of applying f to the
@@ -2553,17 +2609,17 @@
{:tag 'clojure.lang.IChunk})
count- (gensym "count_")
i- (gensym "i_")
- recform `(recur (next ~seq-) nil (int 0) (int 0))
+ recform `(recur (next ~seq-) nil 0 0)
steppair (step recform (nnext exprs))
needrec (steppair 0)
subform (steppair 1)
recform-chunk
- `(recur ~seq- ~chunk- ~count- (unchecked-inc ~i-))
+ `(recur ~seq- ~chunk- ~count- (unchecked-inc-long ~i-))
steppair-chunk (step recform-chunk (nnext exprs))
subform-chunk (steppair-chunk 1)]
[true
`(loop [~seq- (seq ~v), ~chunk- nil,
- ~count- (int 0), ~i- (int 0)]
+ ~count- 0, ~i- 0]
(if (< ~i- ~count-)
(let [~k (.nth ~chunk- ~i-)]
~subform-chunk
@@ -2660,11 +2716,11 @@
(= 2 (count bindings)) "exactly 2 forms in binding vector")
(let [i (first bindings)
n (second bindings)]
- `(let [n# (int ~n)]
- (loop [~i (int 0)]
+ `(let [n# ~n]
+ (loop [~i 0]
(when (< ~i n#)
~@body
- (recur (unchecked-inc ~i)))))))
+ (recur (unchecked-inc-long ~i)))))))
#_(defn into
"Returns a new coll consisting of to-coll with all of the items of
@@ -3849,12 +3905,12 @@
(= k :when) `(if ~v
~(do-cmod etc)
(recur
- (unchecked-inc ~gi)))
+ (unchecked-inc-long ~gi)))
(keyword? k)
(err "Invalid 'for' keyword " k)
:else
`(do (chunk-append ~gb ~body-expr)
- (recur (unchecked-inc ~gi)))))]
+ (recur (unchecked-inc-long ~gi)))))]
`(fn ~giter [~gxs]
(lazy-seq
(loop [~gxs ~gxs]
diff --git a/src/clj/clojure/genclass.clj b/src/clj/clojure/genclass.clj
index bacc9277..a1e0fcdb 100644
--- a/src/clj/clojure/genclass.clj
+++ b/src/clj/clojure/genclass.clj
@@ -299,7 +299,7 @@
(arg-types (count ptypes)))))
;expecting [[super-ctor-args] state] returned
(. gen dup)
- (. gen push 0)
+ (. gen push (int 0))
(. gen (invokeStatic rt-type nth-method))
(. gen storeLocal local)
@@ -307,14 +307,14 @@
(. gen dupX1)
(dotimes [i (count super-pclasses)]
(. gen loadLocal local)
- (. gen push i)
+ (. gen push (int i))
(. gen (invokeStatic rt-type nth-method))
(. clojure.lang.Compiler$HostExpr (emitUnboxArg nil gen (nth super-pclasses i))))
(. gen (invokeConstructor super-type super-m))
(if state
(do
- (. gen push 1)
+ (. gen push (int 1))
(. gen (invokeStatic rt-type nth-method))
(. gen (putField ctype state-name obj-type)))
(. gen pop))
diff --git a/src/clj/clojure/gvec.clj b/src/clj/clojure/gvec.clj
index feff544a..bfebb2ea 100644
--- a/src/clj/clojure/gvec.clj
+++ b/src/clj/clojure/gvec.clj
@@ -62,11 +62,11 @@
(if (< aidx (count vec))
(let [node (.arrayFor vec aidx)
result (loop [result result
- node-idx (bit-and (int 0x1f) aidx)]
+ node-idx (bit-and 0x1f aidx)]
(if (< node-idx (.alength am node))
(recur (f result (.aget am node node-idx)) (inc node-idx))
result))]
- (recur result (bit-and (int 0xffe0) (+ aidx (int 32)))))
+ (recur result (bit-and 0xffe0 (+ aidx 32))))
result)))
clojure.lang.ISeq
@@ -141,7 +141,7 @@
(if (= i cnt)
hash
(let [val (.nth this i)]
- (recur (unchecked-add (unchecked-multiply (int 31) hash)
+ (recur (unchecked-add-int (unchecked-multiply-int 31 hash)
(clojure.lang.Util/hash val))
(inc i))))))
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 29e8fbbd..9f8c7b5f 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -139,6 +139,7 @@ private static final Type SYMBOL_TYPE = Type.getType(Symbol.class);
private static final Type IFN_TYPE = Type.getType(IFn.class);
private static final Type AFUNCTION_TYPE = Type.getType(AFunction.class);
private static final Type RT_TYPE = Type.getType(RT.class);
+private static final Type NUMBERS_TYPE = Type.getType(Numbers.class);
final static Type CLASS_TYPE = Type.getType(Class.class);
final static Type NS_TYPE = Type.getType(Namespace.class);
final static Type UTIL_TYPE = Type.getType(Util.class);
@@ -726,22 +727,20 @@ static public abstract class HostExpr implements Expr, MaybePrimitiveExpr{
else
{
if(returnType == int.class)
- //gen.invokeStatic(NUM_TYPE, fromIntMethod);
gen.invokeStatic(INTEGER_TYPE, intValueOfMethod);
else if(returnType == float.class)
{
- //gen.visitInsn(F2D);
- gen.invokeStatic(FLOAT_TYPE, floatValueOfMethod);
- //m = floatValueOfMethod;
+ gen.visitInsn(F2D);
+ gen.invokeStatic(DOUBLE_TYPE, doubleValueOfMethod);
}
else if(returnType == double.class)
gen.invokeStatic(DOUBLE_TYPE, doubleValueOfMethod);
- else if(returnType == long.class)
- gen.invokeStatic(LONG_TYPE, longValueOfMethod);
- else if(returnType == byte.class)
- gen.invokeStatic(BYTE_TYPE, byteValueOfMethod);
- else if(returnType == short.class)
- gen.invokeStatic(SHORT_TYPE, shortValueOfMethod);
+ else if(returnType == long.class)
+ gen.invokeStatic(NUMBERS_TYPE, Method.getMethod("Number num(long)"));
+ else if(returnType == byte.class)
+ gen.invokeStatic(BYTE_TYPE, byteValueOfMethod);
+ else if(returnType == short.class)
+ gen.invokeStatic(SHORT_TYPE, shortValueOfMethod);
}
}
}
@@ -1163,9 +1162,35 @@ static abstract class MethodExpr extends HostExpr{
Expr e = (Expr) args.nth(i);
try
{
- if(maybePrimitiveType(e) == parameterTypes[i])
+ final Class primc = maybePrimitiveType(e);
+ if(primc == parameterTypes[i])
{
- ((MaybePrimitiveExpr) e).emitUnboxed(C.EXPRESSION, objx, gen);
+ final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e;
+ pe.emitUnboxed(C.EXPRESSION, objx, gen);
+ }
+ else if(primc == int.class && parameterTypes[i] == long.class)
+ {
+ final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e;
+ pe.emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.visitInsn(I2L);
+ }
+ else if(primc == long.class && parameterTypes[i] == int.class)
+ {
+ final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e;
+ pe.emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.invokeStatic(RT_TYPE, Method.getMethod("int intCast(long)"));
+ }
+ else if(primc == float.class && parameterTypes[i] == double.class)
+ {
+ final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e;
+ pe.emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.visitInsn(F2D);
+ }
+ else if(primc == double.class && parameterTypes[i] == float.class)
+ {
+ final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e;
+ pe.emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.visitInsn(D2F);
}
else
{
@@ -1508,6 +1533,66 @@ static class UnresolvedVarExpr implements Expr{
}
}
+static class NumberExpr extends LiteralExpr implements MaybePrimitiveExpr{
+ final Number n;
+ public final int id;
+
+ public NumberExpr(Number n){
+ this.n = n;
+ this.id = registerConstant(n);
+ }
+
+ Object val(){
+ return n;
+ }
+
+ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
+ if(context != C.STATEMENT)
+ {
+ objx.emitConstant(gen, id);
+// emitUnboxed(context,objx,gen);
+// HostExpr.emitBoxReturn(objx,gen,getJavaClass());
+ }
+ }
+
+ public boolean hasJavaClass() throws Exception{
+ return true;
+ }
+
+ public Class getJavaClass(){
+ if(n instanceof Integer)
+ return long.class;
+ else if(n instanceof Double)
+ return double.class;
+ else if(n instanceof Long)
+ return long.class;
+ else
+ throw new IllegalStateException("Unsupported Number type: " + n.getClass().getName());
+ }
+
+ public boolean canEmitPrimitive(){
+ return true;
+ }
+
+ public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
+ if(n instanceof Integer)
+ gen.push(n.longValue());
+ else if(n instanceof Double)
+ gen.push(n.doubleValue());
+ else if(n instanceof Long)
+ gen.push(n.longValue());
+ }
+
+ static public Expr parse(Number form){
+ if(form instanceof Integer
+ || form instanceof Double
+ || form instanceof Long)
+ return new NumberExpr(form);
+ else
+ return new ConstantExpr(form);
+ }
+}
+
static class ConstantExpr extends LiteralExpr{
//stuff quoted vals in classloader at compile time, pull out at runtime
//this won't work for static compilation...
@@ -3938,119 +4023,124 @@ static public class ObjExpr implements Expr{
gen.push(((Integer) value).intValue());
gen.invokeStatic(Type.getType(Integer.class), Method.getMethod("Integer valueOf(int)"));
}
+ else if(value instanceof Long)
+ {
+ gen.push(((Long) value).longValue());
+ gen.invokeStatic(Type.getType(Long.class), Method.getMethod("Long valueOf(long)"));
+ }
else if(value instanceof Double)
{
gen.push(((Double) value).doubleValue());
gen.invokeStatic(Type.getType(Double.class), Method.getMethod("Double valueOf(double)"));
}
- else if(value instanceof Character)
- {
- gen.push(((Character) value).charValue());
- gen.invokeStatic(Type.getType(Character.class), Method.getMethod("Character valueOf(char)"));
- }
- else if(value instanceof Class)
- {
- Class cc = (Class)value;
- if(cc.isPrimitive())
- {
- Type bt;
- if ( cc == boolean.class ) bt = Type.getType(Boolean.class);
- else if ( cc == byte.class ) bt = Type.getType(Byte.class);
- else if ( cc == char.class ) bt = Type.getType(Character.class);
- else if ( cc == double.class ) bt = Type.getType(Double.class);
- else if ( cc == float.class ) bt = Type.getType(Float.class);
- else if ( cc == int.class ) bt = Type.getType(Integer.class);
- else if ( cc == long.class ) bt = Type.getType(Long.class);
- else if ( cc == short.class ) bt = Type.getType(Short.class);
- else throw new RuntimeException(
- "Can't embed unknown primitive in code: " + value);
- gen.getStatic( bt, "TYPE", Type.getType(Class.class) );
- }
- else
- {
- gen.push(destubClassName(cc.getName()));
- gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)"));
- }
- }
- else if(value instanceof Symbol)
- {
- gen.push(((Symbol) value).ns);
- gen.push(((Symbol) value).name);
- gen.invokeStatic(Type.getType(Symbol.class),
- Method.getMethod("clojure.lang.Symbol create(String,String)"));
- }
- else if(value instanceof Keyword)
- {
- emitValue(((Keyword) value).sym, gen);
- gen.invokeStatic(Type.getType(Keyword.class),
- Method.getMethod("clojure.lang.Keyword intern(clojure.lang.Symbol)"));
- }
+ else if(value instanceof Character)
+ {
+ gen.push(((Character) value).charValue());
+ gen.invokeStatic(Type.getType(Character.class), Method.getMethod("Character valueOf(char)"));
+ }
+ else if(value instanceof Class)
+ {
+ Class cc = (Class)value;
+ if(cc.isPrimitive())
+ {
+ Type bt;
+ if ( cc == boolean.class ) bt = Type.getType(Boolean.class);
+ else if ( cc == byte.class ) bt = Type.getType(Byte.class);
+ else if ( cc == char.class ) bt = Type.getType(Character.class);
+ else if ( cc == double.class ) bt = Type.getType(Double.class);
+ else if ( cc == float.class ) bt = Type.getType(Float.class);
+ else if ( cc == int.class ) bt = Type.getType(Integer.class);
+ else if ( cc == long.class ) bt = Type.getType(Long.class);
+ else if ( cc == short.class ) bt = Type.getType(Short.class);
+ else throw new RuntimeException(
+ "Can't embed unknown primitive in code: " + value);
+ gen.getStatic( bt, "TYPE", Type.getType(Class.class) );
+ }
+ else
+ {
+ gen.push(destubClassName(cc.getName()));
+ gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)"));
+ }
+ }
+ else if(value instanceof Symbol)
+ {
+ gen.push(((Symbol) value).ns);
+ gen.push(((Symbol) value).name);
+ gen.invokeStatic(Type.getType(Symbol.class),
+ Method.getMethod("clojure.lang.Symbol create(String,String)"));
+ }
+ else if(value instanceof Keyword)
+ {
+ emitValue(((Keyword) value).sym, gen);
+ gen.invokeStatic(Type.getType(Keyword.class),
+ Method.getMethod("clojure.lang.Keyword intern(clojure.lang.Symbol)"));
+ }
// else if(value instanceof KeywordCallSite)
// {
// emitValue(((KeywordCallSite) value).k.sym, gen);
// gen.invokeStatic(Type.getType(KeywordCallSite.class),
// Method.getMethod("clojure.lang.KeywordCallSite create(clojure.lang.Symbol)"));
// }
- else if(value instanceof Var)
- {
- Var var = (Var) value;
- gen.push(var.ns.name.toString());
- gen.push(var.sym.toString());
- gen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)"));
- }
- else if(value instanceof IPersistentMap)
- {
- List entries = new ArrayList();
- for(Map.Entry entry : (Set<Map.Entry>) ((Map) value).entrySet())
- {
- entries.add(entry.getKey());
- entries.add(entry.getValue());
- }
- emitListAsObjectArray(entries, gen);
- gen.invokeStatic(RT_TYPE,
- Method.getMethod("clojure.lang.IPersistentMap map(Object[])"));
- }
- else if(value instanceof IPersistentVector)
- {
- emitListAsObjectArray(value, gen);
- gen.invokeStatic(RT_TYPE, Method.getMethod(
- "clojure.lang.IPersistentVector vector(Object[])"));
- }
- else if(value instanceof ISeq || value instanceof IPersistentList)
- {
- emitListAsObjectArray(value, gen);
- gen.invokeStatic(Type.getType(java.util.Arrays.class),
- Method.getMethod("java.util.List asList(Object[])"));
- gen.invokeStatic(Type.getType(PersistentList.class),
- Method.getMethod(
- "clojure.lang.IPersistentList create(java.util.List)"));
- }
- else
- {
- String cs = null;
- try
- {
- cs = RT.printString(value);
- //System.out.println("WARNING SLOW CODE: " + value.getClass() + " -> " + cs);
- }
- catch(Exception e)
- {
- throw new RuntimeException(
- "Can't embed object in code, maybe print-dup not defined: " +
- value);
- }
- if(cs.length() == 0)
- throw new RuntimeException(
- "Can't embed unreadable object in code: " + value);
-
- if(cs.startsWith("#<"))
- throw new RuntimeException(
- "Can't embed unreadable object in code: " + cs);
-
- gen.push(cs);
- gen.invokeStatic(RT_TYPE, readStringMethod);
- partial = false;
- }
+ else if(value instanceof Var)
+ {
+ Var var = (Var) value;
+ gen.push(var.ns.name.toString());
+ gen.push(var.sym.toString());
+ gen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)"));
+ }
+ else if(value instanceof IPersistentMap)
+ {
+ List entries = new ArrayList();
+ for(Map.Entry entry : (Set<Map.Entry>) ((Map) value).entrySet())
+ {
+ entries.add(entry.getKey());
+ entries.add(entry.getValue());
+ }
+ emitListAsObjectArray(entries, gen);
+ gen.invokeStatic(RT_TYPE,
+ Method.getMethod("clojure.lang.IPersistentMap map(Object[])"));
+ }
+ else if(value instanceof IPersistentVector)
+ {
+ emitListAsObjectArray(value, gen);
+ gen.invokeStatic(RT_TYPE, Method.getMethod(
+ "clojure.lang.IPersistentVector vector(Object[])"));
+ }
+ else if(value instanceof ISeq || value instanceof IPersistentList)
+ {
+ emitListAsObjectArray(value, gen);
+ gen.invokeStatic(Type.getType(java.util.Arrays.class),
+ Method.getMethod("java.util.List asList(Object[])"));
+ gen.invokeStatic(Type.getType(PersistentList.class),
+ Method.getMethod(
+ "clojure.lang.IPersistentList create(java.util.List)"));
+ }
+ else
+ {
+ String cs = null;
+ try
+ {
+ cs = RT.printString(value);
+ //System.out.println("WARNING SLOW CODE: " + value.getClass() + " -> " + cs);
+ }
+ catch(Exception e)
+ {
+ throw new RuntimeException(
+ "Can't embed object in code, maybe print-dup not defined: " +
+ value);
+ }
+ if(cs.length() == 0)
+ throw new RuntimeException(
+ "Can't embed unreadable object in code: " + value);
+
+ if(cs.startsWith("#<"))
+ throw new RuntimeException(
+ "Can't embed unreadable object in code: " + cs);
+
+ gen.push(cs);
+ gen.invokeStatic(RT_TYPE, readStringMethod);
+ partial = false;
+ }
if(partial)
{
@@ -4558,26 +4648,8 @@ public static class FnMethod extends ObjMethod{
try
{
Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this));
- MaybePrimitiveExpr be = (MaybePrimitiveExpr) body;
- if(Util.isPrimitive(retClass) && be.canEmitPrimitive())
- {
- if(be.getJavaClass() == retClass)
- be.emitUnboxed(C.RETURN,fn,gen);
- //todo - support the standard widening conversions
- else
- throw new IllegalArgumentException("Mismatched primitive return, expected: "
- + retClass + ", had: " + be.getJavaClass());
- }
- else
- {
- body.emit(C.RETURN, fn, gen);
- if(retClass == void.class)
- {
- gen.pop();
- }
- else
- gen.unbox(getReturnType());
- }
+ emitBody(objx, gen, retClass, body);
+
Label end = gen.mark();
for(ISeq lbs = argLocals.seq(); lbs != null; lbs = lbs.next())
{
@@ -4739,6 +4811,7 @@ abstract public static class ObjMethod{
PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY;
protected IPersistentMap methodMeta;
+
public final IPersistentMap locals(){
return locals;
}
@@ -4768,6 +4841,48 @@ abstract public static class ObjMethod{
this.objx = objx;
}
+ static void emitBody(ObjExpr objx, GeneratorAdapter gen, Class retClass, Expr body) throws Exception{
+ MaybePrimitiveExpr be = (MaybePrimitiveExpr) body;
+ if(Util.isPrimitive(retClass) && be.canEmitPrimitive())
+ {
+ Class bc = maybePrimitiveType(be);
+ if(bc == retClass)
+ be.emitUnboxed(C.RETURN, objx, gen);
+ else if(retClass == long.class && bc == int.class)
+ {
+ be.emitUnboxed(C.RETURN, objx, gen);
+ gen.visitInsn(I2L);
+ }
+ else if(retClass == double.class && bc == float.class)
+ {
+ be.emitUnboxed(C.RETURN, objx, gen);
+ gen.visitInsn(F2D);
+ }
+ else if(retClass == int.class && bc == long.class)
+ {
+ be.emitUnboxed(C.RETURN, objx, gen);
+ gen.invokeStatic(RT_TYPE, Method.getMethod("int intCast(long)"));
+ }
+ else if(retClass == float.class && bc == double.class)
+ {
+ be.emitUnboxed(C.RETURN, objx, gen);
+ gen.visitInsn(D2F);
+ }
+ else
+ throw new IllegalArgumentException("Mismatched primitive return, expected: "
+ + retClass + ", had: " + be.getJavaClass());
+ }
+ else
+ {
+ body.emit(C.RETURN, objx, gen);
+ if(retClass == void.class)
+ {
+ gen.pop();
+ }
+ else
+ gen.unbox(Type.getType(retClass));
+ }
+ }
abstract int numParams();
abstract String getMethodName();
abstract Type getReturnType();
@@ -5245,6 +5360,13 @@ public static class LetExpr implements Expr, MaybePrimitiveExpr{
if(sym.getNamespace() != null)
throw new Exception("Can't let qualified name: " + sym);
Expr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name);
+ if(isLoop)
+ {
+ if(maybePrimitiveType(init) == int.class)
+ init = new StaticMethodExpr("", 0, null, RT.class, "longCast", RT.vector(init));
+ else if(maybePrimitiveType(init) == float.class)
+ init = new StaticMethodExpr("", 0, null, RT.class, "doubleCast", RT.vector(init));
+ }
//sequential enhancement of env (like Lisp let*)
LocalBinding lb = registerLocal(sym, tagOf(sym), init,false);
BindingInit bi = new BindingInit(lb, init);
@@ -5389,18 +5511,47 @@ public static class RecurExpr implements Expr{
Class primc = lb.getPrimitiveType();
try
{
- if(!(arg instanceof MaybePrimitiveExpr && arg.hasJavaClass() && arg.getJavaClass() == primc))
- throw new IllegalArgumentException("recur arg for primitive local: " +
+ final Class pc = maybePrimitiveType(arg);
+ if(pc == primc)
+ ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen);
+ else if(primc == long.class && pc == int.class)
+ {
+ ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.visitInsn(I2L);
+ }
+ else if(primc == double.class && pc == float.class)
+ {
+ ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.visitInsn(F2D);
+ }
+ else if(primc == int.class && pc == long.class)
+ {
+ ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.invokeStatic(RT_TYPE, Method.getMethod("int intCast(long)"));
+ }
+ else if(primc == float.class && pc == double.class)
+ {
+ ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen);
+ gen.visitInsn(D2F);
+ }
+ else
+ {
+ if(RT.booleanCast(RT.WARN_ON_REFLECTION.deref()))
+ //throw new IllegalArgumentException
+ RT.errPrintWriter().println
+ ("recur arg for primitive local: " +
lb.name + " must be matching primitive, had: " +
(arg.hasJavaClass() ? arg.getJavaClass().getName():"Object") +
", needed: " +
primc.getName());
+ arg.emit(C.EXPRESSION, objx, gen);
+ HostExpr.emitUnboxArg(objx,gen,primc);
+ }
}
catch(Exception e)
{
throw new RuntimeException(e);
}
- ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen);
}
else
{
@@ -5501,28 +5652,28 @@ private static Expr analyze(C context, Object form, String name) throws Exceptio
return analyzeSymbol((Symbol) form);
else if(fclass == Keyword.class)
return registerKeyword((Keyword) form);
-// else if(form instanceof Num)
-// return new NumExpr((Num) form);
+ else if(form instanceof Number)
+ return NumberExpr.parse((Number) form);
else if(fclass == String.class)
return new StringExpr(((String) form).intern());
// else if(fclass == Character.class)
// return new CharExpr((Character) form);
- else if(form instanceof IPersistentCollection && ((IPersistentCollection) form).count() == 0)
- {
- Expr ret = new EmptyExpr(form);
- if(RT.meta(form) != null)
- ret = new MetaExpr(ret, MapExpr
- .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta()));
- return ret;
- }
- else if(form instanceof ISeq)
- return analyzeSeq(context, (ISeq) form, name);
- else if(form instanceof IPersistentVector)
- return VectorExpr.parse(context, (IPersistentVector) form);
- else if(form instanceof IPersistentMap)
- return MapExpr.parse(context, (IPersistentMap) form);
- else if(form instanceof IPersistentSet)
- return SetExpr.parse(context, (IPersistentSet) form);
+ else if(form instanceof IPersistentCollection && ((IPersistentCollection) form).count() == 0)
+ {
+ Expr ret = new EmptyExpr(form);
+ if(RT.meta(form) != null)
+ ret = new MetaExpr(ret, MapExpr
+ .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta()));
+ return ret;
+ }
+ else if(form instanceof ISeq)
+ return analyzeSeq(context, (ISeq) form, name);
+ else if(form instanceof IPersistentVector)
+ return VectorExpr.parse(context, (IPersistentVector) form);
+ else if(form instanceof IPersistentMap)
+ return MapExpr.parse(context, (IPersistentMap) form);
+ else if(form instanceof IPersistentSet)
+ return SetExpr.parse(context, (IPersistentSet) form);
// else
//throw new UnsupportedOperationException();
@@ -7004,27 +7155,7 @@ public static class NewInstanceMethod extends ObjMethod{
try
{
Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this));
- MaybePrimitiveExpr be = (MaybePrimitiveExpr) body;
- if(Util.isPrimitive(retClass) && be.canEmitPrimitive())
- {
- if(be.getJavaClass() == retClass)
- be.emitUnboxed(C.RETURN,obj,gen);
- //todo - support the standard widening conversions
- else
- throw new IllegalArgumentException("Mismatched primitive return, expected: "
- + retClass + ", had: " + be.getJavaClass());
- }
- else
- {
- body.emit(C.RETURN, obj, gen);
- if(retClass == void.class)
- {
- gen.pop();
- }
- else
- gen.unbox(retType);
- }
-
+ emitBody(objx, gen, retClass, body);
Label end = gen.mark();
gen.visitLocalVariable("this"