diff --git a/j8code/.classpath b/j8code/.classpath
new file mode 100644
index 0000000..4ad1cf5
--- /dev/null
+++ b/j8code/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/j8code/.project b/j8code/.project
new file mode 100644
index 0000000..2970a0c
--- /dev/null
+++ b/j8code/.project
@@ -0,0 +1,17 @@
+
+
+ j8code
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/j8code/.settings/org.eclipse.jdt.core.prefs b/j8code/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..4378554
--- /dev/null
+++ b/j8code/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/j8code/src/j8code/J8Helper.java b/j8code/src/j8code/J8Helper.java
new file mode 100644
index 0000000..4e3c942
--- /dev/null
+++ b/j8code/src/j8code/J8Helper.java
@@ -0,0 +1,69 @@
+package j8code;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+public class J8Helper {
+
+ public static Object simulateInvokeDynamic(Object lookup) {
+ 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()))});
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+
+ public static CallSite callLambdaMetaFactory(Object lookup) throws Exception {
+ // At invokedynamic:
+ // bsmId = 0
+ // nameAndDescriptor = m()Lbasic/LambdaA$Foo;
+
+// 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
+
+ // First two stacked by VM when used with invokedynamic
+
+// 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);
+ }
+}
diff --git a/springloaded/.classpath b/springloaded/.classpath
index 18ff684..ea09e62 100644
--- a/springloaded/.classpath
+++ b/springloaded/.classpath
@@ -2,9 +2,10 @@
-
-
+
+
+
diff --git a/springloaded/build.gradle b/springloaded/build.gradle
index 888dc94..71e6990 100644
--- a/springloaded/build.gradle
+++ b/springloaded/build.gradle
@@ -34,12 +34,17 @@ task wrapper(type: Wrapper) {
dependencies {
tools 'com.googlecode.jarjar:jarjar:1.3'
+/*
compile 'asm:asm:3.2'
compile 'asm:asm-tree:3.2'
+*/
+ compile 'org.ow2.asm:asm:5.0_BETA'
+ compile 'org.ow2.asm:asm-tree:5.0_BETA'
+
testCompile 'junit:junit:4.11'
- testCompileOnly files("../testdata-groovy/groovy-1.8.2.jar")
+ testCompileOnly files("../testdata-groovy/groovy-all-1.8.6.jar")
testCompileOnly project(':testdata')
testCompileOnly project(':testdata-groovy')
testCompileOnly project(':testdata-plugin')
diff --git a/springloaded/lib/asm-5.0_BETA.jar b/springloaded/lib/asm-5.0_BETA.jar
new file mode 100644
index 0000000..2e26615
Binary files /dev/null and b/springloaded/lib/asm-5.0_BETA.jar differ
diff --git a/springloaded/lib/asm-tree-5.0_BETA.jar b/springloaded/lib/asm-tree-5.0_BETA.jar
new file mode 100644
index 0000000..e486d18
Binary files /dev/null and b/springloaded/lib/asm-tree-5.0_BETA.jar differ
diff --git a/springloaded/springloaded tests (no generated tests) (1.8).launch b/springloaded/springloaded tests (no generated tests) (1.8).launch
new file mode 100644
index 0000000..b09fecc
--- /dev/null
+++ b/springloaded/springloaded tests (no generated tests) (1.8).launch
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java b/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java
index a51b3ef..7d6102e 100644
--- a/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java
+++ b/springloaded/src/main/java/org/springsource/loaded/ClassRenamer.java
@@ -18,11 +18,10 @@ package org.springsource.loaded;
import java.util.HashMap;
import java.util.Map;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -54,7 +53,7 @@ public class ClassRenamer {
return renamed;
}
- static class RenameAdapter extends ClassAdapter implements Opcodes {
+ static class RenameAdapter extends ClassVisitor implements Opcodes {
private ClassWriter cw;
private String oldname;
@@ -62,7 +61,7 @@ public class ClassRenamer {
private Map retargets = new HashMap();
public RenameAdapter(String newname, String[] retargets) {
- super(new ClassWriter(0));
+ super(ASM5,new ClassWriter(0));
cw = (ClassWriter) cv;
this.newname = newname.replace('.', '/');
if (retargets != null) {
@@ -141,13 +140,13 @@ public class ClassRenamer {
return super.visitField(access, name, desc, signature, value);
}
- class RenameMethodAdapter extends MethodAdapter implements Opcodes {
+ class RenameMethodAdapter extends MethodVisitor implements Opcodes {
String oldname;
String newname;
public RenameMethodAdapter(MethodVisitor mv, String oldname, String newname) {
- super(mv);
+ super(ASM5,mv);
this.oldname = oldname;
this.newname = newname;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/Constants.java b/springloaded/src/main/java/org/springsource/loaded/Constants.java
index 24ea275..22b49c1 100644
--- a/springloaded/src/main/java/org/springsource/loaded/Constants.java
+++ b/springloaded/src/main/java/org/springsource/loaded/Constants.java
@@ -81,6 +81,7 @@ public interface Constants extends Opcodes {
static String mChangedForInvokeInterfaceName = "iincheck";
static String mChangedForInvokeVirtualName = "ivicheck";
static String mChangedForInvokeSpecialName = "ispcheck";
+ static String mPerformInvokeDynamicName = "idyrun";
static String descriptorChangedForInvokeSpecialName = "(ILjava/lang/String;)Lorg/springsource/loaded/__DynamicallyDispatchable;";
static String mChangedForConstructorName = "ccheck";
@@ -103,6 +104,7 @@ public interface Constants extends Opcodes {
static int ACC_PUBLIC_PROTECTED = Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED;
static int ACC_PUBLIC_PRIVATE_PROTECTED = Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED;
+ static int ACC_PRIVATE_STATIC_SYNTHETIC = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC;
static int ACC_PRIVATE_PROTECTED = Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED;
static int ACC_PRIVATE_STATIC_FINAL = ACC_FINAL | ACC_STATIC | ACC_PRIVATE;
diff --git a/springloaded/src/main/java/org/springsource/loaded/ConstructorCopier.java b/springloaded/src/main/java/org/springsource/loaded/ConstructorCopier.java
index 323c309..bb398c1 100644
--- a/springloaded/src/main/java/org/springsource/loaded/ConstructorCopier.java
+++ b/springloaded/src/main/java/org/springsource/loaded/ConstructorCopier.java
@@ -16,14 +16,13 @@
package org.springsource.loaded;
import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
/**
* @author Andy Clement
* @since 0.5.0
*/
-class ConstructorCopier extends MethodAdapter implements Constants {
+class ConstructorCopier extends MethodVisitor implements Constants {
private final static int preInvokeSpecial = 0;
private final static int postInvokeSpecial = 1;
@@ -39,7 +38,7 @@ class ConstructorCopier extends MethodAdapter implements Constants {
private String classname;
public ConstructorCopier(MethodVisitor mv, TypeDescriptor typeDescriptor, String suffix, String classname) {
- super(mv);
+ super(ASM5,mv);
this.typeDescriptor = typeDescriptor;
this.suffix = suffix;
this.classname = classname;
diff --git a/springloaded/src/main/java/org/springsource/loaded/DispatcherBuilder.java b/springloaded/src/main/java/org/springsource/loaded/DispatcherBuilder.java
index 045bd45..16a175d 100644
--- a/springloaded/src/main/java/org/springsource/loaded/DispatcherBuilder.java
+++ b/springloaded/src/main/java/org/springsource/loaded/DispatcherBuilder.java
@@ -57,7 +57,7 @@ public class DispatcherBuilder {
/**
* Whilst visiting the interface, the implementation is created.
*/
- static class DispatcherBuilderVisitor implements ClassVisitor, Opcodes, Constants {
+ static class DispatcherBuilderVisitor extends ClassVisitor implements Opcodes, Constants {
private ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
@@ -68,6 +68,7 @@ public class DispatcherBuilder {
private IncrementalTypeDescriptor typeDescriptor;
public DispatcherBuilderVisitor(ReloadableType rtype, IncrementalTypeDescriptor typeDescriptor, String suffix) {
+ super(ASM5);
this.classname = rtype.getSlashedName();
this.typeDescriptor = typeDescriptor;
this.suffix = suffix;
diff --git a/springloaded/src/main/java/org/springsource/loaded/EmptyClassVisitor.java b/springloaded/src/main/java/org/springsource/loaded/EmptyClassVisitor.java
index a21d72c..d2024fa 100644
--- a/springloaded/src/main/java/org/springsource/loaded/EmptyClassVisitor.java
+++ b/springloaded/src/main/java/org/springsource/loaded/EmptyClassVisitor.java
@@ -27,7 +27,11 @@ import org.objectweb.asm.MethodVisitor;
* @author Andy Clement
* @since 0.7.3
*/
-public class EmptyClassVisitor implements ClassVisitor, Constants {
+public class EmptyClassVisitor extends ClassVisitor implements Constants {
+
+ public EmptyClassVisitor() {
+ super(ASM5);
+ }
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java b/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java
index 29737f5..a7efa70 100644
--- a/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java
+++ b/springloaded/src/main/java/org/springsource/loaded/ExecutorBuilder.java
@@ -69,7 +69,7 @@ public class ExecutorBuilder {
* ClassVisitor that constructs the executor by visiting the original class. The basic goal is to visit the original class and
* 'copy' the methods into the executor, making adjustments as we go.
*/
- static class ExecutorBuilderVisitor implements ClassVisitor, Constants {
+ static class ExecutorBuilderVisitor extends ClassVisitor implements Constants {
private ClassWriter cw = new ClassWriter(0);
@@ -78,6 +78,7 @@ public class ExecutorBuilder {
protected TypeDescriptor typeDescriptor;
public ExecutorBuilderVisitor(String classname, String suffix, TypeDescriptor typeDescriptor) {
+ super(ASM5);
this.classname = classname;
this.suffix = suffix;
this.typeDescriptor = typeDescriptor;
@@ -145,11 +146,12 @@ public class ExecutorBuilder {
cw.visitSource(sourcefile, debug);
}
- private static class CopyingAnnotationVisitor implements AnnotationVisitor {
+ private static class CopyingAnnotationVisitor extends AnnotationVisitor {
private AnnotationVisitor av;
public CopyingAnnotationVisitor(AnnotationVisitor av) {
+ super(ASM5);
this.av = av;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/InterfaceExtractor.java b/springloaded/src/main/java/org/springsource/loaded/InterfaceExtractor.java
index d00e467..e7d09a0 100644
--- a/springloaded/src/main/java/org/springsource/loaded/InterfaceExtractor.java
+++ b/springloaded/src/main/java/org/springsource/loaded/InterfaceExtractor.java
@@ -66,13 +66,14 @@ public class InterfaceExtractor {
return extractorVisitor.getBytes();
}
- class ExtractorVisitor implements ClassVisitor, Constants {
+ class ExtractorVisitor extends ClassVisitor implements Constants {
private TypeDescriptor typeDescriptor;
private ClassWriter interfaceWriter = new ClassWriter(0);
private String slashedtypename;
public ExtractorVisitor(TypeDescriptor typeDescriptor) {
+ super(ASM5);
this.typeDescriptor = typeDescriptor;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/MethodCopier.java b/springloaded/src/main/java/org/springsource/loaded/MethodCopier.java
index 3d048a2..6505103 100644
--- a/springloaded/src/main/java/org/springsource/loaded/MethodCopier.java
+++ b/springloaded/src/main/java/org/springsource/loaded/MethodCopier.java
@@ -16,7 +16,6 @@
package org.springsource.loaded;
import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.springsource.loaded.Utils.ReturnType;
@@ -26,7 +25,7 @@ import org.springsource.loaded.Utils.ReturnType;
* @author Andy Clement
* @since 0.5.0
*/
-class MethodCopier extends MethodAdapter implements Constants {
+class MethodCopier extends MethodVisitor implements Constants {
private boolean isInterface;
private String descriptor;
@@ -37,7 +36,7 @@ class MethodCopier extends MethodAdapter implements Constants {
public MethodCopier(MethodVisitor mv, boolean isInterface, String descriptor, TypeDescriptor typeDescriptor, String classname,
String suffix) {
- super(mv);
+ super(ASM5,mv);
this.isInterface = isInterface;
this.descriptor = descriptor;
this.typeDescriptor = typeDescriptor;
diff --git a/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java b/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java
index 1466783..b46d851 100644
--- a/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java
+++ b/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java
@@ -30,13 +30,12 @@ import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.logging.Logger;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.springsource.loaded.ConstantPoolChecker2.References;
@@ -436,7 +435,7 @@ public class MethodInvokerRewriter {
static class DontRewriteException extends RuntimeException {
}
- static class RewriteClassAdaptor extends ClassAdapter implements Opcodes {
+ static class RewriteClassAdaptor extends ClassVisitor implements Opcodes {
private ClassVisitor cw;
@@ -667,14 +666,14 @@ public class MethodInvokerRewriter {
return intercepted.contains(owner + "." + methodName);
}
- private TypeRegistry typeRegistry;
+ protected TypeRegistry typeRegistry;
boolean isEnum = false;
private boolean isGroovyClosure = false;
int fieldcount = 0;
public RewriteClassAdaptor(TypeRegistry typeRegistry, ClassVisitor classWriter) {
// TODO should it also compute frames?
- super(classWriter);
+ super(ASM5,classWriter);
cw = cv;
this.typeRegistry = typeRegistry;
}
@@ -691,7 +690,7 @@ public class MethodInvokerRewriter {
public ClassVisitor getClassVisitor() {
return cv;
}
-
+
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
@@ -721,7 +720,7 @@ public class MethodInvokerRewriter {
return new RewritingMethodAdapter(mv, name);
}
- class RewritingMethodAdapter extends MethodAdapter implements Opcodes, Constants {
+ class RewritingMethodAdapter extends MethodVisitor implements Opcodes, Constants {
// tracks max variable used in a method so we know what we can use
// safely
@@ -731,7 +730,7 @@ public class MethodInvokerRewriter {
private boolean isClinitOrEnumInit = false;
public RewritingMethodAdapter(MethodVisitor mv, String methodname) {
- super(mv);
+ super(ASM5,mv);
this.methodname = methodname;
if (isEnum) {
isClinitOrEnumInit = this.methodname.length() > 2 && this.methodname.charAt(0) == '<'
@@ -950,6 +949,123 @@ public class MethodInvokerRewriter {
super.visitTypeInsn(opcode, type);
}
+ private String toString(Handle handle) {
+ return "handle(tag="+handle.getTag()+",name="+handle.getName()+",desc="+handle.getDesc()+",owner="+handle.getOwner();
+ }
+ private String toString(Object[] oa) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("[");
+ if (oa!=null) {
+ for (Object o:oa) {
+ buf.append(" ");
+ buf.append(o);
+ }
+ }
+ buf.append("]");
+ return buf.toString();
+ }
+
+ @Override
+ public void visitInvokeDynamicInsn(String name, String desc, org.objectweb.asm.Handle bsm, Object... bsmArgs) {
+ // TODO *shudder* what about invoke dynamic calls that target reflective APIs
+ boolean handled = false;
+ // TODO Perhaps (for sake of my sanity initially) make a distinction here between the general invokedynamic case and the special lambda support case?
+
+ // name=m
+ // desc=()Lbasic/LambdaA2$Foo;
+ // bsm=handle(tag=6,
+ // name=metafactory,
+ // desc=(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;,
+ // owner=java/lang/invoke/LambdaMetafactory
+ // bsmArgs=[ ()I basic/LambdaA2.lambda$run$1()I (6) ()I]
+ if (bsm.getTag()==H_INVOKESTATIC) {
+// InvokeDynamic(name=m,desc=()Lbasic/LambdaA$Foo;,bsm=handle(tag=6,name=metafactory,desc=(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;,owner=java/lang/invoke/LambdaMetafactory,bsmArgs=[ ()I basic/LambdaA.lambda$run$0()I (6) ()I]
+ System.out.println("InvokeDynamic(name="+name+",desc="+desc+",bsm="+toString(bsm)+",bsmArgs="+toString(bsmArgs));
+ // The other invokes use the 'owner' of the target method to determine which type registry should be part of this
+ // check. Here the 'owner' is wrapped up in the bootstrap method - as version 1 we can assume the owner is the lambdametafactory
+ // which *wont* be getting reloaded - so we already know we don't need to do some jiggery pokery.
+
+// int classId = typeRegistry.getTypeIdFor(owner, true);
+ // Call type registry to determine 'can we do what we were going to do?'
+
+ int bsmReferenceId = typeRegistry.recordBootstrapMethod(bsm,bsmArgs);
+ // Method java/lang/invoke/MethodHandles.lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
+ mv.visitMethodInsn(INVOKESTATIC,"java/lang/invoke/MethodHandles","lookup","()Ljava/lang/invoke/MethodHandles$Lookup;");
+ mv.visitLdcInsn(name+desc); // Ljava/lang/String;
+ mv.visitLdcInsn(bsmReferenceId); // I
+ mv.visitMethodInsn(INVOKESTATIC, tRegistryType, mPerformInvokeDynamicName, "(Ljava/lang/Object;Ljava/lang/String;I)Ljava/lang/Object;");
+ handled=true;
+ // TODO handle return type
+// mv.visitLdcInsn(Utils.toCombined(typeRegistry.getId(),classId));
+// mv.visitLdcInsn(name+desc);
+// mv.visitLdcInsn(BSM_NUMBER);
+// mv.visitLdcInsn(bsmArgs);
+
+
+
+// // What can we check to see whether it is necessary to intercept this call? Is it the return type of the descriptor? (For when
+// // the bsm is recognizable as for lambda support)
+// mv.visitLdcInsn(Utils.toCombined(typeRegistry.getId(), classId));
+// mv.visitLdcInsn(name + desc);
+// mv.visitMethodInsn(INVOKESTATIC, tRegistryType, mChangedForInvokeVirtualName, "(ILjava/lang/String;)Z");
+// // Return value is the extracted interface to call if there is a
+// // change and it can't be called directly
+//
+// // 2. preserve a copy of the return value (new target)
+// // mv.visitInsn(DUP);
+//
+// // 3. Was it null?
+// Label l1 = new Label();
+// mv.visitJumpInsn(IFEQ, l1);
+//
+// // 4. Not false
+//
+// // 5. Store the target implementation of the interface that we
+// // will invoke later
+// // mv.visitVarInsn(ASTORE, max + 1);
+//
+// // 6. Package up any parameters
+// if (hasParams) {
+// Utils.collapseStackToArray(mv, desc);
+// }
+//
+// // Prepare for the invocation:
+// if (!hasParams) {
+// // [targetInstance]
+// mv.visitInsn(DUP);
+// mv.visitInsn(ACONST_NULL); // no parameters
+// mv.visitInsn(SWAP); // [targetInstance NULL targetInstance]
+// } else {
+// // [targetInstance paramArray]
+// mv.visitInsn(SWAP);
+// mv.visitInsn(DUP_X1); // [targetInstance paramArray
+// // targetInstance]
+// }
+//
+// mv.visitLdcInsn(name + desc);
+//
+// // calling __execute(params array,this,name+desc)
+// mv.visitMethodInsn(INVOKEVIRTUAL, owner, mDynamicDispatchName, mDynamicDispatchDescriptor);
+//
+// insertAppropriateReturn(returnType);
+// Label gotolabel = new Label();
+// mv.visitJumpInsn(GOTO, gotolabel);
+// mv.visitLabel(l1);
+// // mv.visitInsn(POP);
+// // Here is where we end up if the test for changes failed (ie.
+// // there were no changes - just 'do what you were going to do'
+// super.visitMethodInsn(opcode, owner, name, desc);
+// mv.visitLabel(gotolabel);
+
+ }
+ else {
+ // TODO handle it!
+ }
+ if (!handled) {
+ super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ }
+ }
+
@Override
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
if (GlobalConfiguration.interceptReflection && rewriteReflectiveCall(opcode, owner, name, desc)) {
diff --git a/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java b/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java
index 2fca034..a0ab008 100644
--- a/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java
+++ b/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java
@@ -31,8 +31,8 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.springsource.loaded.MethodInvokerRewriter.DontRewriteException;
import org.springsource.loaded.MethodInvokerRewriter.RewriteClassAdaptor;
@@ -839,10 +839,10 @@ public class ReloadableType {
}
}
- static class ChainedAdapters extends ClassAdapter implements Constants {
+ static class ChainedAdapters extends ClassVisitor implements Constants {
public ChainedAdapters(ReloadableType rtype) {
- super(new RewriteClassAdaptor(rtype.typeRegistry, new TypeRewriter.RewriteClassAdaptor(rtype, new ClassWriter(
+ super(ASM5,new RewriteClassAdaptor(rtype.typeRegistry, new TypeRewriter.RewriteClassAdaptor(rtype, new ClassWriter(
ClassWriter.COMPUTE_MAXS))));
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java b/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java
index 415e8c0..7684c89 100644
--- a/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java
+++ b/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java
@@ -15,10 +15,9 @@
*/
package org.springsource.loaded;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -39,7 +38,7 @@ public class SystemClassReflectionInvestigator {
return classAdaptor.hitCount;
}
- static class RewriteClassAdaptor extends ClassAdapter implements Constants {
+ static class RewriteClassAdaptor extends ClassVisitor implements Constants {
int hitCount = 0;
private ClassWriter cw;
@@ -52,7 +51,7 @@ public class SystemClassReflectionInvestigator {
public RewriteClassAdaptor() {
// TODO should it also compute frames?
- super(new ClassWriter(ClassWriter.COMPUTE_MAXS));
+ super(ASM5,new ClassWriter(ClassWriter.COMPUTE_MAXS));
cw = (ClassWriter) cv;
}
@@ -77,10 +76,10 @@ public class SystemClassReflectionInvestigator {
return new RewritingMethodAdapter(mv);
}
- class RewritingMethodAdapter extends MethodAdapter implements Opcodes, Constants {
+ class RewritingMethodAdapter extends MethodVisitor implements Opcodes, Constants {
public RewritingMethodAdapter(MethodVisitor mv) {
- super(mv);
+ super(ASM5,mv);
}
private boolean interceptReflection(String owner, String name, String desc) {
diff --git a/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionRewriter.java b/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionRewriter.java
index 63c4285..127655a 100644
--- a/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionRewriter.java
+++ b/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionRewriter.java
@@ -18,12 +18,11 @@ package org.springsource.loaded;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -105,7 +104,7 @@ public class SystemClassReflectionRewriter {
}
}
- static class RewriteClassAdaptor extends ClassAdapter implements Constants {
+ static class RewriteClassAdaptor extends ClassVisitor implements Constants {
private ClassWriter cw;
int bits = 0x0000;
@@ -122,7 +121,7 @@ public class SystemClassReflectionRewriter {
public RewriteClassAdaptor() {
// TODO should it also compute frames?
- super(new ClassWriter(ClassWriter.COMPUTE_MAXS));
+ super(ASM5,new ClassWriter(ClassWriter.COMPUTE_MAXS));
cw = (ClassWriter) cv;
}
@@ -189,10 +188,10 @@ public class SystemClassReflectionRewriter {
}
}
- class RewritingMethodAdapter extends MethodAdapter implements Opcodes, Constants {
+ class RewritingMethodAdapter extends MethodVisitor implements Opcodes, Constants {
public RewritingMethodAdapter(MethodVisitor mv) {
- super(mv);
+ super(ASM5,mv);
}
/**
diff --git a/springloaded/src/main/java/org/springsource/loaded/TypeDescriptorExtractor.java b/springloaded/src/main/java/org/springsource/loaded/TypeDescriptorExtractor.java
index 2c37f53..3428cdc 100644
--- a/springloaded/src/main/java/org/springsource/loaded/TypeDescriptorExtractor.java
+++ b/springloaded/src/main/java/org/springsource/loaded/TypeDescriptorExtractor.java
@@ -54,7 +54,7 @@ public class TypeDescriptorExtractor {
/**
* Visit a class and accumulate sufficient information to build a TypeDescriptor.
*/
- class ExtractionVisitor implements ClassVisitor, Opcodes {
+ class ExtractionVisitor extends ClassVisitor implements Opcodes {
private boolean isReloadableType;
private int flags;
@@ -72,6 +72,7 @@ public class TypeDescriptorExtractor {
private List finalInHierarchy = new ArrayList();
public ExtractionVisitor(boolean isReloadableType) {
+ super(ASM5);
this.isReloadableType = isReloadableType;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/TypeRegistry.java b/springloaded/src/main/java/org/springsource/loaded/TypeRegistry.java
index ef9753e..9b51810 100644
--- a/springloaded/src/main/java/org/springsource/loaded/TypeRegistry.java
+++ b/springloaded/src/main/java/org/springsource/loaded/TypeRegistry.java
@@ -15,6 +15,8 @@
*/
package org.springsource.loaded;
+import j8code.J8Helper;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -42,6 +44,7 @@ import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.objectweb.asm.Handle;
import org.springsource.loaded.agent.FileSystemWatcher;
import org.springsource.loaded.agent.ReloadDecision;
import org.springsource.loaded.agent.ReloadableFileChangeListener;
@@ -1459,7 +1462,25 @@ public class TypeRegistry {
}
return false;
}
+
+ @UsedByGeneratedCode
+ public static Object idyrun(Object methodHandles_lookup, String nameAndDescriptor, int bsmId) {
+ // bsmId = 0
+ // nameAndDescriptor = m()Lbasic/LambdaA$Foo;
+// 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
+
+
+ System.out.println("idyrun("+methodHandles_lookup+","+nameAndDescriptor+","+bsmId+")");
+ return J8Helper.simulateInvokeDynamic(methodHandles_lookup);
+ }
+
/**
* Used in code the generated code replaces invokevirtual calls. Determine if the code can run as it was originally compiled.
*
@@ -1856,4 +1877,36 @@ public class TypeRegistry {
public Set getJDKProxiesFor(String slashedInterfaceTypeName) {
return jdkProxiesForInterface.get(slashedInterfaceTypeName);
}
+
+
+ /**
+ * When an invokedynamic instruction is reached, we allocate an id that
+ * recognizes that bsm and the parameters to that bsm. The index can be
+ * used when rewriting that invokedynamic
+ *
+ * @return id that represents this bootstrap method usage
+ */
+ public synchronized int recordBootstrapMethod(Handle bsm, Object[] bsmArgs) {
+ // TODO [memory] search the existing bsmInfos for a matching one! Reuse!
+ if (nextBsmIndex >= bsmInfo.length) {
+ BsmInfo[] newarray = new BsmInfo[bsmInfo.length+4];
+ System.arraycopy(bsmInfo, 0, newarray, 0, bsmInfo.length);
+ bsmInfo = newarray;
+ }
+ bsmInfo[nextBsmIndex] = new BsmInfo(bsm,bsmArgs);
+ nextBsmIndex++;
+ return nextBsmIndex-1;
+ }
+
+ private int nextBsmIndex = 0;
+ private BsmInfo[] bsmInfo = new BsmInfo[4];
+
+ static class BsmInfo {
+ Handle bsm;
+ Object[] bsmArgs;
+ public BsmInfo(Handle bsm, Object[] bsmArgs) {
+ this.bsm = bsm;
+ this.bsmArgs = bsmArgs;
+ }
+ }
}
\ No newline at end of file
diff --git a/springloaded/src/main/java/org/springsource/loaded/TypeRewriter.java b/springloaded/src/main/java/org/springsource/loaded/TypeRewriter.java
index 327df49..f8a7bd0 100644
--- a/springloaded/src/main/java/org/springsource/loaded/TypeRewriter.java
+++ b/springloaded/src/main/java/org/springsource/loaded/TypeRewriter.java
@@ -19,13 +19,11 @@ import java.lang.reflect.Modifier;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.springsource.loaded.Utils.ReturnType;
@@ -55,7 +53,7 @@ public class TypeRewriter implements Constants {
return classAdaptor.getBytes();
}
- static class RewriteClassAdaptor extends ClassAdapter implements Constants {
+ static class RewriteClassAdaptor extends ClassVisitor implements Constants {
private ClassWriter cw;
private String slashedname;
@@ -72,7 +70,7 @@ public class TypeRewriter implements Constants {
}
public RewriteClassAdaptor(ReloadableType rtype, ClassWriter classWriter) {
- super(classWriter);
+ super(ASM5,classWriter);
this.rtype = rtype;
this.slashedname = rtype.getSlashedName();
this.cw = (ClassWriter) cv;
@@ -414,7 +412,7 @@ public class TypeRewriter implements Constants {
@Override
public MethodVisitor visitMethod(int flags, String name, String descriptor, String signature, String[] exceptions) {
- MethodVisitor mv = super.visitMethod(promoteIfNecessary(flags), name, descriptor, signature, exceptions);
+ MethodVisitor mv = super.visitMethod(promoteIfNecessary(flags,name), name, descriptor, signature, exceptions);
MethodVisitor newMethodVisitor = getMethodVisitor(name, descriptor, mv);
return newMethodVisitor;
}
@@ -444,8 +442,8 @@ public class TypeRewriter implements Constants {
}
// Default visibility elements need promotion to public so that they can be seen from the executor
- private int promoteIfNecessary(int flags) {
- int newflags = Utils.promoteDefaultOrProtectedToPublic(flags, isEnum);
+ private int promoteIfNecessary(int flags,String name) {
+ int newflags = Utils.promoteDefaultOrProtectedToPublic(flags, isEnum, name);
return newflags;
}
@@ -816,7 +814,7 @@ public class TypeRewriter implements Constants {
/**
* Rewrites a method to include the extra checks to verify it is the most up to date version.
*/
- class AugmentingMethodAdapter extends MethodAdapter implements Opcodes {
+ class AugmentingMethodAdapter extends MethodVisitor implements Opcodes {
int methodId;
String name;
@@ -825,7 +823,7 @@ public class TypeRewriter implements Constants {
ReturnType returnType;
public AugmentingMethodAdapter(MethodVisitor mv, String name, String descriptor) {
- super(mv);
+ super(ASM5,mv);
this.name = name;
this.method = rtype.getMethod(name, descriptor);
this.methodId = method.getId();
@@ -916,7 +914,7 @@ public class TypeRewriter implements Constants {
}
- class AugmentingConstructorAdapter extends MethodAdapter implements Opcodes {
+ class AugmentingConstructorAdapter extends MethodVisitor implements Opcodes {
int ctorId;
String name;
@@ -926,7 +924,7 @@ public class TypeRewriter implements Constants {
boolean isTopMost;
public AugmentingConstructorAdapter(MethodVisitor mv, String descriptor, String type, boolean isTopMost) {
- super(mv);
+ super(ASM5,mv);
this.descriptor = descriptor;
this.type = type;
this.isTopMost = isTopMost;
@@ -1053,12 +1051,12 @@ public class TypeRewriter implements Constants {
void prepend();
}
- class MethodPrepender extends MethodAdapter implements Opcodes {
+ class MethodPrepender extends MethodVisitor implements Opcodes {
Prepender appender;
public MethodPrepender(MethodVisitor mv, Prepender appender) {
- super(mv);
+ super(ASM5,mv);
this.appender = appender;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/Utils.java b/springloaded/src/main/java/org/springsource/loaded/Utils.java
index 2541ef6..ed35c0a 100644
--- a/springloaded/src/main/java/org/springsource/loaded/Utils.java
+++ b/springloaded/src/main/java/org/springsource/loaded/Utils.java
@@ -1369,7 +1369,7 @@ public class Utils implements Opcodes, Constants {
return access;
}
- public static int promoteDefaultOrProtectedToPublic(int access, boolean isEnum) {
+ public static int promoteDefaultOrProtectedToPublic(int access, boolean isEnum, String name) {
if ((access & Constants.ACC_PUBLIC_PRIVATE_PROTECTED) == 0) {
// is default
return (access | Modifier.PUBLIC);
@@ -1382,6 +1382,10 @@ public class Utils implements Opcodes, Constants {
// was private, need to 'publicize' it
return access - Constants.ACC_PRIVATE + Constants.ACC_PUBLIC;
}
+ if ((access&Constants.ACC_PRIVATE_STATIC_SYNTHETIC)==ACC_PRIVATE_STATIC_SYNTHETIC && name.startsWith("lambda")) {
+ // Special case for lambda, may need to generalize for general invokedynamic support
+ return access - Constants.ACC_PRIVATE + Constants.ACC_PUBLIC;
+ }
return access;
}
@@ -1733,7 +1737,11 @@ public class Utils implements Opcodes, Constants {
// TODO [performance] speed up by throwing exception from first visit method? (but this isn't used in the mainline really)
// TODO or just write a quicker bytecode parser that just looks at the interfaces then returns
- private static class InterfaceCollectingClassVisitor implements ClassVisitor {
+ private static class InterfaceCollectingClassVisitor extends ClassVisitor {
+
+ public InterfaceCollectingClassVisitor() {
+ super(ASM5);
+ }
public String[] interfaces;
diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java b/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java
index cd9de43..41eb180 100644
--- a/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java
+++ b/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java
@@ -19,10 +19,9 @@ import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.springsource.loaded.Constants;
@@ -33,7 +32,7 @@ import org.springsource.loaded.Constants;
* @author Andy Clement
* @since 0.8.3
*/
-public class CglibPluginCapturing extends ClassAdapter implements Constants {
+public class CglibPluginCapturing extends ClassVisitor implements Constants {
public static Map, Object[]> clazzToGeneratorStrategyAndClassGeneratorMap = new HashMap, Object[]>();
public static Map, Object[]> clazzToGeneratorStrategyAndFastClassGeneratorMap = new HashMap, Object[]>();
@@ -48,7 +47,7 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
}
private CglibPluginCapturing() {
- super(new ClassWriter(0)); // TODO review 0 here
+ super(ASM5,new ClassWriter(0)); // TODO review 0 here
}
@Override
@@ -74,10 +73,10 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
}
}
- class CreateMethodInterceptor extends MethodAdapter implements Constants {
+ class CreateMethodInterceptor extends MethodVisitor implements Constants {
public CreateMethodInterceptor(MethodVisitor mv) {
- super(mv);
+ super(ASM5,mv);
}
@Override
diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/ClassVisitingConstructorAppender.java b/springloaded/src/main/java/org/springsource/loaded/agent/ClassVisitingConstructorAppender.java
index dea4960..740ec8a 100644
--- a/springloaded/src/main/java/org/springsource/loaded/agent/ClassVisitingConstructorAppender.java
+++ b/springloaded/src/main/java/org/springsource/loaded/agent/ClassVisitingConstructorAppender.java
@@ -15,9 +15,8 @@
*/
package org.springsource.loaded.agent;
-import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.springsource.loaded.Constants;
@@ -27,7 +26,7 @@ import org.springsource.loaded.Constants;
* @author Andy Clement
* @since 0.5.0
*/
-public class ClassVisitingConstructorAppender extends ClassAdapter implements Constants {
+public class ClassVisitingConstructorAppender extends ClassVisitor implements Constants {
private String calleeOwner;
private String calleeName;
@@ -41,7 +40,7 @@ public class ClassVisitingConstructorAppender extends ClassAdapter implements Co
* @param name
*/
public ClassVisitingConstructorAppender(String owner, String name) {
- super(new ClassWriter(0)); // TODO review 0 here
+ super(ASM5,new ClassWriter(0)); // TODO review 0 here
this.calleeOwner = owner;
this.calleeName = name;
}
@@ -63,10 +62,10 @@ public class ClassVisitingConstructorAppender extends ClassAdapter implements Co
* This constructor appender includes a couple of instructions at the end of each constructor it is asked to visit. It
* recognizes the end by observing a RETURN instruction. The instructions are inserted just before the RETURN.
*/
- class ConstructorAppender extends MethodAdapter implements Constants {
+ class ConstructorAppender extends MethodVisitor implements Constants {
public ConstructorAppender(MethodVisitor mv) {
- super(mv);
+ super(ASM5,mv);
}
@Override
diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/FalseReturner.java b/springloaded/src/main/java/org/springsource/loaded/agent/FalseReturner.java
index b22029b..1cec1a7 100644
--- a/springloaded/src/main/java/org/springsource/loaded/agent/FalseReturner.java
+++ b/springloaded/src/main/java/org/springsource/loaded/agent/FalseReturner.java
@@ -15,7 +15,7 @@
*/
package org.springsource.loaded.agent;
-import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.springsource.loaded.Constants;
@@ -26,12 +26,12 @@ import org.springsource.loaded.Constants;
* @author Andy Clement
* @since 0.7.0
*/
-public class FalseReturner extends ClassAdapter implements Constants {
+public class FalseReturner extends ClassVisitor implements Constants {
private String methodname;
public FalseReturner(String methodname) {
- super(new ClassWriter(0)); // TODO review 0 here
+ super(ASM5,new ClassWriter(0)); // TODO review 0 here
this.methodname = methodname;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/ModifyDefineInClassLoaderForClassArtifactsType.java b/springloaded/src/main/java/org/springsource/loaded/agent/ModifyDefineInClassLoaderForClassArtifactsType.java
index f155e29..baa4057 100644
--- a/springloaded/src/main/java/org/springsource/loaded/agent/ModifyDefineInClassLoaderForClassArtifactsType.java
+++ b/springloaded/src/main/java/org/springsource/loaded/agent/ModifyDefineInClassLoaderForClassArtifactsType.java
@@ -15,9 +15,8 @@
*/
package org.springsource.loaded.agent;
-import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.springsource.loaded.Constants;
import org.springsource.loaded.GlobalConfiguration;
@@ -30,10 +29,10 @@ import org.springsource.loaded.TypeRegistry;
* @author Andy Clement
* @since 0.7.3
*/
-public class ModifyDefineInClassLoaderForClassArtifactsType extends ClassAdapter implements Constants {
+public class ModifyDefineInClassLoaderForClassArtifactsType extends ClassVisitor implements Constants {
public ModifyDefineInClassLoaderForClassArtifactsType() {
- super(new ClassWriter(0)); // TODO review 0 here
+ super(ASM5,new ClassWriter(0)); // TODO review 0 here
}
public byte[] getBytes() {
@@ -49,10 +48,10 @@ public class ModifyDefineInClassLoaderForClassArtifactsType extends ClassAdapter
}
}
- class DefineClassModifierVisitor extends MethodAdapter implements Constants {
+ class DefineClassModifierVisitor extends MethodVisitor implements Constants {
public DefineClassModifierVisitor(MethodVisitor mv) {
- super(mv);
+ super(ASM5,mv);
}
@Override
diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/NonFinalizer.java b/springloaded/src/main/java/org/springsource/loaded/agent/NonFinalizer.java
index 24d6e15..0ede959 100644
--- a/springloaded/src/main/java/org/springsource/loaded/agent/NonFinalizer.java
+++ b/springloaded/src/main/java/org/springsource/loaded/agent/NonFinalizer.java
@@ -17,7 +17,7 @@ package org.springsource.loaded.agent;
import java.lang.reflect.Modifier;
-import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.springsource.loaded.Constants;
@@ -29,7 +29,7 @@ import org.springsource.loaded.Constants;
* @author Andy Clement
* @since 0.7.0
*/
-public class NonFinalizer extends ClassAdapter implements Constants {
+public class NonFinalizer extends ClassVisitor implements Constants {
private String fieldname;
@@ -42,7 +42,7 @@ public class NonFinalizer extends ClassAdapter implements Constants {
* @param name
*/
public NonFinalizer(String fieldname) {
- super(new ClassWriter(0)); // TODO review 0 here
+ super(ASM5,new ClassWriter(0)); // TODO review 0 here
this.fieldname = fieldname;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/pluginhelpers/EmptyCtor.java b/springloaded/src/main/java/org/springsource/loaded/pluginhelpers/EmptyCtor.java
index 2a2542b..3328a08 100644
--- a/springloaded/src/main/java/org/springsource/loaded/pluginhelpers/EmptyCtor.java
+++ b/springloaded/src/main/java/org/springsource/loaded/pluginhelpers/EmptyCtor.java
@@ -17,8 +17,8 @@ package org.springsource.loaded.pluginhelpers;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -32,7 +32,7 @@ import org.springsource.loaded.test.infra.ClassPrinter;
* @author Andy Clement
* @since 0.8.3
*/
-public class EmptyCtor extends ClassAdapter implements Constants {
+public class EmptyCtor extends ClassVisitor implements Constants {
private String[] descriptors;
@@ -52,7 +52,7 @@ public class EmptyCtor extends ClassAdapter implements Constants {
}
private EmptyCtor(String... descriptors) {
- super(new ClassWriter(0)); // TODO review 0 here
+ super(ASM5,new ClassWriter(0)); // TODO review 0 here
this.descriptors = descriptors;
}
@@ -80,11 +80,12 @@ public class EmptyCtor extends ClassAdapter implements Constants {
}
}
- static class Emptier implements MethodVisitor, Constants {
+ static class Emptier extends MethodVisitor implements Constants {
MethodVisitor mv;
public Emptier(MethodVisitor mv) {
+ super(ASM5);
this.mv = mv;
}
diff --git a/springloaded/src/main/java/org/springsource/loaded/test/infra/ClassPrinter.java b/springloaded/src/main/java/org/springsource/loaded/test/infra/ClassPrinter.java
index 204d2e3..e9de0a3 100644
--- a/springloaded/src/main/java/org/springsource/loaded/test/infra/ClassPrinter.java
+++ b/springloaded/src/main/java/org/springsource/loaded/test/infra/ClassPrinter.java
@@ -32,7 +32,7 @@ import org.springsource.loaded.Utils;
/**
* @author Andy Clement
*/
-public class ClassPrinter implements ClassVisitor, Opcodes {
+public class ClassPrinter extends ClassVisitor implements Opcodes {
private PrintStream destination;
private boolean includeBytecode;
@@ -47,6 +47,7 @@ public class ClassPrinter implements ClassVisitor, Opcodes {
}
public ClassPrinter(PrintStream destination, boolean includeBytecode) {
+ super(ASM5);
this.destination = destination;
this.includeBytecode = includeBytecode;
}
@@ -188,7 +189,11 @@ public class ClassPrinter implements ClassVisitor, Opcodes {
return new AnnotationVisitorPrinter();
}
- class AnnotationVisitorPrinter implements AnnotationVisitor {
+ class AnnotationVisitorPrinter extends AnnotationVisitor {
+
+ public AnnotationVisitorPrinter() {
+ super(ASM5);
+ }
public void visit(String name, Object value) {
destination.print(name + "=" + value + " ");
diff --git a/springloaded/src/main/java/org/springsource/loaded/test/infra/MethodPrinter.java b/springloaded/src/main/java/org/springsource/loaded/test/infra/MethodPrinter.java
index 04121be..2f464c5 100644
--- a/springloaded/src/main/java/org/springsource/loaded/test/infra/MethodPrinter.java
+++ b/springloaded/src/main/java/org/springsource/loaded/test/infra/MethodPrinter.java
@@ -21,17 +21,17 @@ import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.springsource.loaded.Utils;
-
/**
*
* @author Andy Clement
*/
-public class MethodPrinter implements MethodVisitor, Opcodes {
+public class MethodPrinter extends MethodVisitor implements Opcodes {
PrintStream to;
@@ -47,12 +47,22 @@ public class MethodPrinter implements MethodVisitor, Opcodes {
}
public MethodPrinter(PrintStream destination) {
+ super(ASM5);
this.to = destination;
}
public void visitCode() {
to.print(" CODE\n");
}
+
+ @Override
+ public void visitInvokeDynamicInsn(String name, String desc, org.objectweb.asm.Handle bsm, Object... bsmArgs) {
+ to.println(" INVOKEDYNAMIC " + name+"."+desc+" bsm="+toString(bsm));
+ }
+
+ private String toString(Handle bsm) {
+ return "#"+bsm.getTag()+" "+bsm.getOwner()+"."+bsm.getName()+bsm.getDesc();
+ }
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.INVOKESTATIC) {
@@ -75,7 +85,11 @@ public class MethodPrinter implements MethodVisitor, Opcodes {
return new AnnotationVisitorPrinter();
}
- class AnnotationVisitorPrinter implements AnnotationVisitor {
+ class AnnotationVisitorPrinter extends AnnotationVisitor {
+
+ public AnnotationVisitorPrinter() {
+ super(ASM5);
+ }
public void visit(String name, Object value) {
to.print(name + "=" + value + " ");
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java b/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java
index 7ec24d1..def4722 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/ExecutorBuilderTests.java
@@ -296,8 +296,22 @@ public class ExecutorBuilderTests extends SpringLoadedTests {
checkAnnotations(rtype.getLatestExecutorBytes(), "m2(Lexecutor/I;)V", "@common.Marker()", "@common.Anno(id=abc)");
Method m = rtype.getLatestExecutorClass().getDeclaredMethod("m2", rtype.getClazz());
assertEquals("@common.Marker()", m.getAnnotations()[0].toString());
- assertEquals("@common.Anno(someValue=37, longValue=2, id=abc)", m.getAnnotations()[1].toString());
+ assertEquals("@common.Anno(someValue=37, longValue=2, id=abc)", printAnnotation(m.getAnnotations()[1]));
}
+//
+ private String printAnnotation(Annotation a) {
+ return a.toString();
+// StringBuilder buf = new StringBuilder();
+// printAnnotationHelper(buf,a);
+// return buf.toString();
+ }
+//
+// private void printAnnotationHelper(StringBuilder buf, Annotation a) {
+// Class> clazz = a.annotationType();a.toString()
+// clazz.getDeclaredFields()[0].get
+// System.out.println(a.annotationType());
+//
+// }
@Test
public void methodLevelAnnotationsOnInterfaces2() throws Exception {
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/Java8Tests.java b/springloaded/src/test/java/org/springsource/loaded/test/Java8Tests.java
new file mode 100644
index 0000000..dea5524
--- /dev/null
+++ b/springloaded/src/test/java/org/springsource/loaded/test/Java8Tests.java
@@ -0,0 +1,150 @@
+package org.springsource.loaded.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.springsource.loaded.ReloadableType;
+import org.springsource.loaded.TypeRegistry;
+import org.springsource.loaded.test.infra.ClassPrinter;
+import org.springsource.loaded.test.infra.Result;
+
+/**
+ * Test reloading of Java 8.
+ *
+ * @author Andy Clement
+ * @since 1.1.5
+ */
+public class Java8Tests extends SpringLoadedTests {
+
+ @Test
+ public void theBasics() {
+ String t = "basic.FirstClass";
+ TypeRegistry typeRegistry = getTypeRegistry(t);
+ byte[] sc = loadBytesForClass(t);
+ ReloadableType rtype = new ReloadableType(t, sc, 1, typeRegistry, null);
+
+ assertEquals(1, rtype.getId());
+ assertEquals(t, rtype.getName());
+ assertEquals(slashed(t), rtype.getSlashedName());
+ assertNotNull(rtype.getTypeDescriptor());
+ assertEquals(typeRegistry, rtype.getTypeRegistry());
+ }
+
+ @Test
+ public void callBasicType() throws Exception {
+ String t = "basic.FirstClass";
+ 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(8, r.returnValue);
+
+ rtype.loadNewVersion("002", rtype.bytesInitial);
+
+ r = runUnguarded(simpleClass, "run");
+ assertEquals(8, r.returnValue);
+ }
+
+ @Test
+ public void lambdaA() throws Exception {
+ String t = "basic.LambdaA";
+ 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(77, r.returnValue);
+ ClassPrinter.print(rtype.bytesLoaded);
+
+ rtype.loadNewVersion("002", rtype.bytesInitial);
+ r = runUnguarded(simpleClass, "run");
+ assertEquals(77, r.returnValue);
+ }
+
+ @Test
+ public void changingALambda() throws Exception {
+ String t = "basic.LambdaA";
+ TypeRegistry typeRegistry = getTypeRegistry(t);
+ byte[] sc = loadBytesForClass(t);
+ 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"));
+ ClassPrinter.print(rtype.getLatestExecutorBytes());
+ r = runUnguarded(simpleClass, "run");
+ assertEquals(77, 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.
+
+ // 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
+
+ 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));
+ }
+ }
+*/
+
+
+
+
+ // --
+
+ private String slashed(String dotted) {
+ return dotted.replaceAll("\\.", "/");
+ }
+}
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/JavaMicroBenchmarkTests.java b/springloaded/src/test/java/org/springsource/loaded/test/JavaMicroBenchmarkTests.java
index 5a6ebbf..546c569 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/JavaMicroBenchmarkTests.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/JavaMicroBenchmarkTests.java
@@ -53,14 +53,6 @@ public class JavaMicroBenchmarkTests extends SpringLoadedTests {
average(rtype, 5);
}
- private void pause(int seconds) {
- System.out.println("waiting...");
- try {
- Thread.sleep(seconds * 1000);
- } catch (Exception e) {
- }
- }
-
// TODO fibonacci
private void average(ReloadableType rtype, int count) throws Exception {
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java b/springloaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java
index 6608cb8..d0bc365 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java
@@ -205,7 +205,7 @@ public class ReloadableTypeTests extends SpringLoadedTests {
@Test
public void invokeStaticReloading_gh4_2() throws Exception {
TypeRegistry tr = getTypeRegistry("invokestatic..*");
- ReloadableType AA = tr.addType("invokestatic.issue4.AA", loadBytesForClass("invokestatic.issue4.AA"));
+ tr.addType("invokestatic.issue4.AA", loadBytesForClass("invokestatic.issue4.AA"));
ReloadableType BB = tr.addType("invokestatic.issue4.BB", loadBytesForClass("invokestatic.issue4.BB"));
Result r = runUnguarded(BB.getClazz(), "getMessage");
@@ -272,7 +272,7 @@ public class ReloadableTypeTests extends SpringLoadedTests {
@Test
public void invokeStaticReloading_gh4_6() throws Exception {
TypeRegistry tr = getTypeRegistry("invokestatic.issue4..*");
- ReloadableType AB = tr.addType("invokestatic.issue4.AB", loadBytesForClass("invokestatic.issue4.AB"));
+ tr.addType("invokestatic.issue4.AB", loadBytesForClass("invokestatic.issue4.AB"));
ReloadableType B = tr.addType("invokestatic.issue4.BBBBB", loadBytesForClass("invokestatic.issue4.BBBBB"));
Result r = runUnguarded(B.getClazz(), "getMessage");
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/ReloadingJVM.java b/springloaded/src/test/java/org/springsource/loaded/test/ReloadingJVM.java
index 525580c..5324de6 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/ReloadingJVM.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/ReloadingJVM.java
@@ -236,6 +236,25 @@ public class ReloadingJVM {
}
Utils.write(new File(testdataDirectory,classfile),data);
}
+
+ public void clearTestdataDirectory() {
+ File[] fs = testdataDirectory.listFiles();
+ for (File f: fs) {
+ delete(f);
+ }
+ }
+
+ private void delete(File toDelete) {
+ if (toDelete.isDirectory()) {
+ File[] fs = toDelete.listFiles();
+ for (File f: fs) {
+ delete(f);
+ }
+ }
+ else {
+ toDelete.delete();
+ }
+ }
public JVMOutput newInstance(String instanceName, String classname) {
copyToTestdataDirectory(classname);
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java b/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java
index 2cc8df1..9b14528 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java
@@ -97,7 +97,7 @@ public abstract class SpringLoadedTests implements Constants {
protected String CodeJar = "../testdata/code.jar";
// TODO [java8] replace this with project dependency when Java8 is out
protected String Java8CodeJar = "../testdata-java8/build/libs/testdata-java8.jar";
- protected String GroovyrtJar = "../testdata-groovy/groovy-1.8.2.jar";
+ protected String GroovyrtJar = "../testdata-groovy/groovy-all-1.8.6.jar";
protected Result result;
protected TypeRegistry registry;
@@ -1260,5 +1260,12 @@ public abstract class SpringLoadedTests implements Constants {
m.invoke(null);
return captureOff();
}
+
+ protected final static void pause(int seconds) {
+ try {
+ Thread.sleep(seconds*1000);
+ } catch (Exception e) {}
+ }
+
}
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTestsInSeparateJVM.java b/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTestsInSeparateJVM.java
index a3458a9..83b88e9 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTestsInSeparateJVM.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/SpringLoadedTestsInSeparateJVM.java
@@ -17,11 +17,15 @@ package org.springsource.loaded.test;
import static org.junit.Assert.fail;
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Test;
import org.springsource.loaded.test.ReloadingJVM.JVMOutput;
+import sun.misc.Cleaner;
+
/**
* These tests use a harness that forks a JVM with the agent attached, closely simulating a real environment. The
* forked process is running a special class that can be sent commands.
@@ -42,6 +46,12 @@ public class SpringLoadedTestsInSeparateJVM extends SpringLoadedTests {
public static void stopJVM() {
jvm.shutdown();
}
+
+ @After
+ public void teardown() throws Exception {
+ super.teardown();
+ jvm.clearTestdataDirectory();
+ }
@Test
public void testEcho() throws Exception {
@@ -80,6 +90,10 @@ public class SpringLoadedTestsInSeparateJVM extends SpringLoadedTests {
assertStdout("jvmtwo.Runner.run1() running", jvm.call("a", "run1"));
}
+ /* careful with this test - when the forked JVM takes a while the output can interfere with later tests, needs fixing up
+ *
+ */
+ @Ignore
@Test
public void reloadedPerformance() throws Exception {
// debug();
@@ -91,7 +105,7 @@ public class SpringLoadedTestsInSeparateJVM extends SpringLoadedTests {
pause(2);
// In Perf2 the static method is gone, why does it give us a NSME?
jo = jvm.call("a","time"); // 150ms
- System.out.println(jo);
+ pause(5);
}
private final static void debug() {
@@ -103,23 +117,14 @@ public class SpringLoadedTestsInSeparateJVM extends SpringLoadedTests {
jvm = ReloadingJVM.launch(options,true);
}
- private final static void pause(int seconds) {
- try {
- Thread.sleep(seconds*1000);
- } catch (Exception e) {}
- }
-
-
@Test
public void testReloadingInOtherVM() throws Exception {
- jvm.newInstance("a", "remote.One");
- assertStdout("first", jvm.call("a", "run"));
+ jvm.newInstance("b", "remote.One");
+ assertStdout("first", jvm.call("b", "run"));
+ pause(1);
jvm.updateClass("remote.One",retrieveRename("remote.One","remote.One2"));
- try {
- Thread.sleep(2000);
- } catch (Exception e) {
- }
- assertStdoutContains("second", jvm.call("a", "run"));
+ pause(2);
+ assertStdoutContains("second", jvm.call("b", "run"));
}
// TODO tidyup test data area after each test?
// TODO flush/replace classloader in forked VM to clear it out after each test?
@@ -135,11 +140,14 @@ public class SpringLoadedTestsInSeparateJVM extends SpringLoadedTests {
String subtype="foo.Controller";
jvm.copyToTestdataDirectory(supertype);
jvm.copyToTestdataDirectory(subtype);
- jvm.newInstance("a",subtype);
- assertStdout("Top.foo() running\nController.foo() running\n", jvm.call("a", "foo"));
+ JVMOutput jo = jvm.newInstance("bb",subtype);
+ System.out.println(jo);
+ pause(1);
+ assertStdout("Top.foo() running\nController.foo() running\n", jvm.call("bb", "foo"));
+ pause(1);
jvm.updateClass(subtype,retrieveRename(subtype,subtype+"2"));
waitForReloadToOccur();
- JVMOutput jo = jvm.call("a", "foo");
+ jo = jvm.call("bb", "foo");
assertStdoutContains("Top.foo() running\nController.foo() running again!\n", jo);
}
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/infra/FakeMethodVisitor.java b/springloaded/src/test/java/org/springsource/loaded/test/infra/FakeMethodVisitor.java
index 3d0e2bc..8cc0258 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/infra/FakeMethodVisitor.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/infra/FakeMethodVisitor.java
@@ -19,13 +19,18 @@ import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
+import org.springsource.loaded.Constants;
import org.springsource.loaded.Utils;
/**
* MethodVisitor that records events - very useful for testing
*/
-public class FakeMethodVisitor implements MethodVisitor {
+public class FakeMethodVisitor extends MethodVisitor implements Constants {
+
+ public FakeMethodVisitor() {
+ super(ASM5);
+ }
StringBuilder events = new StringBuilder();
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/infra/RewriteReflectUtilsDefineClass.java b/springloaded/src/test/java/org/springsource/loaded/test/infra/RewriteReflectUtilsDefineClass.java
index 4cef98a..9be7813 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/infra/RewriteReflectUtilsDefineClass.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/infra/RewriteReflectUtilsDefineClass.java
@@ -15,10 +15,9 @@
*/
package org.springsource.loaded.test.infra;
-import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.springsource.loaded.Constants;
import org.springsource.loaded.ReloadableType;
@@ -32,7 +31,7 @@ import org.springsource.loaded.TypeRegistry;
* @author Andy Clement
* @version 0.8.3
*/
-public class RewriteReflectUtilsDefineClass extends ClassAdapter implements Constants {
+public class RewriteReflectUtilsDefineClass extends ClassVisitor implements Constants {
public static byte[] rewriteReflectUtilsDefineClass(byte[] data) {
ClassReader cr = new ClassReader(data);
@@ -43,7 +42,7 @@ public class RewriteReflectUtilsDefineClass extends ClassAdapter implements Cons
}
private RewriteReflectUtilsDefineClass() {
- super(new ClassWriter(0)); // TODO review 0 here
+ super(ASM5,new ClassWriter(0)); // TODO review 0 here
}
public byte[] getBytes() {
@@ -74,10 +73,10 @@ public class RewriteReflectUtilsDefineClass extends ClassAdapter implements Cons
}
}
- class DefineClassInterceptor extends MethodAdapter implements Constants {
+ class DefineClassInterceptor extends MethodVisitor implements Constants {
public DefineClassInterceptor(MethodVisitor mv) {
- super(mv);
+ super(ASM5,mv);
}
@Override
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/infra/SubLoader.java b/springloaded/src/test/java/org/springsource/loaded/test/infra/SubLoader.java
index d2bd283..ce04187 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/infra/SubLoader.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/infra/SubLoader.java
@@ -47,7 +47,7 @@ public class SubLoader extends ClassLoader {
TestUtils.getPathToClasses("../testdata-subloader")
};
static String[] jars = new String[] {
- "../testdata-groovy/groovy-1.8.2.jar"
+ "../testdata-groovy/groovy-all-1.8.6.jar"
};
// @formatter:on
@@ -140,8 +140,8 @@ public class SubLoader extends ClassLoader {
c = defineClass(name, data, 0, data.length);
break;
}
+ zipfile.close();
}
- // zipfile.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Problem defining class", e);
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/infra/SuperLoader.java b/springloaded/src/test/java/org/springsource/loaded/test/infra/SuperLoader.java
index b2af228..992f95f 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/infra/SuperLoader.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/infra/SuperLoader.java
@@ -45,12 +45,12 @@ public class SuperLoader extends ClassLoader {
TestUtils.getPathToClasses("../testdata-superloader")
};
static String[] jars = new String[] {
- "../testdata-groovy/groovy-1.8.2.jar"
+ "../testdata-groovy/groovy-all-1.8.6.jar"
};
// @formatter:on
public SuperLoader() {
- jars = new String[] { "../testdata-groovy/groovy-1.8.2.jar" };
+ jars = new String[] { "../testdata-groovy/groovy-all-1.8.6.jar" };
}
public SuperLoader(String... jars) {
@@ -132,8 +132,8 @@ public class SuperLoader extends ClassLoader {
c = defineClass(name, data, 0, data.length);
break;
}
+ zipfile.close();
}
- // zipfile.close();
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/springloaded/src/test/java/org/springsource/loaded/test/infra/TestClassloaderWithRewriting.java b/springloaded/src/test/java/org/springsource/loaded/test/infra/TestClassloaderWithRewriting.java
index 29a5a2b..ba9facb 100644
--- a/springloaded/src/test/java/org/springsource/loaded/test/infra/TestClassloaderWithRewriting.java
+++ b/springloaded/src/test/java/org/springsource/loaded/test/infra/TestClassloaderWithRewriting.java
@@ -51,12 +51,12 @@ public class TestClassloaderWithRewriting extends ClassLoader {
TestUtils.getPathToClasses("../testdata-groovy")
};
static String[] jars = new String[] {
- "../testdata-groovy/groovy-1.8.2.jar"
+ "../testdata-groovy/groovy-all-1.8.6.jar"
};
// @formatter:on
public TestClassloaderWithRewriting() {
- jars = new String[] { "../testdata-groovy/groovy-1.8.2.jar" };
+ jars = new String[] { "../testdata-groovy/groovy-all-1.8.6.jar" };
}
public TestClassloaderWithRewriting(String metainfFolder) {
@@ -64,7 +64,7 @@ public class TestClassloaderWithRewriting extends ClassLoader {
newFolders[0] = folders[0];
newFolders[1] = "../testdata/" + metainfFolder;
folders = newFolders;
- jars = new String[] { "../testdata-groovy/groovy-1.8.2.jar" };
+ jars = new String[] { "../testdata-groovy/groovy-all-1.8.6.jar" };
}
public TestClassloaderWithRewriting(String metainfFolder, boolean b) {
@@ -74,7 +74,7 @@ public class TestClassloaderWithRewriting extends ClassLoader {
newFolders[2] = TestUtils.getPathToClasses("../testdata");
newFolders[3] = TestUtils.getPathToClasses("../testdata-plugin");
folders = newFolders;
- jars = new String[] { "../testdata-groovy/groovy-1.8.2.jar" };
+ jars = new String[] { "../testdata-groovy/groovy-all-1.8.6.jar" };
}
public TestClassloaderWithRewriting(String metainfFolder, boolean b, boolean useRegistry, URLClassLoader classLoader) {
@@ -85,7 +85,7 @@ public class TestClassloaderWithRewriting extends ClassLoader {
newFolders[2] = TestUtils.getPathToClasses("../testdata");
folders = newFolders;
this.useRegistry = useRegistry;
- jars = new String[] { "../testdata-groovy/groovy-1.8.2.jar" };
+ jars = new String[] { "../testdata-groovy/groovy-all-1.8.6.jar" };
}
public TestClassloaderWithRewriting(boolean b, boolean useRegistry, boolean addCglib) {
diff --git a/testdata-groovy/.classpath b/testdata-groovy/.classpath
index b81d5bc..89435f1 100644
--- a/testdata-groovy/.classpath
+++ b/testdata-groovy/.classpath
@@ -3,5 +3,6 @@
+
diff --git a/testdata-groovy/groovy-all-1.8.6.jar b/testdata-groovy/groovy-all-1.8.6.jar
new file mode 100644
index 0000000..6dc0128
Binary files /dev/null and b/testdata-groovy/groovy-all-1.8.6.jar differ
diff --git a/testdata-java8/.classpath b/testdata-java8/.classpath
new file mode 100644
index 0000000..7461090
--- /dev/null
+++ b/testdata-java8/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/testdata-java8/.gradle/1.7/taskArtifacts/cache.properties b/testdata-java8/.gradle/1.7/taskArtifacts/cache.properties
new file mode 100644
index 0000000..be198ef
--- /dev/null
+++ b/testdata-java8/.gradle/1.7/taskArtifacts/cache.properties
@@ -0,0 +1 @@
+#Thu Feb 06 13:01:33 PST 2014
diff --git a/testdata-java8/.gradle/1.7/taskArtifacts/cache.properties.lock b/testdata-java8/.gradle/1.7/taskArtifacts/cache.properties.lock
new file mode 100644
index 0000000..40fdece
--- /dev/null
+++ b/testdata-java8/.gradle/1.7/taskArtifacts/cache.properties.lock
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/testdata-java8/.gradle/1.7/taskArtifacts/fileHashes.bin b/testdata-java8/.gradle/1.7/taskArtifacts/fileHashes.bin
new file mode 100644
index 0000000..b6c8cc9
Binary files /dev/null and b/testdata-java8/.gradle/1.7/taskArtifacts/fileHashes.bin differ
diff --git a/testdata-java8/.gradle/1.7/taskArtifacts/fileSnapshots.bin b/testdata-java8/.gradle/1.7/taskArtifacts/fileSnapshots.bin
new file mode 100644
index 0000000..755b7b8
Binary files /dev/null and b/testdata-java8/.gradle/1.7/taskArtifacts/fileSnapshots.bin differ
diff --git a/testdata-java8/.gradle/1.7/taskArtifacts/outputFileStates.bin b/testdata-java8/.gradle/1.7/taskArtifacts/outputFileStates.bin
new file mode 100644
index 0000000..f8edce7
Binary files /dev/null and b/testdata-java8/.gradle/1.7/taskArtifacts/outputFileStates.bin differ
diff --git a/testdata-java8/.gradle/1.7/taskArtifacts/taskArtifacts.bin b/testdata-java8/.gradle/1.7/taskArtifacts/taskArtifacts.bin
new file mode 100644
index 0000000..4a4eb10
Binary files /dev/null and b/testdata-java8/.gradle/1.7/taskArtifacts/taskArtifacts.bin differ
diff --git a/testdata-java8/.project b/testdata-java8/.project
new file mode 100644
index 0000000..c51edec
--- /dev/null
+++ b/testdata-java8/.project
@@ -0,0 +1,17 @@
+
+
+ testdata-java8
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/testdata-java8/.settings/org.eclipse.jdt.core.prefs b/testdata-java8/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..7341ab1
--- /dev/null
+++ b/testdata-java8/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/testdata-java8/build.gradle b/testdata-java8/build.gradle
new file mode 100644
index 0000000..17b41ee
--- /dev/null
+++ b/testdata-java8/build.gradle
@@ -0,0 +1,3 @@
+
+apply plugin: 'java'
+sourceCompatibility = 1.8
diff --git a/testdata-java8/build.sh b/testdata-java8/build.sh
new file mode 100755
index 0000000..9157ee6
--- /dev/null
+++ b/testdata-java8/build.sh
@@ -0,0 +1,2 @@
+cd src/main/java
+find . -name "*.java" | javac
diff --git a/testdata-java8/code.jar b/testdata-java8/code.jar
new file mode 100644
index 0000000..36dd8e9
Binary files /dev/null and b/testdata-java8/code.jar differ
diff --git a/testdata-java8/src/main/java/basic/FirstClass.class b/testdata-java8/src/main/java/basic/FirstClass.class
new file mode 100644
index 0000000..7755e76
Binary files /dev/null and b/testdata-java8/src/main/java/basic/FirstClass.class differ
diff --git a/testdata-java8/src/main/java/basic/FirstClass.java b/testdata-java8/src/main/java/basic/FirstClass.java
new file mode 100644
index 0000000..846f4ea
--- /dev/null
+++ b/testdata-java8/src/main/java/basic/FirstClass.java
@@ -0,0 +1,12 @@
+package basic;
+
+public class FirstClass {
+
+ public static void main(String[] args) {
+ System.out.println("This is Java8");
+ }
+
+ public static int run() {
+ return 8;
+ }
+}
diff --git a/testdata-java8/src/main/java/basic/LambdaA.java b/testdata-java8/src/main/java/basic/LambdaA.java
new file mode 100644
index 0000000..b276dc6
--- /dev/null
+++ b/testdata-java8/src/main/java/basic/LambdaA.java
@@ -0,0 +1,16 @@
+package basic;
+
+public class LambdaA {
+
+ public interface Foo { int m(); }
+
+ public static void main(String[] args) {
+ run();
+ }
+
+ public static int run() {
+ Foo f = null;
+ f = () -> 77;
+ return f.m();
+ }
+}
diff --git a/testdata-java8/src/main/java/basic/LambdaA2.java b/testdata-java8/src/main/java/basic/LambdaA2.java
new file mode 100644
index 0000000..7e7de68
--- /dev/null
+++ b/testdata-java8/src/main/java/basic/LambdaA2.java
@@ -0,0 +1,16 @@
+package basic;
+
+public class LambdaA2 {
+
+ public interface Foo { int m(); }
+
+ public static void main(String[] args) {
+ run();
+ }
+
+ public static int run() {
+ Foo f = null;
+ f = () -> 88;
+ return f.m();
+ }
+}
diff --git a/testdata/.classpath b/testdata/.classpath
index 050e031..92b173c 100644
--- a/testdata/.classpath
+++ b/testdata/.classpath
@@ -2,10 +2,10 @@
-
+