more Java8 fixes
This commit is contained in:
@@ -2,5 +2,6 @@
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J180_b128"/>
|
||||
<classpathentry kind="lib" path="lib/asm-5.0_BETA.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>j8code</name>
|
||||
<name>springloaded-java8</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
|
||||
BIN
j8code/lib/asm-5.0_BETA.jar
Normal file
BIN
j8code/lib/asm-5.0_BETA.jar
Normal file
Binary file not shown.
3
j8code/readme.txt
Normal file
3
j8code/readme.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
The main springloaded codebase is not yet using Java8. The Java8 'stuff' is captured here in this
|
||||
project and included in the distributed agent. It should only be loaded if we find ourselves on a
|
||||
Java8 VM. This code is not using Java8 source constructs, it is calling Java8 APIs.
|
||||
@@ -1,4 +1,19 @@
|
||||
package j8code;
|
||||
/*
|
||||
* Copyright 2014 Pivotal Software Inc. and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springsource.loaded.support;
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
@@ -6,64 +21,122 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
public class J8Helper {
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public static Object simulateInvokeDynamic(Object lookup) {
|
||||
/**
|
||||
* This class encapsulates dependencies on Java 8 APIs (e.g. LambdaMetafactory).
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 1.2
|
||||
*/
|
||||
public class Java8 {
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
*
|
||||
* Useful to have an example of how this code behaves. Here is a bit of code:
|
||||
*
|
||||
* class basic.LambdaA {
|
||||
* interface Foo { int m(); }
|
||||
* static int run() {
|
||||
* Foo f = null;
|
||||
* f = () -> 77;
|
||||
* return f.m();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Here is a bootstrap method entry in the constant pool:
|
||||
*
|
||||
* 0: #31 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:
|
||||
* #32 ()I
|
||||
* #33 invokestatic basic/LambdaA.lambda$run$0:()I
|
||||
* #32 ()I
|
||||
*
|
||||
* At the invokedynamic site:
|
||||
* bsmId = 0
|
||||
* nameAndDescriptor = m()Lbasic/LambdaA$Foo;
|
||||
*
|
||||
* When invoking the metafactory bootstrap method the first two parameters are stacked by the VM automatically, namely the MethodHandles$Lookup
|
||||
* instance (caller) and the first String (invokedName). What the VM actually sees is this:
|
||||
*
|
||||
* metaFactory parameters:
|
||||
* 0:MethodHandles$Lookup caller = basic.LambdaA
|
||||
* 1:String invokedName = "m"
|
||||
* 2:MethodType invokedType = "()Foo"
|
||||
* 3:MethodType samMethodType = "()int"
|
||||
* 4:MethodHandle implMethod = (actually a DirectMethodHandle where memberName is "basic.LambdaA.lambda$run$0()int/invokeStatic")
|
||||
* 5:MethodType instantiatedMethodType = "()int"
|
||||
*
|
||||
* With all that information then the calls in this case are relatively straightforward:
|
||||
* CallSite callsite = LambdaMetafactory.metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType);
|
||||
* callsite.dynamicInvoker().invokeWithArguments((Object[])null);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Programmatic emulation of INVOKEDYNAMIC so initialize the callsite via use of the bootstrap method then
|
||||
* invoke the result.
|
||||
*
|
||||
* @param executorClass null if not yet reloaded
|
||||
* @param handle
|
||||
* @param bsmArgs
|
||||
* @param lookup
|
||||
* @return
|
||||
*/
|
||||
public static Object emulateInvokeDynamic(Class executorClass, Handle handle, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Object[] indyParams) {
|
||||
try {
|
||||
CallSite callsite = callLambdaMetaFactory(lookup);
|
||||
// java.lang.invoke.ConstantCallSite@1e965684
|
||||
// nameAndDescriptor at invokedynamic: m()Lbasic/LambdaA$Foo;
|
||||
MethodHandles.Lookup caller = (MethodHandles.Lookup)lookup;
|
||||
return callsite.dynamicInvoker().invokeWithArguments((Object[])null);//asType(MethodType.methodType())invoke(new Object[]{"m", MethodType.methodType(Class.forName("basic.LambdaA$Foo",false,caller.lookupClass().getClassLoader()))});
|
||||
CallSite callsite = callLambdaMetaFactory(bsmArgs,lookup,indyNameAndDescriptor,executorClass);
|
||||
return callsite.dynamicInvoker().invokeWithArguments(indyParams);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static CallSite callLambdaMetaFactory(Object lookup) throws Exception {
|
||||
// At invokedynamic:
|
||||
// bsmId = 0
|
||||
// nameAndDescriptor = m()Lbasic/LambdaA$Foo;
|
||||
// TODO [perf] How about a table of CallSites indexed by invokedynamic number through the class file. Computed on first reference but cleared on reload. Possibly extend this to all invoke types!
|
||||
|
||||
// 0: #31 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:
|
||||
// #32 ()I
|
||||
// #33 invokestatic basic/LambdaA.lambda$run$0:()I
|
||||
// #32 ()I
|
||||
// TODO [lambda] Need to handle altMetaFactory which is used when the lambdas are more 'complex' (e.g. Serializable)
|
||||
public static CallSite callLambdaMetaFactory(Object[] bsmArgs, Object lookup, String indyNameAndDescriptor,Class executorClass) throws Exception {
|
||||
MethodHandles.Lookup caller = (MethodHandles.Lookup)lookup;
|
||||
|
||||
ClassLoader callerLoader = caller.lookupClass().getClassLoader();
|
||||
|
||||
int descriptorStart = indyNameAndDescriptor.indexOf('(');
|
||||
String invokedName = indyNameAndDescriptor.substring(0,descriptorStart);
|
||||
MethodType invokedType = MethodType.fromMethodDescriptorString(indyNameAndDescriptor.substring(descriptorStart), callerLoader);
|
||||
|
||||
// First two stacked by VM when used with invokedynamic
|
||||
// Use bsmArgs to build the parameters
|
||||
MethodType samMethodType = MethodType.fromMethodDescriptorString((String)(((Type)bsmArgs[0]).getDescriptor()), callerLoader);
|
||||
|
||||
Handle bsmArgsHandle = (Handle)bsmArgs[1];
|
||||
String owner = bsmArgsHandle.getOwner();
|
||||
String name = bsmArgsHandle.getName();
|
||||
String descriptor = bsmArgsHandle.getDesc();
|
||||
MethodType implMethodType = MethodType.fromMethodDescriptorString(descriptor, callerLoader);
|
||||
// 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 6: // INVOKESSTATIC
|
||||
implMethod = caller.findStatic(caller.lookupClass(), name, implMethodType);
|
||||
break;
|
||||
case 7: // INVOKESPECIAL
|
||||
// If there is an executor, the lambda function is actually modified from 'private instance' to 'public static' so adjust lookup:
|
||||
if (executorClass == null) {
|
||||
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;
|
||||
default:
|
||||
throw new IllegalStateException("nyi "+bsmArgsHandle.getTag());
|
||||
}
|
||||
|
||||
MethodType instantiatedMethodType = MethodType.fromMethodDescriptorString((String)(((Type)bsmArgs[2]).getDescriptor()), callerLoader);
|
||||
|
||||
// 0: #31 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:
|
||||
// #32 ()I
|
||||
// #33 invokestatic basic/LambdaA.lambda$run$0:()I
|
||||
// #32 ()I
|
||||
|
||||
// caller = basic.LambdaA (MethodHandles$Lookup)
|
||||
|
||||
// invokedName = m (String)
|
||||
// invokedType = ()Foo (MethodType)
|
||||
|
||||
// samMethodType=()int (MethodType)
|
||||
// implMethod=MethodHandle()int (DirectMethodHandle - membername in this object is "basic.LambdaA.lambda$run$0()int/invokeStatic")
|
||||
// form members is:
|
||||
//
|
||||
// DMH.invokeStatic__I=Lambda(a0:L)=>{
|
||||
// t1:L=DirectMethodHandle.internalMemberName(a0:L);
|
||||
// t2:I=MethodHandle.linkToStatic(t1:L);t2:I}
|
||||
// instantiatedMethodType=()int (MethodType)
|
||||
MethodHandles.Lookup caller = (MethodHandles.Lookup)lookup;
|
||||
MethodType invokedType = MethodType.methodType(Class.forName("basic.LambdaA$Foo",false,caller.lookupClass().getClassLoader()));
|
||||
|
||||
MethodType samMethodType = MethodType.methodType(Integer.TYPE);
|
||||
// Cheating here by changing first param to pretend the original type is looking for it rather than the executor
|
||||
MethodHandle implMethod = caller.findStatic(caller.lookupClass(), "lambda$run$0",MethodType.methodType(Integer.TYPE));
|
||||
MethodType instantiatedMethodType = MethodType.methodType(Integer.TYPE);
|
||||
return LambdaMetafactory.metafactory(caller, "m", invokedType, samMethodType, implMethod, instantiatedMethodType);
|
||||
return LambdaMetafactory.metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
<classpathentry kind="lib" path="lib/asm-tree-5.0_BETA.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/j8code"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/springloaded-java8"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
/*
|
||||
* Copyright 2014 Pivotal Software Inc. and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springsource.loaded.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springsource.loaded.ReloadableType;
|
||||
import org.springsource.loaded.TypeRegistry;
|
||||
@@ -13,7 +29,7 @@ import org.springsource.loaded.test.infra.Result;
|
||||
* Test reloading of Java 8.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 1.1.5
|
||||
* @since 1.2
|
||||
*/
|
||||
public class Java8Tests extends SpringLoadedTests {
|
||||
|
||||
@@ -77,74 +93,172 @@ public class Java8Tests extends SpringLoadedTests {
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
ClassPrinter.print(rtype.bytesLoaded);
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(77, r.returnValue);
|
||||
|
||||
rtype.loadNewVersion("002", retrieveRename(t,t+"2"));
|
||||
byte[] renamed = retrieveRename(t,t+"2",t+"2$Foo:"+t+"$Foo");
|
||||
rtype.loadNewVersion("002", renamed);
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(88, r.returnValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lambdaWithParameter() throws Exception {
|
||||
String t = "basic.LambdaB";
|
||||
TypeRegistry typeRegistry = getTypeRegistry(t);
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(99L, r.returnValue);
|
||||
|
||||
byte[] renamed = retrieveRename(t,t+"2",t+"2$Foo:"+t+"$Foo");
|
||||
rtype.loadNewVersion("002", renamed);
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(176L, r.returnValue);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void lambdaWithTwoParameters() throws Exception {
|
||||
String t = "basic.LambdaC";
|
||||
TypeRegistry typeRegistry = getTypeRegistry(t);
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(6L, r.returnValue);
|
||||
|
||||
byte[] renamed = retrieveRename(t,t+"2",t+"2$Boo:"+t+"$Boo");
|
||||
rtype.loadNewVersion("002", renamed);
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(5L, r.returnValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lambdaWithThreeMixedTypeParameters() throws Exception {
|
||||
String t = "basic.LambdaD";
|
||||
TypeRegistry typeRegistry = getTypeRegistry(t);
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("true342abc", r.returnValue);
|
||||
|
||||
byte[] renamed = retrieveRename(t,t+"2",t+"2$Boo:"+t+"$Boo");
|
||||
rtype.loadNewVersion("002", renamed);
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("def264true", r.returnValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lambdaWithCapturedVariable() throws Exception {
|
||||
String t = "basic.LambdaE";
|
||||
TypeRegistry typeRegistry = getTypeRegistry(t);
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("aaaa", r.returnValue);
|
||||
|
||||
byte[] renamed = retrieveRename(t,t+"2",t+"2$Boo:"+t+"$Boo");
|
||||
rtype.loadNewVersion("002", renamed);
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("aaaaaaaa", r.returnValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lambdaWithThis() throws Exception {
|
||||
String t = "basic.LambdaF";
|
||||
TypeRegistry typeRegistry = getTypeRegistry(t);
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals("aaaaaaa", r.returnValue);
|
||||
|
||||
byte[] renamed = retrieveRename(t,t+"2",t+"2$Boo:"+t+"$Boo");
|
||||
rtype.loadNewVersion("002", renamed);
|
||||
ClassPrinter.print(rtype.getLatestExecutorBytes());
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(77, r.returnValue);
|
||||
assertEquals("a:a:a:", r.returnValue);
|
||||
}
|
||||
|
||||
// TODO changing a lambda body
|
||||
// TODO changing a lambda signature
|
||||
// TODO adding a lambda that wasn't there before
|
||||
// TODO deleting a lambda
|
||||
// TODO make that inner interface non-public in LambdaA - seems to break things.
|
||||
@Test
|
||||
public void lambdaWithNonPublicInnerInterface() throws Exception {
|
||||
String t = "basic.LambdaG";
|
||||
TypeRegistry typeRegistry = getTypeRegistry("basic..*");
|
||||
|
||||
// Since Boo needs promoting to public, have to ensure it is directly loaded:
|
||||
typeRegistry.addType(t+"$Boo", loadBytesForClass(t+"$Boo"));
|
||||
|
||||
// Bytecode for LambdaA
|
||||
/*
|
||||
BootstrapMethods:
|
||||
0: #31 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:
|
||||
#32 ()I
|
||||
#33 invokestatic basic/LambdaA.lambda$run$0:()I
|
||||
#32 ()I
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
public static int run();
|
||||
descriptor: ()I
|
||||
flags: ACC_PUBLIC, ACC_STATIC
|
||||
Code:
|
||||
stack=1, locals=1, args_size=0
|
||||
0: aconst_null
|
||||
1: astore_0
|
||||
2: invokedynamic #3, 0 // InvokeDynamic #0:m:()Lbasic/LambdaA$Foo;
|
||||
7: astore_0
|
||||
8: aload_0
|
||||
9: invokeinterface #4, 1 // InterfaceMethod basic/LambdaA$Foo.m:()I
|
||||
14: ireturn
|
||||
*/
|
||||
/*
|
||||
static void test() throws Throwable {
|
||||
// THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
|
||||
InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
|
||||
}
|
||||
private static void printArgs(Object... args) {
|
||||
System.out.println(java.util.Arrays.deepToString(args));
|
||||
}
|
||||
private static final MethodHandle printArgs;
|
||||
static {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
Class thisClass = lookup.lookupClass(); // (who am I?)
|
||||
printArgs = lookup.findStatic(thisClass,
|
||||
"printArgs", MethodType.methodType(void.class, Object[].class));
|
||||
}
|
||||
private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
|
||||
// ignore caller and name, but match the type:
|
||||
return new ConstantCallSite(printArgs.asType(type));
|
||||
}
|
||||
}
|
||||
*/
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(99, r.returnValue);
|
||||
ClassPrinter.print(rtype.bytesLoaded);
|
||||
|
||||
byte[] renamed = retrieveRename(t,t+"2",t+"2$Boo:"+t+"$Boo");
|
||||
rtype.loadNewVersion("002", renamed);
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(44, r.returnValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleLambdasInOneMethod() throws Exception {
|
||||
String t = "basic.LambdaH";
|
||||
TypeRegistry typeRegistry = getTypeRegistry("basic..*");
|
||||
|
||||
// Since Foo needs promoting to public, have to ensure it is directly loaded:
|
||||
typeRegistry.addType(t+"$Foo", loadBytesForClass(t+"$Foo"));
|
||||
|
||||
|
||||
// --
|
||||
|
||||
private String slashed(String dotted) {
|
||||
return dotted.replaceAll("\\.", "/");
|
||||
byte[] sc = loadBytesForClass(t);
|
||||
ReloadableType rtype = typeRegistry.addType(t, sc);
|
||||
|
||||
Class<?> simpleClass = rtype.getClazz();
|
||||
Result r = runUnguarded(simpleClass, "run");
|
||||
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(56, r.returnValue);
|
||||
|
||||
rtype.loadNewVersion("002", rtype.bytesInitial);
|
||||
r = runUnguarded(simpleClass, "run");
|
||||
assertEquals(56, r.returnValue);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void lambdaWithVirtualMethodUse() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
// TODO before commit
|
||||
// copyrights
|
||||
// tidyup up invokedynamic rewriting to only intercept metafactory usages
|
||||
// decide about altmetafactory handling (marker interfaces on multicasts)
|
||||
// Guard idyrun on whether anything reloaded
|
||||
// Cache result of idyrun for reuse?
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1261,6 +1261,10 @@ public abstract class SpringLoadedTests implements Constants {
|
||||
return captureOff();
|
||||
}
|
||||
|
||||
protected String slashed(String dotted) {
|
||||
return dotted.replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
protected final static void pause(int seconds) {
|
||||
try {
|
||||
Thread.sleep(seconds*1000);
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
cd src/main/java
|
||||
find . -name "*.java" | javac
|
||||
../gradlew build
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user