问题
After compiling with Java 8 and dumping the resulting class files with javap, I see this, of which I am only showing the first 2 items:
BootstrapMethods:
0: #174 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#175 (Ljava/lang/Object;)Z
#179 invokestatic llllll/lallll.lambda$printPersons$0:(Lllllll/lallll;)Z
#180 (Lllllll/lallll;)Z
1: #174 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#175 (Ljava/lang/Object;)Z
#191 invokestatic llllll/lallll.lambda$printPersons$1:(Lllllll/lallll;)Z
#180 (Lllllll/lallll;)Z
2: #174 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/inv
Can I use ASM to visit the instructions in these bootstrap methods and change, say, the names of the methods being called using invokestatic instructions above?
Apparently these methods are not part of the normal methods of a class, and I haven't had any luck visiting them using standard ASM class and method techniques.
If not using ASM, is it possible to find and modify these instructions using another Java bytecode/class file manipulation framework?
I been reading the standard class file format documents for Java and I am not seeing a direct description of the instructions for the bootstrap methods, though I do see what I will describe as metadata for the bootstrap methods.
thanks,
-David
回答1:
The BootstrapMethods
attribute contains references to other methods. There are no bootstrap methods in your class file (usually) and you actually do not want to change the bootstrap method, which is the method metafactory
within the class java.lang.invoke.LambdaMetafactory
in your example.
What you actually want to do (apparently), is to change the properties of the invokedynamic instruction that will create the instance for a lambda expression or method reference. For this task, ASM does already help you.
When using the Visitor API, you have to override visitInvokeDynamicInsn. At this place, ASM has already decoded the referenced entry of the BootstrapMethods
attribute, provides these values to the visit method and will (re)create the appropriate BootstrapMethods
attribute when you pass these, possibly changed, values to the visitInvokeDynamicInsn
method of the ClassWriter
’s method visitor.
Within the overridden visitInvokeDynamicInsn
, you first have to verify that this invokedynamic
instruction truly is a lambda creation site. The bsm
argument must be a Handle whose owner is java/lang/invoke/LambdaMetafactory
and the method must be either metafactory or altMetafactory. If not, just pass everything to super.visitInvokeDynamicInsn
(delegating to the writer unchanged), as it is a different use of the invokedynamic feature then (e.g., Java 9 will use it for string concatenation).
When it is a lambda creation site, you can interpret the arguments according to the conventions specified in the documentation of LambdaMetafactory. The bsmArgs
array corresponds to the attribute you have posted in your question. The array element at index 1
will be the target method, again represented as Handle in ASM. You may change it to a different handle, which seems to be your intended operation. The target functional interface is the return type encoded in the desc
argument and the name of the functional interface’s method is provided as name
argument (the invokedName
name argument of the bootstrap method). For more details, refer to LambdaMetafactory’s comprehensive documentation.
来源:https://stackoverflow.com/questions/47561756/how-to-modify-instructions-in-java-bootstrapmethods-using-asm