- do not introduce extra variable at initialization of visited methods array

- share visited methods array for particular class between different classloaders
This commit is contained in:
Maxim.Mossienko
2015-08-20 12:08:35 +02:00
parent e2728ab72d
commit 87636c4a5c
2 changed files with 20 additions and 64 deletions
@@ -17,11 +17,11 @@
package org.jetbrains.testme.instrumentation;
import org.jetbrains.org.objectweb.asm.ClassVisitor;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
public class Instrumenter extends ClassVisitor {
private static final int ADDED_CODE_STACK_SIZE = 6;
protected final ClassVisitor myClassVisitor;
private final String myClassName;
private final String myInternalClassName;
@@ -88,7 +88,7 @@ public class Instrumenter extends ClassVisitor {
mv = new StaticBlockMethodVisitor(mv);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(myMethodNames.length + 2, 1);
mv.visitMaxs(ADDED_CODE_STACK_SIZE, 0);
mv.visitEnd();
}
super.visitEnd();
@@ -102,12 +102,11 @@ public class Instrumenter extends ClassVisitor {
public void visitCode() {
super.visitCode();
visitLdcInsn(myClassName);
pushInstruction(this, myMethodNames.length);
visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BOOLEAN);
visitFieldInsn(Opcodes.PUTSTATIC, myInternalClassName, METHODS_VISITED, METHODS_VISITED_CLASS);
pushInstruction(this, myMethodNames.length);
visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
for(int i = 0; i < myMethodNames.length; ++i) {
@@ -117,28 +116,16 @@ public class Instrumenter extends ClassVisitor {
visitInsn(Opcodes.AASTORE);
}
visitVarInsn(Opcodes.ASTORE, 0);
visitMethodInsn(Opcodes.INVOKESTATIC, ProjectData.PROJECT_DATA_OWNER, "trace", "(Ljava/lang/String;[Z[Ljava/lang/String;)[Z", false);
visitFieldInsn(Opcodes.PUTSTATIC, myInternalClassName, METHODS_VISITED, METHODS_VISITED_CLASS);
Label startLabel = new Label();
visitLabel(startLabel);
visitLdcInsn(myClassName);
visitFieldInsn(Opcodes.GETSTATIC, myInternalClassName, METHODS_VISITED, METHODS_VISITED_CLASS);
visitVarInsn(Opcodes.ALOAD, 0);
visitMethodInsn(Opcodes.INVOKESTATIC, ProjectData.PROJECT_DATA_OWNER, "trace", "(Ljava/lang/String;[Z[Ljava/lang/String;)V", false);
Label endLabel = new Label();
visitLabel(endLabel);
visitLocalVariable("methodNames", "[Ljava/lang/String;", null, startLabel, endLabel, 0);
// no return here
}
public void visitMaxs(int maxStack, int maxLocals) {
final int ourMaxStack = myMethodNames.length + 2;
final int ourMaxLocals = 1;
final int ourMaxStack = ADDED_CODE_STACK_SIZE;
super.visitMaxs(Math.max(ourMaxStack, maxStack), Math.max(ourMaxLocals, maxLocals));
super.visitMaxs(Math.max(ourMaxStack, maxStack), maxLocals);
}
}
@@ -17,42 +17,31 @@ public class ProjectData {
myTraceDir = traceDir;
}
private ConcurrentMap<String, Set<String>> myTrace;
private final ConcurrentMap<String, boolean[]> myTrace2 = new ConcurrentHashMap<String, boolean[]>();
private final ConcurrentMap<String, String[]> myTrace3 = new ConcurrentHashMap<String, String[]>();
public static ProjectData getProjectData() {
return ourData;
}
public static void trace(String className, String methodSignature) {
ourData.traceLines(className, methodSignature);
}
// called from instrumented code during class's static init
public static void trace(String className, boolean[] methodFlags, String[] methodNames) {
ourData.traceLines(className, methodFlags, methodNames);
}
public void traceLines(String className, String methodSignature) {
if (myTrace != null) {
Set<String> methods = myTrace.get(className);
if (methods == null) {
methods = new HashSet<String>();
Set<String> previousMethods = myTrace.putIfAbsent(className, methods);
if (previousMethods != null) methods = previousMethods;
}
synchronized (methods) {
methods.add(methodSignature);
}
}
public static boolean[] trace(String className, boolean[] methodFlags, String[] methodNames) {
return ourData.traceLines(className, methodFlags, methodNames);
}
public synchronized void traceLines(String className, boolean[] methodFlags, String[] methodNames) {
private synchronized boolean[] traceLines(String className, boolean[] methodFlags, String[] methodNames) {
//System.out.println("Registering " + className);
assert methodFlags.length == methodNames.length;
myTrace2.put(className, methodFlags);
myTrace3.put(className, methodNames);
final boolean[] previousMethodFlags = myTrace2.putIfAbsent(className, methodFlags);
if (previousMethodFlags != null) {
assert previousMethodFlags.length == methodFlags.length;
final String[] previousMethodNames = myTrace3.get(className);
assert previousMethodNames != null && previousMethodNames.length == methodNames.length;
} else {
myTrace3.put(className, methodNames);
}
return previousMethodFlags != null ? previousMethodFlags : methodFlags;
}
private static final int STRING_LENGTH_THRESHOLD = 255;
@@ -163,22 +152,6 @@ public class ProjectData {
catch (IOException e) {
e.printStackTrace();
}
finally {
myTrace = null;
}
}
private void saveOldTrace(DataOutputStream os) throws IOException {
os.writeInt(myTrace.size());
for (Iterator<String> it = myTrace.keySet().iterator(); it.hasNext();) {
final String classData = it.next();
os.writeUTF(classData);
final Set<String> methods = myTrace.get(classData);
os.writeInt(methods.size());
for (Iterator<String> iterator = methods.iterator(); iterator.hasNext(); ) {
os.writeUTF(iterator.next());
}
}
}
public synchronized void testStarted(final String name) {
@@ -190,8 +163,4 @@ public class ProjectData {
}
}
}
private void clearOldTrace() {
myTrace = new ConcurrentHashMap<String, Set<String>>();
}
}