From f8e066dacc3176561610ba0faaedc89f08f27e55 Mon Sep 17 00:00:00 2001
From: Dmitry Tsitelov <cit@devexperts.com>
Date: Fri, 1 Sep 2017 21:33:13 +0300
Subject: [PATCH] Fix: don't track <init> invocations to avoid verification
 errors

---
 .../devexperts/aprof/transformer/AProfTransformer.java | 10 ++++++----
 .../aprof/transformer/AbstractMethodVisitor.java       |  6 ++++--
 .../java/com/devexperts/aprof/transformer/Context.java |  6 +++++-
 .../devexperts/aprof/transformer/MethodAnalyzer.java   |  4 ++--
 .../aprof/transformer/MethodTransformer.java           |  4 ++--
 5 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/transformer/src/main/java/com/devexperts/aprof/transformer/AProfTransformer.java b/transformer/src/main/java/com/devexperts/aprof/transformer/AProfTransformer.java
index bae45ea..5a92b8a 100644
--- a/transformer/src/main/java/com/devexperts/aprof/transformer/AProfTransformer.java
+++ b/transformer/src/main/java/com/devexperts/aprof/transformer/AProfTransformer.java
@@ -133,7 +133,7 @@ private byte[] transformImpl(ClassLoader loader, String internalClassName,
 			ClassWriter cw = computeFrames ?
 				new FrameClassWriter(cr, loader) :
 				new ClassWriter(ClassWriter.COMPUTE_MAXS);
-			ClassVisitor classTransformer = new ClassTransformer(cw, classAnalyzer.contexts);
+			ClassVisitor classTransformer = new ClassTransformer(cw, classAnalyzer.contexts, classAnalyzer.classVersion);
 			int transformFlags =
 				(config.isSkipDebug() ? ClassReader.SKIP_DEBUG : 0) +
 				(config.isNoFrames() || computeFrames ? ClassReader.SKIP_FRAMES : 0);
@@ -255,16 +255,18 @@ public MethodVisitor visitMethod(final int access, final String mname, final Str
 			}
 			Context context = new Context(config, ciCache, loader, binaryClassName, cname, mname, desc);
 			contexts.add(context);
-			return new MethodAnalyzer(new GeneratorAdapter(new EmptyMethodVisitor(), access, mname, desc), context);
+			return new MethodAnalyzer(new GeneratorAdapter(new EmptyMethodVisitor(), access, mname, desc), context, classVersion);
 		}
 	}
 
 	private class ClassTransformer extends ClassVisitor {
 		private final Iterator<Context> contextIterator;
+		private final int classVersion;
 
-		public ClassTransformer(ClassVisitor cv, List<Context> contexts) {
+		public ClassTransformer(ClassVisitor cv, List<Context> contexts, int classVersion) {
 			super(TransformerUtil.ASM_API, cv);
 			this.contextIterator = contexts.iterator();
+			this.classVersion = classVersion;
 		}
 
 		@Override
@@ -281,7 +283,7 @@ public MethodVisitor visitMethod(final int access, final String mname, final Str
 			MethodVisitor visitor = super.visitMethod(access, mname, desc, signature, exceptions);
 			visitor = new TryCatchBlockSorter(visitor, access, mname, desc, signature, exceptions);
 			Context context = contextIterator.next();
-			visitor = new MethodTransformer(new GeneratorAdapter(visitor, access, mname, desc), context);
+			visitor = new MethodTransformer(new GeneratorAdapter(visitor, access, mname, desc), context, classVersion);
 			visitor = new JSRInlinerAdapter(visitor, access, mname, desc, signature, exceptions);
 			return visitor;
 		}
diff --git a/transformer/src/main/java/com/devexperts/aprof/transformer/AbstractMethodVisitor.java b/transformer/src/main/java/com/devexperts/aprof/transformer/AbstractMethodVisitor.java
index d409f24..1b0aa06 100644
--- a/transformer/src/main/java/com/devexperts/aprof/transformer/AbstractMethodVisitor.java
+++ b/transformer/src/main/java/com/devexperts/aprof/transformer/AbstractMethodVisitor.java
@@ -43,11 +43,13 @@ abstract class AbstractMethodVisitor extends MethodVisitor {
 
 	protected final GeneratorAdapter mv;
 	protected final Context context;
+	private final int classVersion;
 
-	public AbstractMethodVisitor(GeneratorAdapter mv, Context context) {
+	public AbstractMethodVisitor(GeneratorAdapter mv, Context context, int classVersion) {
 		super(TransformerUtil.ASM_API, mv);
 		this.mv = mv;
 		this.context = context;
+		this.classVersion = classVersion;
 	}
 
 	protected abstract void visitMarkDeclareLocationStack();
@@ -193,7 +195,7 @@ public void visitMethodInsn(final int opcode, final String owner, final String n
 		boolean isArrayClone = isClone && owner.startsWith("[");
 		boolean isObjectClone = isClone && AProfRegistry.isDirectCloneClass(cname);
 
-		if (context.isMethodInvocationTracked(cname, opcode, owner, name, desc)) {
+		if (context.isMethodInvocationTracked(cname, opcode, owner, name, desc, classVersion)) {
 			visitTrackedMethodInsn(opcode, owner, name, desc, intf);
 		} else {
 			mv.visitMethodInsn(opcode, owner, name, desc, intf);
diff --git a/transformer/src/main/java/com/devexperts/aprof/transformer/Context.java b/transformer/src/main/java/com/devexperts/aprof/transformer/Context.java
index aa4e2d0..127acdb 100644
--- a/transformer/src/main/java/com/devexperts/aprof/transformer/Context.java
+++ b/transformer/src/main/java/com/devexperts/aprof/transformer/Context.java
@@ -105,9 +105,13 @@ private void buildSignatureString(StringBuilder sb) {
 		sb.append(')');
 	}
 
-	public boolean isMethodInvocationTracked(String cname, int opcode, String owner, String name, String desc) {
+	public boolean isMethodInvocationTracked(String cname, int opcode, String owner, String name, String desc,
+		int transformedClassVersion)
+	{
 		if (owner.startsWith("["))
 			return false; // do not track array method invocations
+		if (transformedClassVersion >= Opcodes.V1_7 && TransformerUtil.INIT.equals(name))
+			return false; // <init> invocations don't pass verifier in modern JVMs
 		if (config.isMethodTracked(cname, name))
 			return true; // direct invocation of tracked method through its actual class
 		if (opcode != Opcodes.INVOKEVIRTUAL && opcode != Opcodes.INVOKEINTERFACE)
diff --git a/transformer/src/main/java/com/devexperts/aprof/transformer/MethodAnalyzer.java b/transformer/src/main/java/com/devexperts/aprof/transformer/MethodAnalyzer.java
index d5c75de..a042bdf 100644
--- a/transformer/src/main/java/com/devexperts/aprof/transformer/MethodAnalyzer.java
+++ b/transformer/src/main/java/com/devexperts/aprof/transformer/MethodAnalyzer.java
@@ -28,8 +28,8 @@
  * @author Dmitry Paraschenko
  */
 class MethodAnalyzer extends AbstractMethodVisitor {
-	public MethodAnalyzer(GeneratorAdapter mv, Context context) {
-		super(mv, context);
+	public MethodAnalyzer(GeneratorAdapter mv, Context context, int classVersion) {
+		super(mv, context, classVersion);
 	}
 
 	@Override
diff --git a/transformer/src/main/java/com/devexperts/aprof/transformer/MethodTransformer.java b/transformer/src/main/java/com/devexperts/aprof/transformer/MethodTransformer.java
index c0a5b63..afcd8ae 100644
--- a/transformer/src/main/java/com/devexperts/aprof/transformer/MethodTransformer.java
+++ b/transformer/src/main/java/com/devexperts/aprof/transformer/MethodTransformer.java
@@ -37,8 +37,8 @@ class MethodTransformer extends AbstractMethodVisitor {
 
 	private Label startFinally;
 
-	public MethodTransformer(GeneratorAdapter mv, Context context) {
-		super(mv, context);
+	public MethodTransformer(GeneratorAdapter mv, Context context, int classVersion) {
+		super(mv, context, classVersion);
 	}
 
 	private void pushAllocationPoint(String desc) {