On Wednesday, 9 October 2013 20:29:46 UTC+8, Mikhail Kryshen wrote:

> Nicola Mometto <brob...@gmail.com <javascript:>> writes: 
>
> > I don't think that's what Mike was talking about. 
> > Say we have (defn x ^long [] 1), clojure will use the IFn$L and emit an 
> > "public long invokePrim()" method. 
> > 
> > When we do (defn y [] (let [a (x)] a) the compiler will call .invokePrim 
> > instead of invoke. 
> > 
> > If we redefine (defn x [] "") then y won't work because the new version 
> > of x doesn't implement IFn$L, we'd need to recompile y too. 
>
> Actually I am talking about the same problem.  For virtual calls the JIT 
> compiler can determine that only one implementation of the method is 
> being used, inline the call and perform object explosion, effectively 
> removing boxing of primitives.  When new implementation becomes 
> available it dynamically recompiles affected bytecode.  I don't know if 
> the current implementation does this for invokedynamic calls, but there 
> is a potential.  It just does not feel right to invent a whole new 
> complex optimization layer on the Clojure side until we fully use the 
> optimization capabilities of the JVM. 
>

The JVM is certainly amazing at optimising virtual calls (to be expected 
since that's the usual calling convention for majority of Java OOP code....)

Clojure currently doesn't use virtual calls for functions however: that's 
part of the problem here. It pretty much always emits invokeinterface calls 
(via IFn and IFn's primitive variants). invokeinterface is slower than 
invokevirtual in many cases. They can certainly perform the same in cases 
where the JIT can eliminate the possibility of multiple implementations, 
but that's probably not going to be the case for IFn :-)

So part of making Clojure faster / making the most of the JVM should 
probably involve finding ways to use invokevirtual (or invokespecial) 
instead of invokeinterface where possible.

P.S. in the name of having some real performance data and to reassure 
myself that my knowledge of JVM behaviour is roughly correct, I made a 
quick caliper microbenchmark in Java to demonstrate the difference between 
interface and virtual dispatch:

 0% Scenario{vm=java, trial=0, benchmark=Interface} 13.04 ns; σ=0.19 ns @ 
10 trials
50% Scenario{vm=java, trial=0, benchmark=Virtual} 7.39 ns; σ=0.26 ns @ 10 
trials

benchmark    ns linear runtime
Interface 13.04 ==============================
  Virtual  7.39 =================

vm: java
trial: 0

Test code here for those interested:

https://github.com/mikera/vectorz/blob/develop/src/test/java/mikera/vectorz/performance/InterfaceVsVirtualBenchmark.java


-- 
-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to