summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2009-11-15 12:37:32 -0500
committerRich Hickey <richhickey@gmail.com>2009-11-15 12:37:32 -0500
commitecd7161bf4397f04385fdaf9e5c6168580676ffa (patch)
treef10c8901e09939e522445d06bd36d797683d3521
parenta64704a9f163ed7271e527587c4d27073c25fc48 (diff)
perf tweaks
-rw-r--r--src/clj/clojure/core_deftype.clj14
-rw-r--r--src/jvm/clojure/lang/Compiler.java8
-rw-r--r--src/jvm/clojure/lang/MethodImplCache.java13
-rw-r--r--src/jvm/clojure/lang/Util.java10
-rw-r--r--src/jvm/clojure/lang/Var.java2
5 files changed, 35 insertions, 12 deletions
diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj
index 58827784..3d77ad47 100644
--- a/src/clj/clojure/core_deftype.clj
+++ b/src/clj/clojure/core_deftype.clj
@@ -260,11 +260,13 @@
`(if (instance? ~on-interface ~target)
(. ~(with-meta target {:tag on-interface}) ~(or on-method method) ~@(rest gargs)))
`(do))
- (let [cache# (.__methodImplCache ~gthis)
- c# (class ~target)
- f# (or (.fnFor cache# c#)
- (-cache-protocol-fn ~gthis ~target))]
- (f# ~@gargs))))))
+ (let [cache# (.__methodImplCache ~gthis)]
+ (if (clojure.lang.Util/identical (clojure.lang.Util/classOf ~target)
+ (.lastClass cache#))
+ ((.lastImpl cache#) ~@gargs)
+ (let [f# (or (.fnFor cache# (clojure.lang.Util/classOf ~target))
+ (-cache-protocol-fn ~gthis ~target))]
+ (f# ~@gargs))))))))
arglists))]
(set! (.__methodImplCache f#) cache#)
f#))))
@@ -287,7 +289,7 @@
(defn- emit-protocol [name opts+sigs]
(let [[opts sigs]
- (loop [opts {} sigs opts+sigs]
+ (loop [opts {:on nil} sigs opts+sigs]
(condp #(%1 %2) (first sigs)
string? (recur (assoc opts :doc (first sigs)) (next sigs))
keyword? (recur (assoc opts (first sigs) (second sigs)) (nnext sigs))
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 3f61aba0..24ccd87b 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -2755,7 +2755,8 @@ static class InvokeExpr implements Expr{
Expr e = (Expr) args.nth(0);
e.emit(C.EXPRESSION, objx, gen);
gen.dup(); //target, target
- gen.invokeVirtual(OBJECT_TYPE,Method.getMethod("Class getClass()")); //target,class
+ gen.invokeStatic(UTIL_TYPE,Method.getMethod("Class classOf(Object)")); //target,class
+// gen.invokeVirtual(OBJECT_TYPE,Method.getMethod("Class getClass()")); //target,class
gen.dup(); //target,class,class
gen.loadThis();
gen.getField(objx.objtype, objx.cachedClassName(siteIndex),CLASS_TYPE); //target,class,class,cached-class
@@ -2778,19 +2779,17 @@ static class InvokeExpr implements Expr{
gen.dup(); //target,class,class
gen.loadThis();
gen.swap();
- //gen.checkCast(CLASS_TYPE);
gen.putField(objx.objtype, objx.cachedClassName(siteIndex),CLASS_TYPE); //target,class
objx.emitVar(gen, v);
gen.invokeVirtual(VAR_TYPE, Method.getMethod("Object getRawRoot()")); //target, class, proto-fn
gen.mark(elseLabel); //target, class, proto-fn
+ gen.checkCast(AFUNCTION_TYPE);
gen.dup(); //target,class,proto-fn,proto-fn
gen.loadThis();
gen.swap();
- gen.checkCast(AFUNCTION_TYPE);
gen.putField(objx.objtype, objx.cachedProtoFnName(siteIndex),AFUNCTION_TYPE); //target, class, proto-fn
gen.dupX1(); //target, proto-fn, class, proto-fn
- gen.checkCast(AFUNCTION_TYPE);
gen.getField(AFUNCTION_TYPE,"__methodImplCache", Type.getType(MethodImplCache.class)); //target,protofn,class,cache
gen.swap(); //target,protofn,cache,class
gen.invokeVirtual(Type.getType(MethodImplCache.class),Method.getMethod("clojure.lang.IFn fnFor(Class)")); //target,protofn,impl
@@ -2801,7 +2800,6 @@ static class InvokeExpr implements Expr{
gen.dup(); //target,impl, impl
gen.loadThis();
gen.swap();
- gen.checkCast(IFN_TYPE);
gen.putField(objx.objtype, objx.cachedProtoImplName(siteIndex),IFN_TYPE); //target,impl
gen.swap(); //impl,target
gen.goTo(callLabel);
diff --git a/src/jvm/clojure/lang/MethodImplCache.java b/src/jvm/clojure/lang/MethodImplCache.java
index 8aac1c69..a8670a57 100644
--- a/src/jvm/clojure/lang/MethodImplCache.java
+++ b/src/jvm/clojure/lang/MethodImplCache.java
@@ -19,6 +19,10 @@ public final int shift;
public final int mask;
public final Object[] table; //[class, fn. class, fn ...]
+//these are not volatile by design
+public Object lastClass;
+public IFn lastImpl;
+
public MethodImplCache(IPersistentMap protocol, Keyword methodk){
this(protocol, methodk, 0, 0, RT.EMPTY_ARRAY);
}
@@ -29,12 +33,19 @@ public MethodImplCache(IPersistentMap protocol, Keyword methodk, int shift, int
this.shift = shift;
this.mask = mask;
this.table = table;
+ this.lastClass = this;
}
public IFn fnFor(Class c){
+ if(c == lastClass)
+ return lastImpl;
int idx = ((Util.hash(c) >> shift) & mask) << 1;
if(idx < table.length && table[idx] == c)
- return (IFn) table[idx + 1];
+ {
+ lastClass = c;
+ return lastImpl =
+ (IFn) table[idx + 1];
+ }
return null;
}
diff --git a/src/jvm/clojure/lang/Util.java b/src/jvm/clojure/lang/Util.java
index 0fd54475..6dcdade0 100644
--- a/src/jvm/clojure/lang/Util.java
+++ b/src/jvm/clojure/lang/Util.java
@@ -35,6 +35,16 @@ static public boolean equals(Object k1, Object k2){
return k1 != null && k1.equals(k2);
}
+static public boolean identical(Object k1, Object k2){
+ return k1 == k2;
+}
+
+static public Class classOf(Object x){
+ if(x != null)
+ return x.getClass();
+ return null;
+}
+
static public int compare(Object k1, Object k2){
if(k1 == k2)
return 0;
diff --git a/src/jvm/clojure/lang/Var.java b/src/jvm/clojure/lang/Var.java
index f2681f0c..2a603b03 100644
--- a/src/jvm/clojure/lang/Var.java
+++ b/src/jvm/clojure/lang/Var.java
@@ -128,6 +128,8 @@ public boolean isBound(){
}
final public Object get(){
+ if(count.get() == 0 && root != dvals)
+ return root;
return deref();
}