2021-06-11 14:02:28 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								From 0000000000000000000000000000000000000000 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 or static methods.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-06-11 19:23:18 -07:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								diff --git a/build.gradle.kts b/build.gradle.kts
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- a/build.gradle.kts
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/build.gradle.kts
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@ dependencies {
 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-13 21:11:12 -07:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								     apiAndDocs("net.kyori:adventure-text-serializer-legacy")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     apiAndDocs("net.kyori:adventure-text-serializer-plain")
							 
						 
					
						
							
								
									
										
										
										
											2022-06-12 17:07:40 -04:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								     apiAndDocs("net.kyori:adventure-text-logger-slf4j")
							 
						 
					
						
							
								
									
										
										
										
											2021-07-20 00:58:48 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-26 22:54:18 -08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								+    implementation("org.ow2.asm:asm:9.2")
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    implementation("org.ow2.asm:asm-commons:9.2")
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     // Paper end
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-08 00:49:02 -07:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								     compileOnly("org.apache.maven:maven-resolver-provider:3.8.5")
							 
						 
					
						
							
								
									
										
										
										
											2021-06-11 14:02:28 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								new file mode 100644
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- /dev/null
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+package com.destroystokyo.paper.event.executor;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.lang.invoke.MethodHandle;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.lang.invoke.MethodHandles;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.lang.reflect.Method;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import com.destroystokyo.paper.util.SneakyThrow;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.event.Event;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.event.EventException;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.event.Listener;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.plugin.EventExecutor;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.jetbrains.annotations.NotNull;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+public class MethodHandleEventExecutor implements EventExecutor {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    private final Class<? extends Event> eventClass;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    private final MethodHandle handle;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull MethodHandle handle) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        this.eventClass = eventClass;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        this.handle = handle;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public MethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull Method 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(@NotNull Listener listener, @NotNull Event event) throws EventException {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        if (!eventClass.isInstance(event)) return;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        try {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            handle.invoke(listener, event);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        } catch (Throwable t) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            SneakyThrow.sneaky(t);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+}
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- /dev/null
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+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.destroystokyo.paper.util.SneakyThrow;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import com.google.common.base.Preconditions;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.Bukkit;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.event.Event;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.event.EventException;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.event.Listener;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.plugin.EventExecutor;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.jetbrains.annotations.NotNull;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+public class StaticMethodHandleEventExecutor implements EventExecutor {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    private final Class<? extends Event> eventClass;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    private final MethodHandle handle;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public StaticMethodHandleEventExecutor(@NotNull Class<? extends Event> eventClass, @NotNull Method m) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        Preconditions.checkArgument(eventClass != null, "eventClass is null");
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        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(@NotNull Listener listener, @NotNull Event event) throws EventException {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        if (!eventClass.isInstance(event)) return;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        try {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            handle.invoke(event);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        } catch (Throwable throwable) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            SneakyThrow.sneaky(throwable);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+}
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- /dev/null
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+package com.destroystokyo.paper.event.executor.asm;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.lang.reflect.Method;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.util.concurrent.atomic.AtomicInteger;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.bukkit.plugin.EventExecutor;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.jetbrains.annotations.NotNull;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.objectweb.asm.ClassWriter;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.objectweb.asm.Type;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.objectweb.asm.commons.GeneratorAdapter;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import static org.objectweb.asm.Opcodes.*;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+public class ASMEventExecutorGenerator {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public static byte[] generateEventExecutor(@NotNull Method m, @NotNull String name) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[] {Type.getInternalName(EventExecutor.class)});
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        // Generate constructor
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null), ACC_PUBLIC, "<init>", "()V");
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.loadThis();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); // Invoke the super class (Object) constructor
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.returnValue();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.endMethod();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        // Generate the execute method
 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-20 20:54:57 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								+        methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V", null, null), ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Listener;)V");
 
							 
						 
					
						
							
								
									
										
										
										
											2021-06-11 14:02:28 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.loadArg(0);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.checkCast(Type.getType(m.getDeclaringClass()));
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.loadArg(1);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.checkCast(Type.getType(m.getParameterTypes()[0]));
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.visitMethodInsn(m.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, Type.getInternalName(m.getDeclaringClass()), m.getName(), Type.getMethodDescriptor(m), m.getDeclaringClass().isInterface());
 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-20 20:54:57 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								+        // The only purpose of this switch statement is to generate the correct pop instruction, should the event handler method return something other than void.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        // Non-void event handlers will be unsupported in a future release.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        switch (Type.getType(m.getReturnType()).getSize()) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            // case 0 is omitted because the only type that has size 0 is void - no pop instruction needed.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            case 1 -> methodGenerator.pop(); // handles reference types and most primitives
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            case 2 -> methodGenerator.pop2(); // handles long and double
 
							 
						 
					
						
							
								
									
										
										
										
											2021-06-11 14:02:28 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.returnValue();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        methodGenerator.endMethod();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        writer.visitEnd();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        return writer.toByteArray();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public static AtomicInteger NEXT_ID = new AtomicInteger(1);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public static String generateName() {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        int id = NEXT_ID.getAndIncrement();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        return "com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor" + id;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+}
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								new file mode 100644
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- /dev/null
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+package com.destroystokyo.paper.event.executor.asm;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.jetbrains.annotations.NotNull;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+public interface ClassDefiner {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    /**
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * Returns if the defined classes can bypass access checks
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     *
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * @return if classes bypass access checks
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     */
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public default boolean isBypassAccessChecks() {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        return false;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    /**
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * Define a class
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     *
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * @param parentLoader the parent classloader
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * @param name         the name of the class
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * @param data         the class data to load
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * @return the defined class
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * @throws ClassFormatError     if the class data is invalid
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     * @throws NullPointerException if any of the arguments are null
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+     */
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public static ClassDefiner getInstance() {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        return SafeClassDefiner.INSTANCE;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+}
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								new file mode 100644
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- /dev/null
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+package com.destroystokyo.paper.event.executor.asm;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.util.concurrent.ConcurrentHashMap;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.util.concurrent.ConcurrentMap;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import com.google.common.base.Preconditions;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import com.google.common.collect.MapMaker;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.jetbrains.annotations.NotNull;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import org.objectweb.asm.Type;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+public class SafeClassDefiner implements ClassDefiner {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    /* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    private SafeClassDefiner() {}
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    private final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new MapMaker().weakKeys().makeMap();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    @Override
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public Class<?> defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        GeneratedClassLoader loader = loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        synchronized (loader.getClassLoadingLock(name)) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            Preconditions.checkState(!loader.hasClass(name), "%s already defined", name);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            Class<?> c = loader.define(name, data);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            assert c.getName().equals(name);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            return c;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    private static class GeneratedClassLoader extends ClassLoader {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        static {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            ClassLoader.registerAsParallelCapable();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        protected GeneratedClassLoader(@NotNull ClassLoader parent) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            super(parent);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        private Class<?> define(@NotNull String name, byte[] data) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            synchronized (getClassLoadingLock(name)) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                assert !hasClass(name);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                Class<?> c = defineClass(name, data, 0, data.length);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                resolveClass(c);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                return c;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        @Override
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        public Object getClassLoadingLock(@NotNull String name) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            return super.getClassLoadingLock(name);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        public boolean hasClass(@NotNull String name) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            synchronized (getClassLoadingLock(name)) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                try {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                    Class.forName(name);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                    return true;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                } catch (ClassNotFoundException e) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                    return false;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+}
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- a/src/main/java/org/bukkit/plugin/EventExecutor.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/src/main/java/org/bukkit/plugin/EventExecutor.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@ import org.bukkit.event.EventException;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 import org.bukkit.event.Listener;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 import org.jetbrains.annotations.NotNull;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+// Paper start
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.lang.reflect.Method;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.lang.reflect.Modifier;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.util.concurrent.ConcurrentHashMap;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.util.concurrent.ConcurrentMap;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+import java.util.function.Function;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+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;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+// Paper end
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 /**
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * Interface which defines the class for event call backs to plugins
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  */
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 public interface EventExecutor {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								     public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    // Paper start
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    ConcurrentMap<Method, Class<? extends EventExecutor>> eventExecutorMap = new ConcurrentHashMap<Method, Class<? extends EventExecutor>>() {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        @Override
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        public Class<? extends EventExecutor> computeIfAbsent(@NotNull Method key, @NotNull Function<? super Method, ? extends Class<? extends EventExecutor>> mappingFunction) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            Class<? extends EventExecutor> executorClass = get(key);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            if (executorClass != null)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                return executorClass;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            //noinspection SynchronizationOnLocalVariableOrMethodParameter
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            synchronized (key) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                executorClass = get(key);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                if (executorClass != null)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                    return executorClass;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                return super.computeIfAbsent(key, mappingFunction);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    };
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    @NotNull
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    public static EventExecutor create(@NotNull Method m, @NotNull Class<? extends Event> eventClass) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        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);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        ClassDefiner definer = ClassDefiner.getInstance();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        if (Modifier.isStatic(m.getModifiers())) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            return new StaticMethodHandleEventExecutor(eventClass, m);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        } else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            // get the existing generated EventExecutor class for the Method or generate one
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            Class<? extends EventExecutor> executorClass = eventExecutorMap.computeIfAbsent(m, (__) -> {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                String name = ASMEventExecutorGenerator.generateName();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                return definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            });
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            try {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                EventExecutor asmExecutor = executorClass.newInstance();
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                return (listener, event) -> {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                    if (!eventClass.isInstance(event)) return;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                    asmExecutor.execute(listener, event);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                };
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            } catch (InstantiationException | IllegalAccessException e) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+                throw new AssertionError("Unable to initialize generated event executor", e);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        } else {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            return new MethodHandleEventExecutor(eventClass, m);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+    // Paper end
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 }
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								@@ -0,0 +0,0 @@ public final class JavaPluginLoader implements PluginLoader {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                 }
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								             }
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-            EventExecutor executor = new co.aikar.timings.TimedEventExecutor(new EventExecutor() { // Paper
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                @Override
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { // Paper
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                    try {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                        if (!eventClass.isAssignableFrom(event.getClass())) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                            return;
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                        }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                        method.invoke(listener, event);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                    } catch (InvocationTargetException ex) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                        throw new EventException(ex.getCause());
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                    } catch (Throwable t) {
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                        throw new EventException(t);
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                    }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-                }
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								-            }, plugin, method, eventClass); // Paper
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								+            EventExecutor executor = new co.aikar.timings.TimedEventExecutor(EventExecutor.create(method, eventClass), plugin, method, eventClass); // Paper // Paper (Yes.) - Use factory method `EventExecutor.create()`
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								             if (false) { // Spigot - RL handles useTimings check now
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                 eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								             } else {