Commit 1b43bca7a655ca2cecd144e6eab6b9472e9e6a52

Authored by Mumfrey
1 parent 7a912de0

spawn anonymous inner classes for EventProxy to handle events injected after ini…

…tial proxy generation
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&lt;Event&gt; @@ -36,9 +36,9 @@ public class Event implements Comparable&lt;Event&gt;
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&lt;Event&gt; @@ -239,11 +239,6 @@ public class Event implements Comparable&lt;Event&gt;
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&lt;Event&gt; @@ -264,9 +259,9 @@ public class Event implements Comparable&lt;Event&gt;
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&lt;Event&gt; @@ -286,7 +281,7 @@ public class Event implements Comparable&lt;Event&gt;
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&lt;Event&gt; @@ -300,7 +295,7 @@ public class Event implements Comparable&lt;Event&gt;
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&lt;Event&gt; @@ -360,11 +355,7 @@ public class Event implements Comparable&lt;Event&gt;
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&lt;Event&gt; @@ -426,18 +417,22 @@ public class Event implements Comparable&lt;Event&gt;
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&lt;Event&gt; @@ -503,11 +498,37 @@ public class Event implements Comparable&lt;Event&gt;
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)