From e9df64e1d69c2a65b0e9587dc94fbafefb31aba1 Mon Sep 17 00:00:00 2001 From: cattyn Date: Sat, 15 Nov 2025 01:57:37 +0300 Subject: [PATCH] perf(EventBus): replace reflection call with invokedynamic --- .../alpha432/oyvey/event/system/EventBus.java | 31 ++++++---------- .../alpha432/oyvey/event/system/Listener.java | 37 +++++++++++++++++++ 2 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 src/main/java/me/alpha432/oyvey/event/system/Listener.java diff --git a/src/main/java/me/alpha432/oyvey/event/system/EventBus.java b/src/main/java/me/alpha432/oyvey/event/system/EventBus.java index bf9f1bd..50b7b99 100644 --- a/src/main/java/me/alpha432/oyvey/event/system/EventBus.java +++ b/src/main/java/me/alpha432/oyvey/event/system/EventBus.java @@ -9,44 +9,35 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; public class EventBus { - private final Map, CopyOnWriteArrayList> listeners = - new ConcurrentHashMap<>(); + private final Map, CopyOnWriteArrayList> 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 list : listeners.values()) { - list.removeIf(lm -> lm.owner.equals(listener)); + public void unregister(Object host) { + for (CopyOnWriteArrayList list : listeners.values()) { + list.removeIf(listener -> listener.getHost().equals(host)); } } public void post(Event event) { - List list = listeners.get(event.getClass()); + List 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) {} } \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/event/system/Listener.java b/src/main/java/me/alpha432/oyvey/event/system/Listener.java new file mode 100644 index 0000000..d655b07 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/system/Listener.java @@ -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 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 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) (target.invoke(host)); + } catch (Throwable e) { + throw new RuntimeException("Failed to build lambda from %s method".formatted(method.getName()), e); + } + } +}