@@ -23,6 +23,7 @@ private static class LambdaClassVisitor extends ClassVisitor {
23
23
private final int targetVersion ;
24
24
private String lambdaClass ;
25
25
private Type constructor ;
26
+ private Handle implMethod ;
26
27
private LambdaFactoryMethod factoryMethod ;
27
28
28
29
public LambdaClassVisitor (ClassWriter cw , int targetVersion ) {
@@ -34,6 +35,7 @@ public LambdaClassVisitor(ClassWriter cw, int targetVersion) {
34
35
public void visit (int version , int access , String name , String signature , String superName , String [] interfaces ) {
35
36
lambdaClass = name ;
36
37
LambdaReifier .setLambdaClass (lambdaClass );
38
+ implMethod = LambdaReifier .getLambdaImplMethod ();
37
39
factoryMethod = LambdaReifier .getLambdaFactoryMethod ();
38
40
39
41
if (version > targetVersion ) {
@@ -52,7 +54,7 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
52
54
}
53
55
MethodVisitor mv = super .visitMethod (access , name , desc , signature , exceptions );
54
56
mv = new MagicLambdaRemovingMethodVisitor (mv );
55
- mv = new PrivateMethodInvocationFixingMethodVisitor (mv , factoryMethod . getInvoker () );
57
+ mv = new PrivateMethodInvocationFixingMethodVisitor (mv , implMethod );
56
58
return mv ;
57
59
}
58
60
@@ -135,18 +137,24 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc)
135
137
136
138
private static class PrivateMethodInvocationFixingMethodVisitor extends MethodVisitor {
137
139
138
- private final String invoker ;
140
+ private final Handle implMethod ;
139
141
140
- public PrivateMethodInvocationFixingMethodVisitor (MethodVisitor mv , Class <?> invoker ) {
142
+ public PrivateMethodInvocationFixingMethodVisitor (MethodVisitor mv , Handle implMethod ) {
141
143
super (ASM4 , mv );
142
- this .invoker = Type . getInternalName ( invoker ) ;
144
+ this .implMethod = implMethod ;
143
145
}
144
146
145
147
@ Override
146
148
public void visitMethodInsn (int opcode , String owner , String name , String desc ) {
149
+ // Java 8's lambda classes get away with calling private virtual methods
150
+ // by using invokespecial because the JVM relaxes the bytecode validation
151
+ // of the lambda classes it generates. We must however use invokevirtual
152
+ // for them (which is possible because we also make them non-private).
147
153
if (opcode == INVOKESPECIAL
148
- && owner .equals (invoker )
149
- && LambdaNaming .LAMBDA_IMPL_METHOD .matcher (name ).matches ()) {
154
+ && !name .equals ("<init>" )
155
+ && owner .equals (implMethod .getOwner ())
156
+ && name .equals (implMethod .getName ())
157
+ && desc .equals (implMethod .getDesc ())) {
150
158
opcode = INVOKEVIRTUAL ;
151
159
}
152
160
super .visitMethodInsn (opcode , owner , name , desc );
0 commit comments