Cache generated EventExecutors (fixes #786)

the first 'major' change in this PR is to cache the generated event
executrs from the ASM class, by doing this we only generate a single
class for every method that we need an executor for, thus reducing the
number of classes that are needed, especially in cases where plugins
re/unregister events all the time.

The second change is to modify the generated classloader map, generated
classloaders are not held against the plugin itself but the classloader
that the event is declared in, the implication here is that we cannot
drop generated classloaders when a plugin disable, and so we use a guava
weak-key'd hashmap, downfall here is that classes won't be GC'd until
guava drops the generated classloader, however the first change should
deal with most of the grunt.
This commit is contained in:
Shane Freeder 2017-09-06 21:18:36 +01:00
parent 6d9375d222
commit 9c79dd3214
No known key found for this signature in database
GPG Key ID: A3F61EA5A085289C
11 changed files with 58 additions and 31 deletions

View File

@ -1,4 +1,4 @@
From 780e7e1c25c5f7857d4ce5b834f07f4aef6f6814 Mon Sep 17 00:00:00 2001 From d6c062cb8c337535554a3fcb0008ede65a33c86b Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com> From: Techcable <Techcable@outlook.com>
Date: Thu, 3 Mar 2016 13:20:33 -0700 Date: Thu, 3 Mar 2016 13:20:33 -0700
Subject: [PATCH] Use ASM for event executors. Subject: [PATCH] Use ASM for event executors.
@ -203,10 +203,10 @@ index 00000000..6941d9fb
+} +}
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 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 new file mode 100644
index 00000000..776a9a03 index 00000000..1473ff8c
--- /dev/null --- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java +++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java
@@ -0,0 +1,62 @@ @@ -0,0 +1,63 @@
+package com.destroystokyo.paper.event.executor.asm; +package com.destroystokyo.paper.event.executor.asm;
+ +
+import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentHashMap;
@ -214,6 +214,7 @@ index 00000000..776a9a03
+ +
+import com.google.common.base.Preconditions; +import com.google.common.base.Preconditions;
+ +
+import com.google.common.collect.MapMaker;
+import org.objectweb.asm.Type; +import org.objectweb.asm.Type;
+ +
+public class SafeClassDefiner implements ClassDefiner { +public class SafeClassDefiner implements ClassDefiner {
@ -221,7 +222,7 @@ index 00000000..776a9a03
+ +
+ private SafeClassDefiner() {} + private SafeClassDefiner() {}
+ +
+ private final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new ConcurrentHashMap<>(); + private final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new MapMaker().weakKeys().makeMap();
+ +
+ @Override + @Override
+ public Class<?> defineClass(ClassLoader parentLoader, String name, byte[] data) { + public Class<?> defineClass(ClassLoader parentLoader, String name, byte[] data) {
@ -309,16 +310,20 @@ index 00000000..62acbf82
+ } + }
+} +}
diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java
index 3b2c99ea..f9316d65 100644 index 3b2c99ea..b45b6c1c 100644
--- a/src/main/java/org/bukkit/plugin/EventExecutor.java --- a/src/main/java/org/bukkit/plugin/EventExecutor.java
+++ b/src/main/java/org/bukkit/plugin/EventExecutor.java +++ b/src/main/java/org/bukkit/plugin/EventExecutor.java
@@ -4,9 +4,55 @@ import org.bukkit.event.Event; @@ -4,9 +4,81 @@ import org.bukkit.event.Event;
import org.bukkit.event.EventException; import org.bukkit.event.EventException;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
+// Paper start +// Paper start
+import java.lang.reflect.Method; +import java.lang.reflect.Method;
+import java.lang.reflect.Modifier; +import java.lang.reflect.Modifier;
+import java.util.HashMap;
+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.MethodHandleEventExecutor;
+import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor; +import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor;
@ -334,6 +339,24 @@ index 3b2c99ea..f9316d65 100644
public void execute(Listener listener, Event event) throws EventException; public void execute(Listener listener, Event event) throws EventException;
+ +
+ // Paper start + // Paper start
+ ConcurrentMap<Method, Class<? extends EventExecutor>> eventExecutorMap = new ConcurrentHashMap<Method, Class<? extends EventExecutor>>() {
+ @Override
+ public Class<? extends EventExecutor> computeIfAbsent(Method key, 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);
+ }
+ }
+ };
+
+ public static EventExecutor create(Method m, Class<? extends Event> eventClass) { + public static EventExecutor create(Method m, Class<? extends Event> eventClass) {
+ Preconditions.checkNotNull(m, "Null method"); + Preconditions.checkNotNull(m, "Null method");
+ Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount()); + Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount());
@ -341,12 +364,16 @@ index 3b2c99ea..f9316d65 100644
+ ClassDefiner definer = ClassDefiner.getInstance(); + ClassDefiner definer = ClassDefiner.getInstance();
+ if (Modifier.isStatic(m.getModifiers())) { + if (Modifier.isStatic(m.getModifiers())) {
+ return new StaticMethodHandleEventExecutor(eventClass, m); + return new StaticMethodHandleEventExecutor(eventClass, m);
+ } if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) { + } else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) {
+ String name = ASMEventExecutorGenerator.generateName(); + // get the existing generated EventExecutor class for the Method or generate one
+ byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name); + Class<? extends EventExecutor> executorClass = eventExecutorMap.computeIfAbsent(m, (__) -> {
+ Class<? extends EventExecutor> c = definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class); + String name = ASMEventExecutorGenerator.generateName();
+ byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name);
+ return definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class);
+ });
+
+ try { + try {
+ EventExecutor asmExecutor = c.newInstance(); + EventExecutor asmExecutor = executorClass.newInstance();
+ // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception) + // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception)
+ return new EventExecutor() { + return new EventExecutor() {
+ @Override + @Override
@ -395,5 +422,5 @@ index d8b9c244..40fd71dc 100644
eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
} else { } else {
-- --
2.13.0 2.14.1

View File

@ -1,4 +1,4 @@
From 749b81ac44634b7b41a61d72bf05086b872c39c6 Mon Sep 17 00:00:00 2001 From 3a5f33ba756ff0587b88c7b6340ff6368131f51e Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Sat, 17 Jun 2017 15:04:51 -0400 Date: Sat, 17 Jun 2017 15:04:51 -0400
Subject: [PATCH] Shoulder Entities Release API Subject: [PATCH] Shoulder Entities Release API
@ -34,5 +34,5 @@ index 518aa2a9..3939d4af 100644
* Gets the entity currently perched on the left shoulder or null if no * Gets the entity currently perched on the left shoulder or null if no
* entity. * entity.
-- --
2.13.3 2.14.1

View File

@ -1,4 +1,4 @@
From bf4c10675dba6aa49c9d4db585c9d70b1da00637 Mon Sep 17 00:00:00 2001 From bcbcc7dd8033e55027d77c7eaeaea3b6288b643e Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Sat, 17 Jun 2017 16:30:44 -0400 Date: Sat, 17 Jun 2017 16:30:44 -0400
Subject: [PATCH] Profile Lookup Events Subject: [PATCH] Profile Lookup Events

View File

@ -1,4 +1,4 @@
From 65b1c1ecda7de3d1b4fa683bc9942ec93db9d31f Mon Sep 17 00:00:00 2001 From e7f452ae1e545a3dfa9adf5c634a3f17a8c0b791 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com> From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Sun, 18 Jun 2017 18:17:05 -0500 Date: Sun, 18 Jun 2017 18:17:05 -0500
Subject: [PATCH] Entity#fromMobSpawner() Subject: [PATCH] Entity#fromMobSpawner()
@ -22,5 +22,5 @@ index c86c1c5f..57f62ae4 100644
// Paper end // Paper end
} }
-- --
2.13.3 2.14.1

View File

@ -1,4 +1,4 @@
From 8aa765ebb7b4bb1ba7b65a662bff871d50f90422 Mon Sep 17 00:00:00 2001 From 19295da8c04248bdc579640f5931b9818f1a61a2 Mon Sep 17 00:00:00 2001
From: willies952002 <admin@domnian.com> From: willies952002 <admin@domnian.com>
Date: Thu, 20 Jul 2017 18:05:36 -0400 Date: Thu, 20 Jul 2017 18:05:36 -0400
Subject: [PATCH] Allow Changing of Player Sample in ServerListPingEvent Subject: [PATCH] Allow Changing of Player Sample in ServerListPingEvent
@ -33,5 +33,5 @@ index 3c38d857..84de3ce4 100644
+ +
} }
-- --
2.13.3 2.14.1

