Skip to content

Commit de6fb8d

Browse files
author
Sam Pullara
committed
tighten up the indy code to try and get it to perform
1 parent 451c559 commit de6fb8d

5 files changed

Lines changed: 159 additions & 14 deletions

File tree

indy/src/main/java/com/github/mustachejava/indy/IndyWrapper.java

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.github.mustachejava.util.GuardException;
66
import org.objectweb.asm.ClassWriter;
77
import org.objectweb.asm.Handle;
8+
import org.objectweb.asm.Label;
89
import org.objectweb.asm.Opcodes;
910
import org.objectweb.asm.Type;
1011
import org.objectweb.asm.commons.GeneratorAdapter;
@@ -54,15 +55,11 @@ protected IndyWrapper(ReflectionWrapper rw) {
5455
super(rw);
5556
}
5657

57-
@Override
58-
public Object call(Object[] scopes) throws GuardException {
59-
guardCall(scopes);
60-
Object scope = unwrap(scopes);
61-
if (scope == null) return null;
62-
return indy(scope);
63-
}
64-
65-
public abstract Object indy(Object scope);
58+
public abstract Object call(Object[] scopes) throws GuardException; // {
59+
// guardCall(scopes);
60+
// Object scope = unwrap(scopes);
61+
// if (scope == null) return null;
62+
// return indy(scope);
6663

