Fixes #61: support invokevirtual bootstrap method type
This commit is contained in:
@@ -120,20 +120,32 @@ public class Java8 {
|
||||
// Looking up the lambda$run method in the caller class (note the caller class is the executor, which gets us around the
|
||||
// problem of having to hack into LambdaMetafactory to intercept reflection)
|
||||
MethodHandle implMethod = null;
|
||||
// TODO [lambda] need to handle invokevirtual, surely
|
||||
switch (bsmArgsHandle.getTag()) {
|
||||
case Opcodes.H_INVOKESTATIC:
|
||||
implMethod = caller.findStatic(caller.lookupClass(), name, implMethodType);
|
||||
break;
|
||||
case Opcodes.H_INVOKESPECIAL:
|
||||
// If there is an executor, the lambda function is actually modified from 'private instance' to 'public static' so adjust lookup:
|
||||
// If there is an executor, the lambda function is actually modified from 'private instance' to 'public static' so adjust lookup. The method
|
||||
// will be static with a new leading parameter.
|
||||
if (executorClass == null) {
|
||||
// TODO is final parameter here correct?
|
||||
implMethod = caller.findSpecial(caller.lookupClass(), name, implMethodType, caller.lookupClass());
|
||||
}
|
||||
else {
|
||||
implMethod = caller.findStatic(caller.lookupClass(), name, MethodType.fromMethodDescriptorString("(L"+owner+";"+descriptor.substring(1),callerLoader));
|
||||
}
|
||||
break;
|
||||
case Opcodes.H_INVOKEVIRTUAL:
|
||||
// If there is an executor, the lambda function is actually modified from 'private instance' to 'public static' so adjust lookup. The method
|
||||
// will be static with a new leading parameter.
|
||||
if (executorClass == null) {
|
||||
// TODO when can this scenario occur? Aren't we only here if reloading has happened?
|
||||
implMethod = caller.findVirtual(caller.lookupClass(), name, implMethodType);
|
||||
}
|
||||
else {
|
||||
implMethod = caller.findStatic(caller.lookupClass(), name, MethodType.fromMethodDescriptorString("(L"+owner+";"+descriptor.substring(1),callerLoader));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("nyi "+bsmArgsHandle.getTag());
|
||||
}
|
||||
|
||||
@@ -267,6 +267,31 @@ public class Java8Tests extends SpringLoadedTests {
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("ab", r.returnValue);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void lambdaInvokeVirtual() throws Exception {
|
||||
String t = "basic.LambdaJ";
|
||||
TypeRegistry typeRegistry = getTypeRegistry("basic..*");
|
||||
|
||||
// Since Foo needs promoting to public, have to ensure it is directly loaded:
|
||||
ReloadableType itype = typeRegistry.addType(t+"$Foo", loadBytesForClass(t+"$Foo"));
|
||||
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("fooa", r.returnValue);
|
||||
|
||||
itype.loadNewVersion("002", retrieveRename(t+"$Foo",t+"2$Foo"));
|
||||
rtype.loadNewVersion("002", retrieveRename(t,t+"2",t+"2$Foo:"+t+"$Foo"));
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("fooab", r.returnValue);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
|
||||
24
testdata-java8/src/main/java/basic/LambdaJ.java
Normal file
24
testdata-java8/src/main/java/basic/LambdaJ.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package basic;
|
||||
|
||||
public class LambdaJ {
|
||||
|
||||
public interface Foo { String m(String s); }
|
||||
|
||||
public String getFoo(String s) {
|
||||
return "foo"+s;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
run();
|
||||
}
|
||||
|
||||
public static String run() {
|
||||
return new LambdaJ().run2();
|
||||
}
|
||||
|
||||
public String run2() {
|
||||
Foo f = this::getFoo;
|
||||
return f.m("a");
|
||||
}
|
||||
|
||||
}
|
||||
24
testdata-java8/src/main/java/basic/LambdaJ2.java
Normal file
24
testdata-java8/src/main/java/basic/LambdaJ2.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package basic;
|
||||
|
||||
public class LambdaJ2 {
|
||||
|
||||
public interface Foo { String m(String s, String t); }
|
||||
|
||||
public String getFoo(String s, String t) {
|
||||
return "foo"+s+t;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
run();
|
||||
}
|
||||
|
||||
public static String run() {
|
||||
return new LambdaJ().run2();
|
||||
}
|
||||
|
||||
public String run2() {
|
||||
Foo f = this::getFoo;
|
||||
return f.m("a","b");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user