View File

@ -1,4 +1,4 @@
From 50ad728a3cfb0af96a191960a256d0288ffb22bf Mon Sep 17 00:00:00 2001 From a3b4ea5396b88e411599100f60091cbfe68dc242 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Sat, 10 Dec 2016 16:12:48 -0500 Date: Sat, 10 Dec 2016 16:12:48 -0500
Subject: [PATCH] Improve the Saddle API for Horses Subject: [PATCH] Improve the Saddle API for Horses
@ -94,5 +94,5 @@ index 00000000..010dc364
+ void setSaddle(ItemStack stack); + void setSaddle(ItemStack stack);
+} +}
-- --
2.13.3 2.14.1

View File

@ -1,4 +1,4 @@
From d97890f63015395b9fcf7bc382686ddfe5f3e266 Mon Sep 17 00:00:00 2001 From c6ffdd4bda7232c5e22d96bc0c5e6f6a9c995401 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Wed, 4 May 2016 23:55:48 -0400 Date: Wed, 4 May 2016 23:55:48 -0400
Subject: [PATCH] ensureServerConversions API Subject: [PATCH] ensureServerConversions API
@ -61,5 +61,5 @@ index 188ae6d7..6bb19b9d 100644
+ // Paper end + // Paper end
} }
-- --
2.13.3 2.14.1