6764
public static IndyWrapper create(ReflectionWrapper rw) {
6865
String name;
@@ -92,10 +89,26 @@ public static IndyWrapper create(ReflectionWrapper rw) {
9289
ga.endMethod();
9390
}
9491
{
95-
GeneratorAdapter ga = new GeneratorAdapter(ACC_PROTECTED,
96-
org.objectweb.asm.commons.Method.getMethod("Object indy(Object)"), null, null, cw);
97-
ga.loadThis();
98-
ga.loadArg(0);
92+
GeneratorAdapter ga = new GeneratorAdapter(ACC_PUBLIC,
93+
org.objectweb.asm.commons.Method.getMethod("Object call(Object[])"), null,
94+
new Type[] { Type.getType(GuardException.class)}, cw);
95+
ga.visitVarInsn(ALOAD, 0);
96+
ga.visitVarInsn(ALOAD, 1);
97+
ga.invokeVirtual(Type.getType(IndyWrapper.class),
98+
org.objectweb.asm.commons.Method.getMethod("void guardCall(Object[])"));
99+
ga.visitVarInsn(ALOAD, 0);
100+
ga.visitVarInsn(ALOAD, 1);
101+
ga.invokeVirtual(Type.getType(IndyWrapper.class),
102+
org.objectweb.asm.commons.Method.getMethod("Object unwrap(Object[])"));
103+
ga.visitVarInsn(ASTORE, 2);
104+
ga.visitVarInsn(ALOAD, 2);
105+
Label l0 = new Label();
106+
ga.ifNonNull(l0);
107+
ga.visitInsn(ACONST_NULL);
108+
ga.returnValue();
109+
ga.visitLabel(l0);
110+
ga.visitVarInsn(ALOAD, 0);
111+
ga.visitVarInsn(ALOAD, 2);
99112
ga.invokeDynamic("bootstrap", METHOD_SIGNATURE, BOOTSTRAP_METHOD);
100113
ga.returnValue();
101114
ga.endMethod();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.github.mustachejava.mh;
2+
3+
import com.github.mustachejava.indy.IndyWrapper;
4+
import com.github.mustachejava.reflect.ReflectionObjectHandler;
5+
import com.github.mustachejava.reflect.ReflectionWrapper;
6+
import com.github.mustachejava.util.Wrapper;
7+
import org.objectweb.asm.Opcodes;
8+
9+
/**
10+
* Creates custom classes instead of using reflection for handling objects. Leverages
11+
* the ReflectionObjectHandler to create the original wrappers and converts them to
12+
* new versions.
13+
*/
14+
public class MHObjectHandler extends ReflectionObjectHandler implements Opcodes {
15+
16+
@Override
17+
public Wrapper find(String name, Object[] scopes) {
18+
ReflectionWrapper rw = (ReflectionWrapper) super.find(name, scopes);
19+
try {
20+
return rw == null ? null : new MHWrapper(rw);
21+
} catch (IllegalAccessException e) {
22+
throw new RuntimeException(e);
23+
}
24+
}
25+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.github.mustachejava.mh;
2+
3+
import java.lang.invoke.MethodHandle;
4+
import java.lang.invoke.MethodHandles;
5+
import java.lang.reflect.Field;
6+
import java.lang.reflect.Method;
7+
8+
import com.github.mustachejava.MustacheException;
9+
import com.github.mustachejava.reflect.ReflectionWrapper;
10+
import com.github.mustachejava.util.GuardException;
11+
12+
public class MHWrapper extends ReflectionWrapper {
13+
14+
private MethodHandle mh;
15+
16+
MHWrapper(ReflectionWrapper rw) throws IllegalAccessException {
17+
super(rw);
18+
Method method = rw.getMethod();
19+
if (method == null) {
20+
Field field = rw.getField();
21+
mh = MethodHandles.lookup().unreflectGetter(field);
22+
} else {
23+
mh = MethodHandles.lookup().unreflect(method);
24+
}
25+
}
26+
27+
@Override
28+
public Object call(Object[] scopes) throws GuardException {
29+
try {
30+
guardCall(scopes);
31+
Object scope = unwrap(scopes);
32+
if (scope == null) return null;
33+
if (arguments == null) {
34+
return mh.bindTo(scope).invokeWithArguments();
35+
} else {
36+
return mh.bindTo(scope).invokeExact(arguments);
37+
}
38+
} catch (Throwable e) {
39+
throw new MustacheException("Failed to execute method: " + method, e);
40+
}
41+
}
42+
}

indy/src/test/java/IndyDemo.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import java.lang.invoke.*;
2+
import java.lang.reflect.*;
3+
4+
public class IndyDemo {
5+
public static void main(String[] args) throws Throwable {
6+
for (int i = 0; i < 10; i++) {
7+
timeReflection();
8+
timeIndy();
9+
}
10+
}
11+
12+
private static final String[] strings;
13+
14+
static {
15+
strings = new String[100];
16+
for (int i = 0; i < 100; i++) {
17+
strings[i] = "string" + i;
18+
}
19+
}
20+
21+
public static void timeReflection() throws Throwable {
22+
long start = System.currentTimeMillis();
23+
for (int i = 0; i < 100000000; i++) {
24+
REFLECTED.invoke(null, strings[i % 100]);
25+
}
26+
System.out.println("reflected: " + (System.currentTimeMillis() - start));
27+
}
28+
29+
public static void timeIndy() throws Throwable {
30+
long start = System.currentTimeMillis();
31+
for (int i = 0; i < 100000000; i++) {
32+
HANDLE.invokeExact(strings[i % 100]);
33+
}
34+
System.out.println("indy: " + (System.currentTimeMillis() - start));
35+
}
36+
37+
private static final Method REFLECTED;
38+
private static final MethodHandle HANDLE;
39+
40+
static {
41+
Method method = null;
42+
try {
43+
method = IndyDemo.class.getMethod("someMethod", String.class);
44+
} catch (Exception e) {}
45+
REFLECTED = method;
46+
47+
MethodHandle handle = null;
48+
try {
49+
handle = MethodHandles.lookup().unreflect(REFLECTED);
50+
} catch (Exception e) {}
51+
HANDLE = handle;
52+
}
53+
54+
public static int length = 0;
55+
56+
public static void someMethod(String a) {
57+
length = a.length();
58+
}
59+
}

indy/src/test/java/com/github/mustachejava/BenchmarkTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.concurrent.Executors;
77

88
import com.github.mustachejava.indy.IndyObjectHandler;
9+
import com.github.mustachejava.mh.MHObjectHandler;
910
import junit.framework.TestCase;
1011

1112
/**
@@ -99,21 +100,26 @@ private Writer complextest(Mustache m, Object complexObject) throws MustacheExce
99100
}
100101

101102
private boolean indy = true;
102-
103103
public static void main(String[] args) throws Exception {
104104
BenchmarkTest benchmarkTest = new BenchmarkTest();
105105
benchmarkTest.setUp();
106+
107+
benchmarkTest.indy = true;
106108
System.out.println("Indy");
107109
benchmarkTest.testComplex();
110+
108111
benchmarkTest.indy = false;
109112
System.out.println("Reflection");
110113
benchmarkTest.testComplex();
114+
111115
benchmarkTest.indy = true;
112116
System.out.println("Indy");
113117
benchmarkTest.testComplex();
118+
114119
benchmarkTest.indy = false;
115120
System.out.println("Reflection");
116121
benchmarkTest.testComplex();
122+
117123
System.exit(0);
118124
}
119125
}

0 commit comments

Comments
 (0)