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) |