Skip to content

Commit

Permalink
performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
msbarry committed Dec 3, 2023
1 parent 313a328 commit 74643b0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ static JavaClass forClass(Class<?> c) {

JavaClass(Class<?> c) {
super(c);
this.jclass = this;
this.bindMethods = c.isAnnotationPresent(LuaBindMethods.class);
// planetiler change: compute these maps eagerly
computeFields();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@
*/
class JavaInstance extends LuaUserdata {

volatile JavaClass jclass;
private final JavaClass jclass;
private final Map<LuaValue, LuaValue> boundMethods;

JavaInstance(Object instance) {
super(instance);
// planetiler change: when class annotated with @LuaBindMethods, allow methods to be called with instance.method()
if (m_instance.getClass().isAnnotationPresent(LuaBindMethods.class)) {
boundMethods = jclass().getMethods().entrySet().stream().collect(Collectors.toMap(
var clazz = m_instance.getClass();
jclass = this instanceof JavaClass c ? c : JavaClass.forClass(clazz);
if (clazz.isAnnotationPresent(LuaBindMethods.class)) {
boundMethods = jclass.getMethods().entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
entry -> new BoundMethod(entry.getValue())
));
Expand Down Expand Up @@ -111,44 +113,32 @@ public Varargs invoke(Varargs args) {
}
}

private JavaClass jclass() {
if (jclass == null) {
synchronized (this) {
if (jclass == null) {
jclass = JavaClass.forClass(m_instance.getClass());
}
}
}
return jclass;
}

public LuaValue get(LuaValue key) {
// planetiler change: allow lists to be accessed as tables
if (m_instance instanceof List<?> c) {
int idx = key.toint();
return idx <= 0 || idx > c.size() ? LuaValue.NIL : CoerceJavaToLua.coerce(c.get(idx - 1));
}
JavaClass clazz = jclass();
Field f = clazz.getField(key);
Field f = jclass.getField(key);
if (f != null)
try {
return CoerceJavaToLua.coerce(f.get(m_instance));
} catch (Exception e) {
throw new LuaError(e);
}
// planetiler change: allow getter methods
var getter = clazz.getGetter(key);
var getter = jclass.getGetter(key);
if (getter != null) {
try {
return CoerceJavaToLua.coerce(getter.get(m_instance));
} catch (Exception e) {
throw new LuaError(e);
}
}
LuaValue m = boundMethods != null ? boundMethods.get(key) : clazz.getMethod(key);
LuaValue m = boundMethods != null ? boundMethods.get(key) : jclass.getMethod(key);
if (m != null)
return m;
Class<?> c = clazz.getInnerClass(key);
Class<?> c = jclass.getInnerClass(key);
if (c != null)
return JavaClass.forClass(c);

Expand All @@ -171,8 +161,7 @@ public void set(LuaValue key, LuaValue value) {
c.set(key.toint() - 1, CoerceLuaToJava.coerce(value, Object.class));
return;
}
JavaClass clazz = jclass();
Field f = clazz.getField(key);
Field f = jclass.getField(key);
if (f != null)
try {
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
Expand All @@ -181,7 +170,7 @@ public void set(LuaValue key, LuaValue value) {
throw new LuaError(e);
}
// planetiler change: allow setter methods
var setter = clazz.getSetter(key);
var setter = jclass.getSetter(key);
if (setter != null) {
try {
setter.set(m_instance, CoerceLuaToJava.coerce(value, setter.type()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.luaj.vm2.LuaError;
Expand Down Expand Up @@ -148,10 +150,25 @@ LuaValue invokeMethod(Object instance, Varargs args) {
*/
static class Overload extends LuaFunction {

final JavaMethod[] methods;
private final JavaMethod[][] methodsByArgCount;

Overload(JavaMethod[] methods) {
this.methods = methods;
int max = 0;
// planetiler change: precompute which methods are valid based on number of args
for (JavaMethod method : methods) {
max = Math.max(max, method.fixedargs.length + (method.varargs != null ? 2 : 0));
}
this.methodsByArgCount = new JavaMethod[max + 1][];
for (int nargs = 0; nargs <= max; nargs++) {
List<JavaMethod> methodsForCount = new ArrayList<>();
for (JavaMethod javaMethod : methods) {
int fixed = javaMethod.fixedargs.length;
if (nargs == fixed || nargs > fixed && javaMethod.varargs != null) {
methodsForCount.add(javaMethod);
}
}
methodsByArgCount[nargs] = methodsForCount.isEmpty() ? methods : methodsForCount.toArray(JavaMethod[]::new);
}
}

public LuaValue call() {
Expand All @@ -176,14 +193,22 @@ public Varargs invoke(Varargs args) {

private LuaValue invokeBestMethod(Object instance, Varargs args) {
JavaMethod best = null;
int score = Integer.MAX_VALUE;
for (int i = 0; i < methods.length; i++) {
int s = methods[i].score(args);
if (s < score) {
score = s;
best = methods[i];
if (score == 0)
break;

// first pass: filter possible methods by number of args provided
JavaMethod[] methods = methodsByArgCount[Math.min(methodsByArgCount.length - 1, args.narg())];
if (methods.length == 1) {
best = methods[0];
} else if (methods.length != 0) {
int score = Integer.MAX_VALUE;
// if there are multiple, then pick the one with the best score
for (JavaMethod javaMethod : methods) {
int s = javaMethod.score(args);
if (s < score) {
score = s;
best = javaMethod;
if (score == 0)
break;
}
}
}

Expand Down

0 comments on commit 74643b0

Please sign in to comment.