Community
Participate
Working Groups
This bug is to discuss how AspectJ should treat invokedynamic bytecodes. (see post "Any researchers out there put time into invokedynamic interplay with AspectJ pointcuts?" on aspectj-dev)
As Eric mentioned on the mailing list there are few things that this bug report could cover: (1) AspectJ coping with the invokedynamic instruction (not doing anything special for it, just coping with it) (2) AspectJ recognizing and matching/weaving invokedynamic calls (3) AspectJ using invokedynamic in generated code My goal primarily is (1) whilst exploring (2). A later goal would be (3) if we could show an appreciable benefit - doesn't have to be a performance benefit (seems unlikely that it would be), it could be a flexibility benefit. Now (1) seems pretty straightforward, just letting that instruction through and not damaging it, I doubt this will take much effort. (2) is where I'd like the assistance right now. I don't know if I want a new pointcut, a new modifier on 'call', or even if there is enough information known when using invokedynamic such that we can do the right thing. I've really not looked into invokedynamic thoroughly yet.
Hi Andy. Regarding (1) I would hope that ASM is taking care of that automatically. Can you confirm this? (You are using ASM for weaving, aren't you?) Regarding (3), this is indeed very tricky. IMHO execution joinpoints should just work as before (because they are at the callee side), and so should all other joinpoints except for "call". For call joinpoints, however, one obviously cannot do the usual static matching using the pointcut signature. I think one way one possibly *could* go about this is to somehow wrap or replace the MethodHandle lookup mechanism that the invokedynamic-using application uses. One would then need to recognize advised calls at runtime and reroute the method handles to woven versions of the code dynamically. If I am not mistaken, then lookup is usually performed through a Lookup object, see http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandles.Lookup.html#findGetter(java.lang.Class, java.lang.String, java.lang.Class)
quick reply from me: > Regarding (1) I would hope that ASM is taking care of that automatically. Can you confirm this? (You are using ASM for weaving, aren't you?) No, we still don't use ASM. ASM doesn't provide the right granularity for us (some things we don't want to take apart but we don't get a choice with asm), we continue to use bcel (heavily modified of course). What happens here will depend on (a) whether I modified the bcel code to recognize invokedynamic - dont remember, (b) what happens when the weaver encounters invokedynamic, will it try to create the wrong kind of shadow? will it crash? will it be ignored? will it be swallowed? I just don't know. I will get this sorted for M2. ASM *is* used for recomputing stackmap attributes right now, after weaving is completed.
I have thought a bit more about "(2) AspectJ recognizing and matching/weaving invokedynamic calls"... One may have two different view points. The first view point may be that invokedynamic calls are calls like any other calls, and therefore a pointcut call(foo()) should match on *any* call to foo() no matter whether invoked through invokedynamic or whatever other bytecode. This, however would be very hard (impossible?) to implement with the current API. From what I can see, one would need to wrap the program's bootstrap methods to return wrapper call site objects which execute the pointcut matching logic at runtime. On a call to CallSite.getTarget() one would need to capture this target, see if a pointcut matches on it, and if not, return a MethodHandle to some "nop method". The problem is that CallSite.getTarget() cannot be overwritten, and one also cannot advise calls to this method with aspects because they come from native code. The second view point may be that an invokedynamic instruction is special, and therefore there should be a special pointcut for it, exposing the arguments passed to this call. This would be simple to implement, but the question is how useful it would be. Regarding "(3) AspectJ using invokedynamic in generated code", this would certainly be the way to go. The resulting generated code should be much simpler than today if invokedynamic were used. P.S. On another note, I am also experiencing Bug 353467 when compiling with -target 1.7
just committed changes for (1). Added support for 3 new constant pool entry types, the new attribute and the invokedynamic instruction. Some new IndyTests verify I can weave into bytecode that contains the invokedynamic instruction. The invokedynamic call is currently ignored and will not manifest as a joinpoint.
This one might be blocking https://bugs.eclipse.org/bugs/show_bug.cgi?id=471347. I am mentioning it because Andy asked for possible benefits of (2). I think the two tickets are related.
I forgot to explain: The fact that AspectJ is currently blind to lambda executions and calls is partly due to the fact that invokedynamic is being ignored. A popular and potentially useful example would be intercepting Runnable.run() whereas the runnable is implemented as a lambda, i.e. usually as a private method inside the defining class dynamically called like this for example: invokedynamic #26, 0 // InvokeDynamic #0:run: // Lde/scrum_master/app/Application;) // Ljava/lang/Runnable; invokeinterface #30, 2 // InterfaceMethod // java/util/concurrent/ExecutorService.execute: // (Ljava/lang/Runnable;)V
It is also not possible to intercept constructor calls on such lambdas, i.e. to find out where and when they are being created. In multi-threaded scenarios this makes tracing certain asynchronous control flows via AOP next to impossible.