diff --git a/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java b/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java index 141258061152..432cc6111cc8 100644 --- a/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java +++ b/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java @@ -19,8 +19,7 @@ import java.util.jar.JarFile; public class CaptureAgent { private static Instrumentation ourInstrumentation; - private static final Map> myCapturePoints = new HashMap>(); - private static final Map> myInsertPoints = new HashMap>(); + private static final Map> myInstrumentPoints = new HashMap>(); public static void premain(String args, Instrumentation instrumentation) { ourInstrumentation = instrumentation; @@ -132,10 +131,6 @@ public class CaptureAgent { } } - private static List getNotNull(List list) { - return list != null ? list : Collections.emptyList(); - } - private static class CaptureTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, @@ -144,14 +139,13 @@ public class CaptureAgent { ProtectionDomain protectionDomain, byte[] classfileBuffer) { if (className != null) { - List capturePoints = getNotNull(myCapturePoints.get(className)); - List insertPoints = getNotNull(myInsertPoints.get(className)); - if (!capturePoints.isEmpty() || !insertPoints.isEmpty()) { + List classPoints = myInstrumentPoints.get(className); + if (classPoints != null) { try { ClassReader reader = new ClassReader(classfileBuffer); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); - reader.accept(new CaptureInstrumentor(Opcodes.API_VERSION, writer, capturePoints, insertPoints), 0); + reader.accept(new CaptureInstrumentor(Opcodes.API_VERSION, writer, classPoints), 0); byte[] bytes = writer.toByteArray(); if (CaptureStorage.DEBUG) { @@ -182,15 +176,13 @@ public class CaptureAgent { } private static class CaptureInstrumentor extends ClassVisitor { - private final List myCapturePoints; - private final List myInsertPoints; + private final List myInstrumentPoints; private final Map myFields = new HashMap(); private String mySuperName; - public CaptureInstrumentor(int api, ClassVisitor cv, List capturePoints, List insertPoints) { + public CaptureInstrumentor(int api, ClassVisitor cv, List instrumentPoints) { super(api, cv); - this.myCapturePoints = capturePoints; - this.myInsertPoints = insertPoints; + this.myInstrumentPoints = instrumentPoints; } private static String getNewName(String name) { @@ -216,51 +208,50 @@ public class CaptureAgent { @Override public MethodVisitor visitMethod(final int access, String name, final String desc, String signature, String[] exceptions) { if ((access & Opcodes.ACC_BRIDGE) == 0) { - for (final InstrumentPoint capturePoint : myCapturePoints) { - if (capturePoint.matchesMethod(name, desc)) { - final String methodDisplayName = getMethodDisplayName(capturePoint.myClassName, name, desc); + for (final InstrumentPoint point : myInstrumentPoints) { + if (point.matchesMethod(name, desc)) { + final String methodDisplayName = getMethodDisplayName(point.myClassName, name, desc); if (CaptureStorage.DEBUG) { - System.out.println("Capture agent: instrumented capture point at " + methodDisplayName); + System.out.println( + "Capture agent: instrumented " + (point.myCapture ? "capture" : "insert") + " point at " + methodDisplayName); } - // for constructors and "this" key - move capture to after the super constructor call - if ("".equals(name) && capturePoint.myKeyProvider == THIS_KEY_PROVIDER) { - return new MethodVisitor(api, super.visitMethod(access, name, desc, signature, exceptions)) { - boolean captured = false; + if (point.myCapture) { // capture + // for constructors and "this" key - move capture to after the super constructor call + if (CONSTRUCTOR.equals(name) && point.myKeyProvider == THIS_KEY_PROVIDER) { + return new MethodVisitor(api, super.visitMethod(access, name, desc, signature, exceptions)) { + boolean captured = false; - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - super.visitMethodInsn(opcode, owner, name, desc, itf); - if (opcode == Opcodes.INVOKESPECIAL && !captured && owner.equals(mySuperName) && name.equals("")) { // super constructor - capture(mv, capturePoint.myKeyProvider, (access & Opcodes.ACC_STATIC) != 0, - Type.getMethodType(desc).getArgumentTypes(), methodDisplayName); - captured = true; + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + if (opcode == Opcodes.INVOKESPECIAL && + !captured && + owner.equals(mySuperName) && + name.equals(CONSTRUCTOR)) { // super constructor + capture(mv, point.myKeyProvider, (access & Opcodes.ACC_STATIC) != 0, + Type.getMethodType(desc).getArgumentTypes(), methodDisplayName); + captured = true; + } } - } - }; + }; + } + else { + return new MethodVisitor(api, super.visitMethod(access, name, desc, signature, exceptions)) { + @Override + public void visitCode() { + capture(mv, point.myKeyProvider, (access & Opcodes.ACC_STATIC) != 0, Type.getMethodType(desc).getArgumentTypes(), + methodDisplayName); + super.visitCode(); + } + }; + } } - else { - return new MethodVisitor(api, super.visitMethod(access, name, desc, signature, exceptions)) { - @Override - public void visitCode() { - capture(mv, capturePoint.myKeyProvider, (access & Opcodes.ACC_STATIC) != 0, Type.getMethodType(desc).getArgumentTypes(), - methodDisplayName); - super.visitCode(); - } - }; + else { // insert + generateWrapper(access, name, desc, signature, exceptions, point, methodDisplayName); + return super.visitMethod(access, getNewName(name), desc, signature, exceptions); } } } - - for (InstrumentPoint insertPoint : myInsertPoints) { - if (insertPoint.matchesMethod(name, desc)) { - String methodDisplayName = getMethodDisplayName(insertPoint.myClassName, name, desc); - if (CaptureStorage.DEBUG) { - System.out.println("Capture agent: instrumented insert point at " + methodDisplayName); - } - generateWrapper(access, name, desc, signature, exceptions, insertPoint, methodDisplayName); - return super.visitMethod(access, getNewName(name), desc, signature, exceptions); - } - } } return super.visitMethod(access, name, desc, signature, exceptions); } @@ -352,12 +343,14 @@ public class CaptureAgent { private static class InstrumentPoint { final static String ANY_DESC = "*"; + final boolean myCapture; final String myClassName; final String myMethodName; final String myMethodDesc; final KeyProvider myKeyProvider; - public InstrumentPoint(String className, String methodName, String methodDesc, KeyProvider keyProvider) { + public InstrumentPoint(boolean capture, String className, String methodName, String methodDesc, KeyProvider keyProvider) { + myCapture = capture; myClassName = className; myMethodName = methodName; myMethodDesc = methodDesc; @@ -429,13 +422,12 @@ public class CaptureAgent { String methodName, String methodDesc, KeyProvider keyProvider) { - Map> map = capture ? myCapturePoints : myInsertPoints; - List points = map.get(className); + List points = myInstrumentPoints.get(className); if (points == null) { points = new ArrayList(1); - map.put(className, points); + myInstrumentPoints.put(className, points); } - InstrumentPoint point = new InstrumentPoint(className, methodName, methodDesc, keyProvider); + InstrumentPoint point = new InstrumentPoint(capture, className, methodName, methodDesc, keyProvider); points.add(point); return point; } @@ -548,28 +540,30 @@ public class CaptureAgent { return new ParamKeyProvider(idx); } + public static final String CONSTRUCTOR = ""; + // predefined points static { - addCapture("java/awt/event/InvocationEvent", "", THIS_KEY_PROVIDER); + addCapture("java/awt/event/InvocationEvent", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("java/awt/event/InvocationEvent", "dispatch", THIS_KEY_PROVIDER); addCapture("java/lang/Thread", "start", THIS_KEY_PROVIDER); addInsert("java/lang/Thread", "run", THIS_KEY_PROVIDER); - addCapture("java/util/concurrent/FutureTask", "", THIS_KEY_PROVIDER); + addCapture("java/util/concurrent/FutureTask", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("java/util/concurrent/FutureTask", "run", THIS_KEY_PROVIDER); addInsert("java/util/concurrent/FutureTask", "runAndReset", THIS_KEY_PROVIDER); - addCapture("java/util/concurrent/CompletableFuture$AsyncSupply", "", THIS_KEY_PROVIDER); + addCapture("java/util/concurrent/CompletableFuture$AsyncSupply", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("java/util/concurrent/CompletableFuture$AsyncSupply", "run", THIS_KEY_PROVIDER); - addCapture("java/util/concurrent/CompletableFuture$AsyncRun", "", THIS_KEY_PROVIDER); + addCapture("java/util/concurrent/CompletableFuture$AsyncRun", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("java/util/concurrent/CompletableFuture$AsyncRun", "run", THIS_KEY_PROVIDER); - addCapture("java/util/concurrent/CompletableFuture$UniAccept", "", THIS_KEY_PROVIDER); + addCapture("java/util/concurrent/CompletableFuture$UniAccept", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("java/util/concurrent/CompletableFuture$UniAccept", "tryFire", THIS_KEY_PROVIDER); - addCapture("java/util/concurrent/CompletableFuture$UniRun", "", THIS_KEY_PROVIDER); + addCapture("java/util/concurrent/CompletableFuture$UniRun", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("java/util/concurrent/CompletableFuture$UniRun", "tryFire", THIS_KEY_PROVIDER); // netty @@ -577,10 +571,10 @@ public class CaptureAgent { addInsert("io/netty/util/concurrent/AbstractEventExecutor", "safeExecute", FIRST_PARAM); // scala - addCapture("scala/concurrent/impl/Future$PromiseCompletingRunnable", "", THIS_KEY_PROVIDER); + addCapture("scala/concurrent/impl/Future$PromiseCompletingRunnable", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("scala/concurrent/impl/Future$PromiseCompletingRunnable", "run", THIS_KEY_PROVIDER); - addCapture("scala/concurrent/impl/CallbackRunnable", "", THIS_KEY_PROVIDER); + addCapture("scala/concurrent/impl/CallbackRunnable", CONSTRUCTOR, THIS_KEY_PROVIDER); addInsert("scala/concurrent/impl/CallbackRunnable", "run", THIS_KEY_PROVIDER); // akka-scala