Commit 1b43bca7a655ca2cecd144e6eab6b9472e9e6a52
1 parent
7a912de0
spawn anonymous inner classes for EventProxy to handle events injected after ini…
…tial proxy generation
Showing
3 changed files
with
82 additions
and
38 deletions
java/common/com/mumfrey/liteloader/core/event/EventProxy.java
@@ -56,8 +56,7 @@ public final class EventProxy | @@ -56,8 +56,7 @@ public final class EventProxy | ||
56 | // } | 56 | // } |
57 | // } | 57 | // } |
58 | 58 | ||
59 | - @SuppressWarnings("unused") | ||
60 | - private static void onMissingClass(Error err, EventInfo<?> e) | 59 | + protected static void onMissingClass(Error err, EventInfo<?> e) |
61 | { | 60 | { |
62 | EventProxy.error = "Missing Event Handler Class!"; | 61 | EventProxy.error = "Missing Event Handler Class!"; |
63 | EventProxy.errorDetails = new StringBuilder(); | 62 | EventProxy.errorDetails = new StringBuilder(); |
@@ -83,8 +82,7 @@ public final class EventProxy | @@ -83,8 +82,7 @@ public final class EventProxy | ||
83 | throw new RuntimeErrorException(err, "Missing event handler class for event " + e.getName() + ", see crash report for details"); | 82 | throw new RuntimeErrorException(err, "Missing event handler class for event " + e.getName() + ", see crash report for details"); |
84 | } | 83 | } |
85 | 84 | ||
86 | - @SuppressWarnings("unused") | ||
87 | - private static void onMissingHandler(Error err, EventInfo<?> e) | 85 | + protected static void onMissingHandler(Error err, EventInfo<?> e) |
88 | { | 86 | { |
89 | String descriptor = err.getMessage(); | 87 | String descriptor = err.getMessage(); |
90 | int dotPos = descriptor.lastIndexOf('.'); | 88 | int dotPos = descriptor.lastIndexOf('.'); |
java/common/com/mumfrey/liteloader/transformers/event/Event.java
@@ -36,9 +36,9 @@ public class Event implements Comparable<Event> | @@ -36,9 +36,9 @@ public class Event implements Comparable<Event> | ||
36 | */ | 36 | */ |
37 | private static final Set<Event> events = new HashSet<Event>(); | 37 | private static final Set<Event> events = new HashSet<Event>(); |
38 | 38 | ||
39 | - private static final Map<MethodNode, List<Event>> handlerMethods = new LinkedHashMap<MethodNode, List<Event>>(); | 39 | + private static final List<Map<MethodNode, List<Event>>> proxyHandlerMethods = new ArrayList<Map<MethodNode, List<Event>>>(); |
40 | 40 | ||
41 | - private static boolean generatedProxy = false; | 41 | + private static int proxyInnerClassIndex = 1; |
42 | 42 | ||
43 | /** | 43 | /** |
44 | * The name of this event | 44 | * The name of this event |
@@ -239,11 +239,6 @@ public class Event implements Comparable<Event> | @@ -239,11 +239,6 @@ public class Event implements Comparable<Event> | ||
239 | { | 239 | { |
240 | throw new IllegalStateException("Attempted to inject the event " + this.name + " but the event is not attached!"); | 240 | throw new IllegalStateException("Attempted to inject the event " + this.name + " but the event is not attached!"); |
241 | } | 241 | } |
242 | - | ||
243 | - if (Event.generatedProxy) | ||
244 | - { | ||
245 | - throw new IllegalStateException("Attempted to inject the event " + this.name + " but the event proxy was already generated!"); | ||
246 | - } | ||
247 | } | 242 | } |
248 | 243 | ||
249 | /** | 244 | /** |
@@ -264,9 +259,9 @@ public class Event implements Comparable<Event> | @@ -264,9 +259,9 @@ public class Event implements Comparable<Event> | ||
264 | 259 | ||
265 | // Create the handler delegate method | 260 | // Create the handler delegate method |
266 | MethodNode handler = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, Event.getHandlerName(globalEventID), this.eventDescriptor, null, null); | 261 | MethodNode handler = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, Event.getHandlerName(globalEventID), this.eventDescriptor, null, null); |
267 | - Event.handlerMethods.put(handler, new ArrayList<Event>()); | 262 | + Event.addMethodToActiveProxy(handler); |
268 | 263 | ||
269 | - LiteLoaderLogger.debug("Event %s is spawning handler %s", this.name, handler.name); | 264 | + LiteLoaderLogger.debug("Event %s is spawning handler %s in class %s", this.name, handler.name, Event.getActiveProxyRef()); |
270 | 265 | ||
271 | Type[] argumentTypes = Type.getArgumentTypes(this.method.desc); | 266 | Type[] argumentTypes = Type.getArgumentTypes(this.method.desc); |
272 | int ctorMAXS = 0, invokeMAXS = argumentTypes.length; | 267 | int ctorMAXS = 0, invokeMAXS = argumentTypes.length; |
@@ -286,7 +281,7 @@ public class Event implements Comparable<Event> | @@ -286,7 +281,7 @@ public class Event implements Comparable<Event> | ||
286 | // Call the event handler method in the proxy | 281 | // Call the event handler method in the proxy |
287 | insns.add(new VarInsnNode(Opcodes.ALOAD, eventInfoVar)); | 282 | insns.add(new VarInsnNode(Opcodes.ALOAD, eventInfoVar)); |
288 | Event.pushArgs(argumentTypes, insns, this.methodIsStatic); | 283 | Event.pushArgs(argumentTypes, insns, this.methodIsStatic); |
289 | - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.EventProxy.ref, handler.name, handler.desc, false)); | 284 | + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Event.getActiveProxyRef(), handler.name, handler.desc, false)); |
290 | 285 | ||
291 | if (cancellable) | 286 | if (cancellable) |
292 | { | 287 | { |
@@ -300,7 +295,7 @@ public class Event implements Comparable<Event> | @@ -300,7 +295,7 @@ public class Event implements Comparable<Event> | ||
300 | 295 | ||
301 | return handler; | 296 | return handler; |
302 | } | 297 | } |
303 | - | 298 | + |
304 | /** | 299 | /** |
305 | * if (e.isCancelled()) return e.getReturnValue(); | 300 | * if (e.isCancelled()) return e.getReturnValue(); |
306 | * | 301 | * |
@@ -360,11 +355,7 @@ public class Event implements Comparable<Event> | @@ -360,11 +355,7 @@ public class Event implements Comparable<Event> | ||
360 | { | 355 | { |
361 | LiteLoaderLogger.debug("Adding event %s to handler %s", this.name, handler.name); | 356 | LiteLoaderLogger.debug("Adding event %s to handler %s", this.name, handler.name); |
362 | 357 | ||
363 | - List<Event> handlerEvents = Event.handlerMethods.get(handler); | ||
364 | - if (handlerEvents != null) | ||
365 | - { | ||
366 | - handlerEvents.add(this); | ||
367 | - } | 358 | + Event.getEventsForHandlerMethod(handler).add(this); |
368 | } | 359 | } |
369 | 360 | ||
370 | /** | 361 | /** |
@@ -426,18 +417,22 @@ public class Event implements Comparable<Event> | @@ -426,18 +417,22 @@ public class Event implements Comparable<Event> | ||
426 | * Populates the event proxy class with delegating methods for all injected events | 417 | * Populates the event proxy class with delegating methods for all injected events |
427 | * | 418 | * |
428 | * @param classNode | 419 | * @param classNode |
420 | + * @param proxyIndex TODO | ||
429 | * @return | 421 | * @return |
430 | */ | 422 | */ |
431 | - static ClassNode populateProxy(final ClassNode classNode) | 423 | + static ClassNode populateProxy(final ClassNode classNode, int proxyIndex) |
432 | { | 424 | { |
433 | - Event.generatedProxy = true; | ||
434 | - | ||
435 | int handlerCount = 0; | 425 | int handlerCount = 0; |
436 | int invokeCount = 0; | 426 | int invokeCount = 0; |
437 | - int lineNumber = 210; // From EventProxy.java, this really is only to try and make stack traces a bit easier to read | 427 | + int lineNumber = proxyIndex < 2 ? 210 : 10; // From EventProxy.java, this really is only to try and make stack traces a bit easier to read |
428 | + | ||
429 | + LiteLoaderLogger.info("Generating new Event Handler Proxy Class %s", classNode.name.replace('/', '.')); | ||
430 | + | ||
431 | + Map<MethodNode, List<Event>> handlerMethods = Event.proxyHandlerMethods.get(Event.proxyInnerClassIndex); | ||
432 | + Event.proxyInnerClassIndex++; | ||
438 | 433 | ||
439 | // Loop through all handlers and inject a method for each one | 434 | // Loop through all handlers and inject a method for each one |
440 | - for (Entry<MethodNode, List<Event>> handler : Event.handlerMethods.entrySet()) | 435 | + for (Entry<MethodNode, List<Event>> handler : handlerMethods.entrySet()) |
441 | { | 436 | { |
442 | MethodNode handlerMethod = handler.getKey(); | 437 | MethodNode handlerMethod = handler.getKey(); |
443 | List<Event> handlerEvents = handler.getValue(); | 438 | List<Event> handlerEvents = handler.getValue(); |
@@ -503,11 +498,37 @@ public class Event implements Comparable<Event> | @@ -503,11 +498,37 @@ public class Event implements Comparable<Event> | ||
503 | return classNode; | 498 | return classNode; |
504 | } | 499 | } |
505 | 500 | ||
501 | + private static List<Event> addMethodToActiveProxy(MethodNode handlerMethod) | ||
502 | + { | ||
503 | + while (Event.proxyHandlerMethods.size() < Event.proxyInnerClassIndex + 1) | ||
504 | + Event.proxyHandlerMethods.add(new LinkedHashMap<MethodNode, List<Event>>()); | ||
505 | + | ||
506 | + ArrayList<Event> events = new ArrayList<Event>(); | ||
507 | + Event.proxyHandlerMethods.get(Event.proxyInnerClassIndex).put(handlerMethod, events); | ||
508 | + return events; | ||
509 | + } | ||
510 | + | ||
511 | + private static List<Event> getEventsForHandlerMethod(MethodNode handlerMethod) | ||
512 | + { | ||
513 | + for (Map<MethodNode, List<Event>> handlers : Event.proxyHandlerMethods) | ||
514 | + { | ||
515 | + List<Event> events = handlers.get(handlerMethod); | ||
516 | + if (events != null) return events; | ||
517 | + } | ||
518 | + | ||
519 | + return Event.addMethodToActiveProxy(handlerMethod); | ||
520 | + } | ||
521 | + | ||
506 | private static String getHandlerName(int globalEventID) | 522 | private static String getHandlerName(int globalEventID) |
507 | { | 523 | { |
508 | return String.format("$event%05x", globalEventID); | 524 | return String.format("$event%05x", globalEventID); |
509 | } | 525 | } |
510 | 526 | ||
527 | + private static String getActiveProxyRef() | ||
528 | + { | ||
529 | + return Obf.EventProxy.ref + (Event.proxyInnerClassIndex > 1 ? "$" + Event.proxyInnerClassIndex : ""); | ||
530 | + } | ||
531 | + | ||
511 | /** | 532 | /** |
512 | * @param args | 533 | * @param args |
513 | * @param insns | 534 | * @param insns |
java/common/com/mumfrey/liteloader/transformers/event/EventInjectionTransformer.java
@@ -147,9 +147,21 @@ public abstract class EventInjectionTransformer extends ClassTransformer | @@ -147,9 +147,21 @@ public abstract class EventInjectionTransformer extends ClassTransformer | ||
147 | { | 147 | { |
148 | if (EventInjectionTransformer.master == this) | 148 | if (EventInjectionTransformer.master == this) |
149 | { | 149 | { |
150 | - if (Obf.EventProxy.name.equals(transformedName)) | 150 | + if (transformedName != null && transformedName.startsWith(Obf.EventProxy.name)) |
151 | { | 151 | { |
152 | - return this.transformEventProxy(basicClass); | 152 | + int dollarPos = transformedName.indexOf('$'); |
153 | + int proxyIndex = (dollarPos > -1) ? Integer.parseInt(transformedName.substring(dollarPos + 1)) : 0; | ||
154 | + if (proxyIndex != 1) | ||
155 | + { | ||
156 | + try | ||
157 | + { | ||
158 | + return this.transformEventProxy(transformedName, basicClass, proxyIndex); | ||
159 | + } | ||
160 | + catch (Throwable th) | ||
161 | + { | ||
162 | + th.printStackTrace(); | ||
163 | + } | ||
164 | + } | ||
153 | } | 165 | } |
154 | 166 | ||
155 | if (basicClass != null && EventInjectionTransformer.eventMappings.containsKey(transformedName)) | 167 | if (basicClass != null && EventInjectionTransformer.eventMappings.containsKey(transformedName)) |
@@ -161,21 +173,34 @@ public abstract class EventInjectionTransformer extends ClassTransformer | @@ -161,21 +173,34 @@ public abstract class EventInjectionTransformer extends ClassTransformer | ||
161 | return basicClass; | 173 | return basicClass; |
162 | } | 174 | } |
163 | 175 | ||
164 | - private byte[] transformEventProxy(byte[] basicClass) | 176 | + private byte[] transformEventProxy(String transformedName, byte[] basicClass, int proxyIndex) |
165 | { | 177 | { |
166 | - ClassNode classNode = this.readClass(basicClass, true); | ||
167 | - | ||
168 | - for (MethodNode method : classNode.methods) | 178 | + ClassNode classNode = this.getProxyByteCode(transformedName, basicClass, proxyIndex); |
179 | + return this.writeClass(Event.populateProxy(classNode, proxyIndex == 0 ? 1 : proxyIndex)); | ||
180 | + } | ||
181 | + | ||
182 | + private ClassNode getProxyByteCode(String transformedName, byte[] basicClass, int proxyIndex) | ||
183 | + { | ||
184 | + if (proxyIndex == 0 || basicClass != null) | ||
169 | { | 185 | { |
170 | - // Strip the sanity code out of the EventProxy class initialiser | ||
171 | - if ("<clinit>".equals(method.name)) | 186 | + ClassNode classNode = this.readClass(basicClass, true); |
187 | + | ||
188 | + for (MethodNode method : classNode.methods) | ||
172 | { | 189 | { |
173 | - method.instructions.clear(); | ||
174 | - method.instructions.add(new InsnNode(Opcodes.RETURN)); | ||
175 | - } | ||
176 | - } | 190 | + // Strip the sanity code out of the EventProxy class initialiser |
191 | + if ("<clinit>".equals(method.name)) | ||
192 | + { | ||
193 | + method.instructions.clear(); | ||
194 | + method.instructions.add(new InsnNode(Opcodes.RETURN)); | ||
195 | + } | ||
196 | + } | ||
197 | + | ||
198 | + return classNode; | ||
199 | + } | ||
177 | 200 | ||
178 | - return this.writeClass(Event.populateProxy(classNode)); | 201 | + ClassNode classNode = new ClassNode(); |
202 | + classNode.visit(50, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, transformedName.replace('.', '/'), null, "java/lang/Object", null); | ||
203 | + return classNode; | ||
179 | } | 204 | } |
180 | 205 | ||
181 | private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings) | 206 | private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings) |