diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-12-13 19:25:10 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-12-13 19:25:10 +0000 |
commit | 044419862707c9a540b8e42faad0f69bc66fe1fd (patch) | |
tree | 512b15b4ea91c09f9b39156213db39db8da892c0 /src | |
parent | f95175264df36c3d8fe2113aa9af92cda0f2f5c8 (diff) |
proxy perf tweaks
Note breaking change if you are using the proxy interface other than the proxy macro itself - proxy maps are now maps of (preferably interned) strings to fns, not symbols to fns, and if you construct a proxy manually you must establish initial map with init-proxy
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/core_proxy.clj | 48 | ||||
-rw-r--r-- | src/jvm/clojure/lang/IProxy.java | 5 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentArrayMap.java | 2 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 4 |
4 files changed, 38 insertions, 21 deletions
diff --git a/src/clj/clojure/core_proxy.clj b/src/clj/clojure/core_proxy.clj index 897d15e9..c47d0d0b 100644 --- a/src/clj/clojure/core_proxy.clj +++ b/src/clj/clojure/core_proxy.clj @@ -36,7 +36,7 @@ (into-array (map totype cs)) (make-array Type 0))) super-type (totype super) - map-type (totype PersistentHashMap) + imap-type (totype IPersistentMap) ifn-type (totype clojure.lang.IFn) obj-type (totype Object) sym-type (totype clojure.lang.Symbol) @@ -54,10 +54,9 @@ decl-type (. Type (getType (. meth (getDeclaringClass))))] (. gen (visitCode)) (. gen (loadThis)) - (. gen (getField ctype fmap map-type)) - ;get symbol corresponding to name + (. gen (getField ctype fmap imap-type)) + (. gen (push (. meth (getName)))) - (. gen (invokeStatic sym-type (. Method (getMethod "clojure.lang.Symbol create(String)")))) ;lookup fn in map (. gen (invokeStatic rt-type (. Method (getMethod "Object get(Object, Object)")))) (. gen (dup)) @@ -94,7 +93,7 @@ (into-array (map iname (cons IProxy interfaces))))) ;add field for fn mappings (. cv (visitField (+ (. Opcodes ACC_PRIVATE) (. Opcodes ACC_VOLATILE)) - fmap (. map-type (getDescriptor)) nil nil)) + fmap (. imap-type (getDescriptor)) nil nil)) ;add ctors matching/calling super's (doseq [#^Constructor ctor (. super (getDeclaredConstructors))] (when-not (. Modifier (isPrivate (. ctor (getModifiers)))) @@ -107,24 +106,30 @@ (. gen (dup)) (. gen (loadArgs)) (. gen (invokeConstructor super-type m)) - ;init fmap - (. gen (getStatic map-type "EMPTY" map-type)) - (. gen (putField ctype fmap map-type)) (. gen (returnValue)) (. gen (endMethod))))) ;add IProxy methods + (let [m (. Method (getMethod "void __initClojureFnMappings(clojure.lang.IPersistentMap)")) + gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)] + (. gen (visitCode)) + (. gen (loadThis)) + (. gen (loadArgs)) + (. gen (putField ctype fmap imap-type)) + + (. gen (returnValue)) + (. gen (endMethod))) (let [m (. Method (getMethod "void __updateClojureFnMappings(clojure.lang.IPersistentMap)")) gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)] (. gen (visitCode)) (. gen (loadThis)) (. gen (dup)) - (. gen (getField ctype fmap map-type)) + (. gen (getField ctype fmap imap-type)) (. gen (loadArgs)) (. gen (invokeInterface (totype clojure.lang.IPersistentCollection) (. Method (getMethod "clojure.lang.IPersistentCollection cons(Object)")))) - (. gen (checkCast map-type)) - (. gen (putField ctype fmap map-type)) + (. gen (checkCast imap-type)) + (. gen (putField ctype fmap imap-type)) (. gen (returnValue)) (. gen (endMethod))) @@ -132,7 +137,7 @@ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)] (. gen (visitCode)) (. gen (loadThis)) - (. gen (getField ctype fmap map-type)) + (. gen (getField ctype fmap imap-type)) (. gen (returnValue)) (. gen (endMethod))) @@ -210,8 +215,17 @@ [c & ctor-args] (. Reflector (invokeConstructor c (to-array ctor-args)))) +(defn init-proxy + "Takes a proxy instance and a map of strings (which must + correspond to methods of the proxy superclass/superinterfaces) to + fns (which must take arguments matching the corresponding method, + plus an additional (explicit) first arg corresponding to this, and + sets the proxy's fn map." + [#^IProxy proxy mappings] + (. proxy (__initClojureFnMappings mappings))) + (defn update-proxy - "Takes a proxy instance and a map of symbols (whose names must + "Takes a proxy instance and a map of strings (which must correspond to methods of the proxy superclass/superinterfaces) to fns (which must take arguments matching the corresponding method, plus an additional (explicit) first arg corresponding to this, and @@ -259,9 +273,9 @@ (clojure.lang.Compiler/writeClassFile cname bytecode))) pc-effect (apply get-proxy-class bases) pname (proxy-name super interfaces)] - `(let [pc# (get-proxy-class ~@class-and-interfaces) + `(let [;pc# (get-proxy-class ~@class-and-interfaces) p# (new ~(symbol pname) ~@args)] ;(construct-proxy pc# ~@args)] - (update-proxy p# + (init-proxy p# ~(loop [fmap {} fs fs] (if fs (let [[sym & meths] (first fs) @@ -271,7 +285,7 @@ meths (map (fn [[params & body]] (cons (apply vector 'this params) body)) meths)] - (recur (assoc fmap (list `quote (symbol (name sym))) (cons `fn meths)) (rest fs))) + (recur (assoc fmap (name sym) (cons `fn meths)) (rest fs))) fmap))) p#))) @@ -286,7 +300,7 @@ "Use to call a superclass method in the body of a proxy method. Note, expansion captures 'this" [meth & args] - `(proxy-call-with-super (fn [] (. ~'this ~meth ~@args)) ~'this '~(symbol (name meth)))) + `(proxy-call-with-super (fn [] (. ~'this ~meth ~@args)) ~'this ~(name meth))) (defn bean "Takes a Java object and returns a read-only implementation of the diff --git a/src/jvm/clojure/lang/IProxy.java b/src/jvm/clojure/lang/IProxy.java index 7f3630f9..c32521a7 100644 --- a/src/jvm/clojure/lang/IProxy.java +++ b/src/jvm/clojure/lang/IProxy.java @@ -14,7 +14,8 @@ package clojure.lang; public interface IProxy{ -public void __updateClojureFnMappings(IPersistentMap m); -public IPersistentMap __getClojureFnMappings(); + public void __initClojureFnMappings(IPersistentMap m); + public void __updateClojureFnMappings(IPersistentMap m); + public IPersistentMap __getClojureFnMappings(); } diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java index 070fe1bf..009b1fe8 100644 --- a/src/jvm/clojure/lang/PersistentArrayMap.java +++ b/src/jvm/clojure/lang/PersistentArrayMap.java @@ -27,7 +27,7 @@ import java.util.Map; public class PersistentArrayMap extends APersistentMap{
final Object[] array;
-static final int HASHTABLE_THRESHOLD = 8;
+static final int HASHTABLE_THRESHOLD = 16;
public static final PersistentArrayMap EMPTY = new PersistentArrayMap();
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index ae18bfce..7a31bbdf 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -966,7 +966,9 @@ static public double doubleCast(double x){ } static public IPersistentMap map(Object... init){ - if(init != null && init.length == 2) + if(init == null) + return PersistentArrayMap.EMPTY; + else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD) return new PersistentArrayMap(init); return PersistentHashMap.create(init); } |