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 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 61 EventProxy.error = "Missing Event Handler Class!";
63 62 EventProxy.errorDetails = new StringBuilder();
... ... @@ -83,8 +82,7 @@ public final class EventProxy
83 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 87 String descriptor = err.getMessage();
90 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 36 */
37 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 44 * The name of this event
... ... @@ -239,11 +239,6 @@ public class Event implements Comparable&lt;Event&gt;
239 239 {
240 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 259  
265 260 // Create the handler delegate method
266 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 266 Type[] argumentTypes = Type.getArgumentTypes(this.method.desc);
272 267 int ctorMAXS = 0, invokeMAXS = argumentTypes.length;
... ... @@ -286,7 +281,7 @@ public class Event implements Comparable&lt;Event&gt;
286 281 // Call the event handler method in the proxy
287 282 insns.add(new VarInsnNode(Opcodes.ALOAD, eventInfoVar));
288 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 286 if (cancellable)
292 287 {
... ... @@ -300,7 +295,7 @@ public class Event implements Comparable&lt;Event&gt;
300 295  
301 296 return handler;
302 297 }
303   -
  298 +
304 299 /**
305 300 * if (e.isCancelled()) return e.getReturnValue();
306 301 *
... ... @@ -360,11 +355,7 @@ public class Event implements Comparable&lt;Event&gt;
360 355 {
361 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 417 * Populates the event proxy class with delegating methods for all injected events
427 418 *
428 419 * @param classNode
  420 + * @param proxyIndex TODO
429 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 425 int handlerCount = 0;
436 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 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 437 MethodNode handlerMethod = handler.getKey();
443 438 List<Event> handlerEvents = handler.getValue();
... ... @@ -503,11 +498,37 @@ public class Event implements Comparable&lt;Event&gt;
503 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 522 private static String getHandlerName(int globalEventID)
507 523 {
508 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 533 * @param args
513 534 * @param insns
... ...
java/common/com/mumfrey/liteloader/transformers/event/EventInjectionTransformer.java
... ... @@ -147,9 +147,21 @@ public abstract class EventInjectionTransformer extends ClassTransformer
147 147 {
148 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 167 if (basicClass != null && EventInjectionTransformer.eventMappings.containsKey(transformedName))
... ... @@ -161,21 +173,34 @@ public abstract class EventInjectionTransformer extends ClassTransformer
161 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 206 private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings)
... ...