View File

@ -1,4 +1,4 @@
From 7c28e3c2d2ebf454068b75f615be4feb5ebaeede Mon Sep 17 00:00:00 2001 From f2f0642e3bce08e006218abf9e98fb735a641963 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Wed, 4 May 2016 23:55:48 -0400 Date: Wed, 4 May 2016 23:55:48 -0400
Subject: [PATCH] Add getI18NDisplayName API Subject: [PATCH] Add getI18NDisplayName API
@ -49,5 +49,5 @@ index 6bb19b9d..7a52da9b 100644
// Paper end // Paper end
} }
-- --
2.13.3 2.14.1

View File

@ -1,4 +1,4 @@
From c814474d6c5d9c4d7142d141e6dabf3935a577cb Mon Sep 17 00:00:00 2001 From 225e4e635f54b9f4ba440a4a849a4bddde5c6309 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Mon, 3 Jul 2017 18:11:34 -0500 Date: Mon, 3 Jul 2017 18:11:34 -0500
Subject: [PATCH] ProfileWhitelistVerifyEvent Subject: [PATCH] ProfileWhitelistVerifyEvent
@ -124,5 +124,5 @@ index 00000000..59b69b23
+ } + }
+} +}
-- --
2.13.3 2.14.1

View File

@ -1,4 +1,4 @@
From fcaf4875363c340138dd0f7111ece67e1982e078 Mon Sep 17 00:00:00 2001 From 662bd9bbf378ed4d06831c1e4de040ea3282ce3e Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com> From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Mon, 31 Jul 2017 02:08:55 -0500 Date: Mon, 31 Jul 2017 02:08:55 -0500
Subject: [PATCH] Make /plugins list alphabetical Subject: [PATCH] Make /plugins list alphabetical
@ -51,5 +51,5 @@ index e21d1679..e2274fa2 100644
// Spigot Start // Spigot Start
-- --
2.11.0 2.14.1

View File

@ -1,4 +1,4 @@
From b97b934d735fcb6dceca929737d660db73602ccd Mon Sep 17 00:00:00 2001 From 9eeca99eb63a2892a12da3c26bcee01f402c337e Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com> From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Mon, 31 Jul 2017 01:49:43 -0500 Date: Mon, 31 Jul 2017 01:49:43 -0500
Subject: [PATCH] LivingEntity#setKiller Subject: [PATCH] LivingEntity#setKiller
@ -34,5 +34,5 @@ index be51e389..4a51c519 100644
* Adds the given {@link PotionEffect} to the living entity. * Adds the given {@link PotionEffect} to the living entity.
* <p> * <p>
-- --
2.14.1.windows.1 2.14.1