When injecting into methods that get called a lot (in my case hundreds of thousands of times per second), a large number of CallbackInfo or CallbackInfoReturnable instances get created. Here is an example of this issue getting reported to a different project I found when researching this: FTBTeam/FTB-Mods-Issues#2012
Ideally, it would be possible to inject code that can return without allocating objects in the process. I have a couple of ideas on how this could be implemented:
Cache CallbackInfo[Returnable] objects for each thread
Mixin:
@Inject(method = "targetMethod", at = @At("HEAD"), cancellable = true, highTraffic = true) // highTraffic indicates caching should be used
private void injected(int arg, CallbackInfoReturnable<String> info) {
if (Math.random() < 0.5)
info.setReturnValue("foo");
}
Target:
+ private static final ThreadLocal cache_targetMethod_injected = ThreadLocal.withInitial(() -> new CallbackInfoReturnable<>("targetMethod", true));
public String targetMethod(int arg) {
+ CallbackInfoReturnable<String> info = cache_targetMethod_injected.get();
+ info.reset(); // Sets cancelled to false, return value to null
+ injected(arg, info);
+ if (info.isCancelled())
+ return info.getReturnValue();
...
}
Actually return from mixin method
Mixin:
@InjectInline(method = "targetMethod", at = @At("HEAD"))
private String injected(int arg) {
if (Math.random() < 0.5)
return "foo";
// This should be stripped out of the bytecode before being injected
// Can only show up at the end of the mixin method
throw InjectInline.DONT_RETURN;
// Another option
return InjectInline.DontReturn.forReference(); // non-void methods
InjectInline.DontReturn.forVoid(); // void methods
}
Target:
public String targetMethod(int arg) {
+ if (Math.random() < 0.5) // Bytecode is injected into the target method directly
+ return "foo";
+ // throw is removed
...
}
InjectInline:
public @interface InjectInline {
public static final RuntimeException DONT_RETURN = null;
// Alternatively
public static class DontReturn {
public static <T> T forReference() {
return null;
}
public static void forVoid() {}
}
...
}
When injecting into methods that get called a lot (in my case hundreds of thousands of times per second), a large number of
CallbackInfoorCallbackInfoReturnableinstances get created. Here is an example of this issue getting reported to a different project I found when researching this: FTBTeam/FTB-Mods-Issues#2012Ideally, it would be possible to inject code that can return without allocating objects in the process. I have a couple of ideas on how this could be implemented:
Cache CallbackInfo[Returnable] objects for each thread
Mixin:
Target:
Actually return from mixin method
Mixin:
Target:
public String targetMethod(int arg) { + if (Math.random() < 0.5) // Bytecode is injected into the target method directly + return "foo"; + // throw is removed ... }InjectInline: