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