perf(EventBus): replace reflection call with invokedynamic

This commit is contained in:
cattyn
2025-11-15 01:57:37 +03:00
parent 39fc291f44
commit e9df64e1d6
2 changed files with 48 additions and 20 deletions
@@ -9,44 +9,35 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
public class EventBus {
private final Map<Class<?>, CopyOnWriteArrayList<ListenerMethod>> listeners =
new ConcurrentHashMap<>();
private final Map<Class<?>, CopyOnWriteArrayList<Listener>> listeners = new ConcurrentHashMap<>();
public void register(Object listener) {
for (Method method : listener.getClass().getDeclaredMethods()) {
public void register(Object host) {
for (Method method : host.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(Subscribe.class)) {
Class<?>[] params = method.getParameterTypes();
if (params.length == 1) {
Class<?> eventType = params[0];
listeners
.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>())
.add(new ListenerMethod(listener, method));
listeners.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>())
.add(Listener.of(host, method));
}
}
}
}
public void unregister(Object listener) {
for (CopyOnWriteArrayList<ListenerMethod> list : listeners.values()) {
list.removeIf(lm -> lm.owner.equals(listener));
public void unregister(Object host) {
for (CopyOnWriteArrayList<Listener> list : listeners.values()) {
list.removeIf(listener -> listener.getHost().equals(host));
}
}
public void post(Event event) {
List<ListenerMethod> list = listeners.get(event.getClass());
List<Listener> list = listeners.get(event.getClass());
if (list == null) return;
for (ListenerMethod lm : list) {
for (Listener listener : list) {
if (event.isCancelled()) return;
try {
lm.method.setAccessible(true);
lm.method.invoke(lm.owner, event);
} catch (Exception e) {
e.printStackTrace();
}
listener.invoke(event);
}
}
private record ListenerMethod(Object owner, Method method) {}
}
@@ -0,0 +1,37 @@
package me.alpha432.oyvey.event.system;
import java.lang.invoke.*;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public record Listener(Object host, Consumer<Object> consumer) {
public static Listener of(Object host, Method method) {
return new Listener(host, buildLambdaMetafactory(host, method));
}
public void invoke(Object event) {
consumer.accept(event);
}
public Object getHost() {
return host;
}
private static Consumer<Object> buildLambdaMetafactory(Object host, Method method) {
try {
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(host.getClass(), MethodHandles.lookup());
CallSite site = LambdaMetafactory.metafactory(
lookup,
"accept",
MethodType.methodType(Consumer.class, host.getClass()),
MethodType.methodType(void.class, Object.class),
lookup.unreflect(method),
MethodType.methodType(void.class, method.getParameterTypes()[0])
);
MethodHandle target = site.getTarget();
return (Consumer<Object>) (target.invoke(host));
} catch (Throwable e) {
throw new RuntimeException("Failed to build lambda from %s method".formatted(method.getName()), e);
}
}
}