Handle static methods

This commit is contained in:
Techcable 2016-03-12 09:43:39 -07:00
parent eb7993789f
commit 752452373d
2 changed files with 58 additions and 11 deletions

View file

@ -1,9 +1,9 @@
From 7e35c9c03a1fe023e8da7de1718f60e00298c6b5 Mon Sep 17 00:00:00 2001
From c1dc52ffb0997b633a552eb4fc6341de01a50e40 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Thu, 3 Mar 2016 13:20:33 -0700
Subject: [PATCH] Use ASM for event executors.
Uses method handles for private methods.
Uses method handles for private or static methods.
diff --git a/pom.xml b/pom.xml
index 0b615b4..1ad108e 100644
@ -68,6 +68,51 @@ index 0000000..9ff99e3
+ }
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
new file mode 100644
index 0000000..f60f010
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
@@ -0,0 +1,39 @@
+package com.destroystokyo.paper.event.executor;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import com.google.common.base.Preconditions;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.EventException;
+import org.bukkit.event.Listener;
+import org.bukkit.plugin.EventExecutor;
+
+public class StaticMethodHandleEventExecutor implements EventExecutor {
+ private final Class<? extends Event> eventClass;
+ private final MethodHandle handle;
+
+ public StaticMethodHandleEventExecutor(Class<? extends Event> eventClass, Method m) {
+ Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m);
+ this.eventClass = eventClass;
+ try {
+ m.setAccessible(true);
+ this.handle = MethodHandles.lookup().unreflect(m);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Unable to set accessible", e);
+ }
+ }
+
+ @Override
+ public void execute(Listener listener, Event event) throws EventException {
+ if (!eventClass.isInstance(event)) return;
+ try {
+ handle.invoke(event);
+ } catch (Throwable t) {
+ throw new EventException(t);
+ }
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java
new file mode 100644
index 0000000..45c2330
@ -264,10 +309,10 @@ index 0000000..62acbf8
+ }
+}
diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java
index 3b2c99e..7b92ce0 100644
index 3b2c99e..f9316d6 100644
--- a/src/main/java/org/bukkit/plugin/EventExecutor.java
+++ b/src/main/java/org/bukkit/plugin/EventExecutor.java
@@ -4,9 +4,53 @@ import org.bukkit.event.Event;
@@ -4,9 +4,55 @@ import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
@ -276,6 +321,7 @@ index 3b2c99e..7b92ce0 100644
+import java.lang.reflect.Modifier;
+
+import com.destroystokyo.paper.event.executor.MethodHandleEventExecutor;
+import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor;
+import com.destroystokyo.paper.event.executor.asm.ASMEventExecutorGenerator;
+import com.destroystokyo.paper.event.executor.asm.ClassDefiner;
+import com.google.common.base.Preconditions;
@ -292,9 +338,10 @@ index 3b2c99e..7b92ce0 100644
+ Preconditions.checkNotNull(m, "Null method");
+ Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount());
+ Preconditions.checkArgument(m.getParameterTypes()[0] == eventClass, "First parameter %s doesn't match event class %s", m.getParameterTypes()[0], eventClass);
+ Preconditions.checkArgument(!Modifier.isStatic(m.getModifiers()), "Static method %s", m.getName());
+ ClassDefiner definer = ClassDefiner.getInstance();
+ if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) {
+ if (Modifier.isStatic(m.getModifiers())) {
+ return new StaticMethodHandleEventExecutor(eventClass, m);
+ } if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) {
+ String name = ASMEventExecutorGenerator.generateName();
+ byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name);
+ Class<? extends EventExecutor> c = definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class);