Skip to content

Commit 0444198

Browse files
committed
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
1 parent f951752 commit 0444198

File tree

4 files changed

+38
-21
lines changed

4 files changed

+38
-21
lines changed

src/clj/clojure/core_proxy.clj

+31-17
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
(into-array (map totype cs))
3737
(make-array Type 0)))
3838
super-type (totype super)
39-
map-type (totype PersistentHashMap)
39+
imap-type (totype IPersistentMap)
4040
ifn-type (totype clojure.lang.IFn)
4141
obj-type (totype Object)
4242
sym-type (totype clojure.lang.Symbol)
@@ -54,10 +54,9 @@
5454
decl-type (. Type (getType (. meth (getDeclaringClass))))]
5555
(. gen (visitCode))
5656
(. gen (loadThis))
57-
(. gen (getField ctype fmap map-type))
58-
;get symbol corresponding to name
57+
(. gen (getField ctype fmap imap-type))
58+
5959
(. gen (push (. meth (getName))))
60-
(. gen (invokeStatic sym-type (. Method (getMethod "clojure.lang.Symbol create(String)"))))
6160
;lookup fn in map
6261
(. gen (invokeStatic rt-type (. Method (getMethod "Object get(Object, Object)"))))
6362
(. gen (dup))
@@ -94,7 +93,7 @@
9493
(into-array (map iname (cons IProxy interfaces)))))
9594
;add field for fn mappings
9695
(. cv (visitField (+ (. Opcodes ACC_PRIVATE) (. Opcodes ACC_VOLATILE))
97-
fmap (. map-type (getDescriptor)) nil nil))
96+
fmap (. imap-type (getDescriptor)) nil nil))
9897
;add ctors matching/calling super's
9998
(doseq [#^Constructor ctor (. super (getDeclaredConstructors))]
10099
(when-not (. Modifier (isPrivate (. ctor (getModifiers))))
@@ -107,32 +106,38 @@
107106
(. gen (dup))
108107
(. gen (loadArgs))
109108
(. gen (invokeConstructor super-type m))
110-
;init fmap
111-
(. gen (getStatic map-type "EMPTY" map-type))
112-
(. gen (putField ctype fmap map-type))
113109

114110
(. gen (returnValue))
115111
(. gen (endMethod)))))
116112
;add IProxy methods
113+
(let [m (. Method (getMethod "void __initClojureFnMappings(clojure.lang.IPersistentMap)"))
114+
gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
115+
(. gen (visitCode))
116+
(. gen (loadThis))
117+
(. gen (loadArgs))
118+
(. gen (putField ctype fmap imap-type))
119+
120+
(. gen (returnValue))
121+
(. gen (endMethod)))
117122
(let [m (. Method (getMethod "void __updateClojureFnMappings(clojure.lang.IPersistentMap)"))
118123
gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
119124
(. gen (visitCode))
120125
(. gen (loadThis))
121126
(. gen (dup))
122-
(. gen (getField ctype fmap map-type))
127+
(. gen (getField ctype fmap imap-type))
123128
(. gen (loadArgs))
124129
(. gen (invokeInterface (totype clojure.lang.IPersistentCollection)
125130
(. Method (getMethod "clojure.lang.IPersistentCollection cons(Object)"))))
126-
(. gen (checkCast map-type))
127-
(. gen (putField ctype fmap map-type))
131+
(. gen (checkCast imap-type))
132+
(. gen (putField ctype fmap imap-type))
128133

129134
(. gen (returnValue))
130135
(. gen (endMethod)))
131136
(let [m (. Method (getMethod "clojure.lang.IPersistentMap __getClojureFnMappings()"))
132137
gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
133138
(. gen (visitCode))
134139
(. gen (loadThis))
135-
(. gen (getField ctype fmap map-type))
140+
(. gen (getField ctype fmap imap-type))
136141
(. gen (returnValue))
137142
(. gen (endMethod)))
138143

@@ -210,8 +215,17 @@
210215
[c & ctor-args]
211216
(. Reflector (invokeConstructor c (to-array ctor-args))))
212217

218+
(defn init-proxy
219+
"Takes a proxy instance and a map of strings (which must
220+
correspond to methods of the proxy superclass/superinterfaces) to
221+
fns (which must take arguments matching the corresponding method,
222+
plus an additional (explicit) first arg corresponding to this, and
223+
sets the proxy's fn map."
224+
[#^IProxy proxy mappings]
225+
(. proxy (__initClojureFnMappings mappings)))
226+
213227
(defn update-proxy
214-
"Takes a proxy instance and a map of symbols (whose names must
228+
"Takes a proxy instance and a map of strings (which must
215229
correspond to methods of the proxy superclass/superinterfaces) to
216230
fns (which must take arguments matching the corresponding method,
217231
plus an additional (explicit) first arg corresponding to this, and
@@ -259,9 +273,9 @@
259273
(clojure.lang.Compiler/writeClassFile cname bytecode)))
260274
pc-effect (apply get-proxy-class bases)
261275
pname (proxy-name super interfaces)]
262-
`(let [pc# (get-proxy-class ~@class-and-interfaces)
276+
`(let [;pc# (get-proxy-class ~@class-and-interfaces)
263277
p# (new ~(symbol pname) ~@args)] ;(construct-proxy pc# ~@args)]
264-
(update-proxy p#
278+
(init-proxy p#
265279
~(loop [fmap {} fs fs]
266280
(if fs
267281
(let [[sym & meths] (first fs)
@@ -271,7 +285,7 @@
271285
meths (map (fn [[params & body]]
272286
(cons (apply vector 'this params) body))
273287
meths)]
274-
(recur (assoc fmap (list `quote (symbol (name sym))) (cons `fn meths)) (rest fs)))
288+
(recur (assoc fmap (name sym) (cons `fn meths)) (rest fs)))
275289
fmap)))
276290
p#)))
277291

@@ -286,7 +300,7 @@
286300
"Use to call a superclass method in the body of a proxy method.
287301
Note, expansion captures 'this"
288302
[meth & args]
289-
`(proxy-call-with-super (fn [] (. ~'this ~meth ~@args)) ~'this '~(symbol (name meth))))
303+
`(proxy-call-with-super (fn [] (. ~'this ~meth ~@args)) ~'this ~(name meth)))
290304

291305
(defn bean
292306
"Takes a Java object and returns a read-only implementation of the

src/jvm/clojure/lang/IProxy.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414

1515
public interface IProxy{
1616

17-
public void __updateClojureFnMappings(IPersistentMap m);
18-
public IPersistentMap __getClojureFnMappings();
17+
public void __initClojureFnMappings(IPersistentMap m);
18+
public void __updateClojureFnMappings(IPersistentMap m);
19+
public IPersistentMap __getClojureFnMappings();
1920

2021
}

src/jvm/clojure/lang/PersistentArrayMap.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
public class PersistentArrayMap extends APersistentMap{
2828

2929
final Object[] array;
30-
static final int HASHTABLE_THRESHOLD = 8;
30+
static final int HASHTABLE_THRESHOLD = 16;
3131

3232
public static final PersistentArrayMap EMPTY = new PersistentArrayMap();
3333

src/jvm/clojure/lang/RT.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,9 @@ static public double doubleCast(double x){
966966
}
967967

968968
static public IPersistentMap map(Object... init){
969-
if(init != null && init.length == 2)
969+
if(init == null)
970+
return PersistentArrayMap.EMPTY;
971+
else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD)
970972
return new PersistentArrayMap(init);
971973
return PersistentHashMap.create(init);
972974
}

0 commit comments

Comments
 (0)