[picocontainer-dev] reflectasm - allegedly faster reflection calls.
Paul Hammant <[email protected]> Thu, 8 Dec 2011 09:26:53 -0600
| Newsgroups | gmane.comp.java.picocontainer.devel |
|---|---|
| Message-ID | <CA+298Ujp6vKxpT2bmDr1QXwTpbHHcAzEdSd6yedku-+B+0eHaA@mail.gmail.com> |
--0015174c3d5c4f094904b3964c4e
Content-Type: text/plain; charset=ISO-8859-1
This looked interesting :-
http://code.google.com/p/reflectasm/
... looks pretty intriguing. Faster it claims.
I did some testing last night and it's only 10% faster than regular
reflection for method invocations, and only if your cache the ASM-made
subclass of "MethodAccess".
There are some flaws too:
1. It generates accessors for each method in a class - you may have
been interested in only a single method.
2. It assumed that there is no method overloading in the class
3. Exceptions will pass through (no InvocationTargetException), yet
are not (and cannot be) concisely listed on the throws clause of the
var-args invoke method you use. You have to be aware of the exceptions
that could be thrown, or catch base Exception (yeesh).
It does one interesting trick. See
http://reflectasm.googlecode.com/svn/trunk/src/com/esotericsoftware/reflectasm/MethodAccess.java
MethodAccess (the class) is in your regular classpath on use, as normal
Java launch semantics. The classes that ASM generates ALSO purport to be
MethodAccess (same package), but by some defineClass magic in a child
class-loader, are instantiated instead of the real deal. The Java Compiler
lets you think you are using static method on MethodAccess, but at runtime
you are using a method with the same signature in a different class (with
the same name).
It got me thinking though.
Say, for @Inject methods (and constructors, poss fields too)
There could be a QDox build stage that kicks in and makes an invoke class
for each so-annotated method.
In the same way that GMaven allows Java and Groovy to interop in the same
source buildable jar (by generating shims of the Groovy classes for the
Java classes to compile against), some tricks that JetBrains and Eclipse
would buy into would allow a method invocation design that was more first
class than reflection. For example:
public class Foo {
@Inject
public void bar(Baz baz) {
}
}
public static void main(String[] args) {
Foo instance = new Foo();
Foo.bar1965ed0b.invoke(instance, new Baz());
}
// 1965ed0b is a CRC32 hash of 'Baz baz'
PicoContainer, Guice etc could speculatively look for the inner
class bar1965ed0b and use it. It would still not preserve throws clauses
as Pico/Guice would cast it to a interface to use it for the speed you're
seeking. It would be in the same jar file of course. Shame about the
extra bytes - AFAICR the min byte size of an inner class is 178.
Java7's project coin <http://openjdk.java.net/projects/coin/> makes this a
bit moot though perhaps.
- Paul
--0015174c3d5c4f094904b3964c4e
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
This looked interesting :-=A0<div><br></div><div>=A0 =A0<a href=3D"http://c=
ode.google.com/p/reflectasm/" target=3D"_blank">http://code.google.com/p/re=
flectasm/</a>=A0</div>
<div><br></div><div>... looks pretty intriguing. Faster it claims.</div><di=
v><br></div><div>I did some testing last night and it's only 10% faster=
than regular reflection for method invocations, and only if your cache the=
ASM-made subclass of "MethodAccess".</div>
<div><br></div><div>There are some flaws too: =A0</div><div><ol><li>=A0 It =
generates accessors for each method in a class =A0- you may have been inter=
ested in only a single method.</li><li>=A0 It assumed that there is no meth=
od overloading in the class</li>
<li>=A0 Exceptions will pass through (no InvocationTargetException), yet ar=
e not (and cannot be) concisely listed on the throws clause of the var-args=
invoke method you use. =A0You have to be aware of the exceptions that coul=
d be thrown, or catch base Exception (yeesh).</li>
</ol><div>It does one interesting trick. See=A0<a href=3D"http://reflectasm=
.googlecode.com/svn/trunk/src/com/esotericsoftware/reflectasm/MethodAccess.=
java" target=3D"_blank">http://reflectasm.googlecode.com/svn/trunk/src/com/=
esotericsoftware/reflectasm/MethodAccess.java</a></div>
</div><div><br></div><div>MethodAccess (the class) is in your regular class=
path on use, as normal Java launch semantics. =A0The classes that ASM gener=
ates ALSO purport to be MethodAccess (same package), but by some defineClas=
s magic in a child class-loader, are instantiated instead of the real deal.=
=A0The Java Compiler lets you think you are using static method on MethodA=
ccess, but at runtime you are using a method with the same signature in a d=
ifferent class (with the same name).</div>
<div><br></div><div>It got me thinking though.</div><div><br></div><div>Say=
, for @Inject methods (and constructors, poss fields too)</div><div>There c=
ould be a QDox build stage that kicks in and makes an invoke class for each=
so-annotated method. =A0</div>
<div><br></div><div>In the same way that GMaven allows Java and Groovy to i=
nterop in the same source buildable jar (by generating shims of the Groovy =
classes for the Java classes to compile against), some tricks that JetBrain=
s and Eclipse would buy into would allow a method invocation design that wa=
s more first class than reflection. =A0For example:</div>
<div><br></div><blockquote style=3D"margin:0 0 0 40px;border:none;padding:0=
px"><div>public class Foo {</div><div>=A0 =A0 @Inject</div><div>=A0 =A0 pub=
lic void bar(Baz baz) {</div><div>=A0 =A0 }</div>
<div>}</div><div><br></div><div>public static void main(String[] args) {</d=
iv><div>=A0 =A0 Foo instance =3D new Foo();</div><div><span>=A0 =A0 Foo.bar=
1965ed0b.invoke(</span>instance<span>, new Baz());</span></div>
<div>}</div></blockquote><div>=A0 =A0 =A0 =A0 =A0 //=A01965ed0b is a CRC32 =
hash of 'Baz baz'</div><div><br></div><div><br></div><div>PicoConta=
iner, Guice etc could speculatively look for the inner class=A0bar1965ed0b =
and use it. =A0It would still not preserve throws clauses as Pico/Guice wou=
ld cast it to a interface to use it for the speed you're seeking. =A0It=
would be in the same jar file of course. =A0Shame about the extra bytes -=
=A0AFAICR the min byte size of an inner class is 178.</div>
<div><br></div><div>Java7's <a href=3D"http://openjdk.java.net/projects=
/coin/">project coin</a> makes this a bit moot though perhaps.</div><div><b=
r></div><div>- Paul=A0</div>
--0015174c3d5c4f094904b3964c4e--