Skip to content

Commit

Permalink
proxy perf tweaks
Browse files Browse the repository at this point in the history
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
  • Loading branch information
richhickey committed Dec 13, 2008
1 parent f951752 commit 0444198
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 21 deletions.
48 changes: 31 additions & 17 deletions src/clj/clojure/core_proxy.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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))
Expand Down Expand Up @@ -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))))
Expand All @@ -107,32 +106,38 @@
(. 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)))
(let [m (. Method (getMethod "clojure.lang.IPersistentMap __getClojureFnMappings()"))
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)))

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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#)))

Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions src/jvm/clojure/lang/IProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

public interface IProxy{

public void __updateClojureFnMappings(IPersistentMap m);
public IPersistentMap __getClojureFnMappings();
public void __initClojureFnMappings(IPersistentMap m);
public void __updateClojureFnMappings(IPersistentMap m);
public IPersistentMap __getClojureFnMappings();

}
2 changes: 1 addition & 1 deletion src/jvm/clojure/lang/PersistentArrayMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
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();

Expand Down
4 changes: 3 additions & 1 deletion src/jvm/clojure/lang/RT.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit 0444198

Please sign in to comment.