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