ReflectASM: fast reflection

I recently replaced reflection with bytecode generation in one of my projects. After an evening with the ASM library I had a much faster solution than reflection. It occurred to me that the code was easily reusable, so I created a small project:

http://code.google.com/p/reflectasm/

Usage looks like this:

FieldAccess access = FieldAccess.get(SomeClass.class);
access.set(someObject, "someFieldName", "someValue");
System.out.println(access.get(someObject, "someFieldName"));

Or slightly more efficiently:

int fieldIndex = access.getIndex("someFieldName");
access.set(someObject, fieldIndex, "someValue");
System.out.println(access.get(someObject, fieldIndex));

ReflectASM performance is very close to compiled code, there is just the overhead of calling the get or set method and a switch statement. I’ve only done public field access, I’ll add method access and proper documentation when I find some more free time.

It seems the JIT could generate a class if it detects enough reflection usage. It doesn’t appear to bother. Any good reasons why?

I wouldn’t be surprised if a project like this already exists. If it does, please let me know!

Any fancy pie-charts on how it compares to:
http://www.java-gaming.org/index.php/topic,21175.0.html

?

That is caching the field rather than looking it up. If you are serious about performance, you’d keep the field object around without even a map lookup. Here is FieldAccess versus the JDK’s reflection, without even a map lookup:

http://chart.apis.google.com/chart?chtt=Set%20and%20Get&chs=700x57&chd=t:14.069932,208.21866&chds=0,208.21866&chxl=0:|Reflection|FieldAccess&cht=bhg&chbh=10&chxt=y&chco=6600CC|6600FF

The results as numbers:

The benchmark:


import java.lang.reflect.Field;
import java.util.HashMap;

public class Benchmark {
	public static void main (String[] args) throws Exception {
		int count = 10000000;
		Object[] dontCompileMeAway = new Object[count];

		FieldAccess access = FieldAccess.get(SomeClass.class);
		SomeClass someObject = new SomeClass();
		int index = access.getIndex("name");

		Field field = SomeClass.class.getField("name");

		for (int i = 0; i < 100; i++) {
			for (int ii = 0; ii < count; ii++) {
				access.set(someObject, index, "first");
				dontCompileMeAway[ii] = access.get(someObject, index);
			}
			for (int ii = 0; ii < count; ii++) {
				field.set(someObject, "first");
				dontCompileMeAway[ii] = field.get(someObject);
			}
		}
		warmup = false;

		for (int i = 0; i < 100; i++) {
			start();
			for (int ii = 0; ii < count; ii++) {
				access.set(someObject, index, "first");
				dontCompileMeAway[ii] = access.get(someObject, index);
			}
			end("FieldAccess");
		}
		for (int i = 0; i < 100; i++) {
			start();
			for (int ii = 0; ii < count; ii++) {
				field.set(someObject, "first");
				dontCompileMeAway[ii] = field.get(someObject);
			}
			end("Reflection");
		}
	}

	static boolean warmup = true;
	static long s;

	static void start () {
		s = System.nanoTime();
	}

	static void end (String name) {
		if (warmup) return;
		long e = System.nanoTime();
		long time = e - s;
		System.out.println(name + ": " + time / 1000000f + " ms");
	}

	static public class SomeClass {
		public String name;
	}
}

I finally got around to implementing this for methods. Interesting, reflection does better with methods.

http://chart.apis.google.com/chart?chtt=Method%20Call&chs=700x57&chd=t:9339025,28118418&chds=0,28118418&chxl=0:|Reflection|MethodAccess&cht=bhg&chbh=10&chxt=y&chco=660000|660033|660066|660099|6600CC|6600FF|663300|663333|663366|663399|6633CC|6633FF|666600|666633|666666

This shows the overall difference between using fields and methods:

http://chart.apis.google.com/chart?chtt=Reflection+vs+ReflectASM&chs=700x93&chd=t:14.088954,176.99704,46.756,136.72726&chds=0,176.99704&chxl=0:|Method+Reflection|MethodAccess|Field+Reflection|FieldAccess&cht=bhg&chbh=10&chxt=y&chco=6600CC|6600FF

Raw data:

Benchmark code is checked in with the project.

I also added proper documentation on the homepage.