Search in sources :

Example 1 with TraceMethodVisitor

use of org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor in project kotlin by JetBrains.

the class InlineCodegenUtil method getNodeText.

@NotNull
public static String getNodeText(@Nullable MethodNode node) {
    Textifier textifier = new Textifier();
    if (node == null) {
        return "Not generated";
    }
    node.accept(new TraceMethodVisitor(textifier));
    StringWriter sw = new StringWriter();
    textifier.print(new PrintWriter(sw));
    sw.flush();
    return node.name + " " + node.desc + ":\n" + sw.getBuffer().toString();
}
Also used : StringWriter(java.io.StringWriter) Textifier(org.jetbrains.org.objectweb.asm.util.Textifier) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) PrintWriter(java.io.PrintWriter) NotNull(org.jetbrains.annotations.NotNull)

Example 2 with TraceMethodVisitor

use of org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor in project kotlin by JetBrains.

the class InterceptionInstrumenter method instrument.

private byte[] instrument(byte[] classData, final List<MethodInstrumenter> instrumenters) {
    final ClassReader cr = new ClassReader(classData);
    ClassWriter cw = new ClassWriter(cr, 0);
    cr.accept(new ClassVisitor(ASM5, cw) {

        private final Map<MethodInstrumenter, String> matchedMethods = new HashMap<MethodInstrumenter, String>();

        @Override
        public MethodVisitor visitMethod(final int access, final String name, final String desc, String signature, String[] exceptions) {
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            // Do not instrument synthetic methods
            if ((access & (ACC_BRIDGE | ACC_SYNTHETIC)) != 0)
                return mv;
            List<MethodInstrumenter> applicableInstrumenters = new ArrayList<MethodInstrumenter>();
            for (MethodInstrumenter instrumenter : instrumenters) {
                if (instrumenter.isApplicable(name, desc)) {
                    applicableInstrumenters.add(instrumenter);
                    instrumenter.reportApplication(cr.getClassName(), name, desc);
                    checkMultipleMatches(instrumenter, name, desc);
                    neverMatchedInstrumenters.remove(instrumenter);
                }
            }
            if (applicableInstrumenters.isEmpty())
                return mv;
            boolean dumpByteCode = false;
            final List<MethodData> normalReturnData = new ArrayList<MethodData>();
            final List<MethodData> enterData = new ArrayList<MethodData>();
            final List<MethodData> exceptionData = new ArrayList<MethodData>();
            for (MethodInstrumenter instrumenter : applicableInstrumenters) {
                enterData.addAll(instrumenter.getEnterData());
                normalReturnData.addAll(instrumenter.getNormalReturnData());
                exceptionData.addAll(instrumenter.getExceptionData());
                dumpByteCode |= instrumenter.shouldDumpByteCode();
            }
            if (enterData.isEmpty() && normalReturnData.isEmpty() && exceptionData.isEmpty())
                return mv;
            if (dumpByteCode) {
                mv = getDumpingVisitorWrapper(mv, name, desc);
            }
            final int maxStackDepth = getMaxStackDepth(name, desc, normalReturnData, enterData, exceptionData);
            final boolean isConstructor = "<init>".equals(name);
            return new MethodVisitor(ASM5, mv) {

                private InstructionAdapter ia = null;

                private InstructionAdapter getInstructionAdapter() {
                    if (ia == null) {
                        ia = new InstructionAdapter(this);
                    }
                    return ia;
                }

                @Override
                public void visitMaxs(int maxStack, int maxLocals) {
                    super.visitMaxs(Math.max(maxStack, maxStackDepth), maxLocals);
                }

                @Override
                public void visitCode() {
                    for (MethodData methodData : enterData) {
                        // At the very beginning of a constructor, i.e. before any super() call, 'this' is not available
                        // It's too hard to detect a place right after the super() call, so we just put null instead of 'this' in such cases
                        invokeMethod(access, cr.getClassName(), name, desc, getInstructionAdapter(), methodData, isConstructor);
                    }
                    super.visitCode();
                }

                @Override
                public void visitInsn(int opcode) {
                    switch(opcode) {
                        case RETURN:
                        case IRETURN:
                        case LRETURN:
                        case FRETURN:
                        case DRETURN:
                        case ARETURN:
                            for (MethodData methodData : normalReturnData) {
                                invokeMethod(access, cr.getClassName(), name, desc, getInstructionAdapter(), methodData, false);
                            }
                            break;
                        case ATHROW:
                            for (MethodData methodData : exceptionData) {
                                // A constructor may throw before calling super(), 'this' is not available in this case
                                invokeMethod(access, cr.getClassName(), name, desc, getInstructionAdapter(), methodData, isConstructor);
                            }
                            break;
                    }
                    super.visitInsn(opcode);
                }
            };
        }

        private int getMaxStackDepth(String name, String desc, List<MethodData> normalReturnData, List<MethodData> enterData, List<MethodData> exceptionData) {
            org.jetbrains.org.objectweb.asm.commons.Method methodBeingInstrumented = new org.jetbrains.org.objectweb.asm.commons.Method(name, desc);
            List<MethodData> allData = new ArrayList<MethodData>();
            allData.addAll(enterData);
            allData.addAll(exceptionData);
            allData.addAll(normalReturnData);
            int maxStackDepth = 0;
            for (MethodData methodData : allData) {
                int depth = stackDepth(methodData, methodBeingInstrumented);
                if (maxStackDepth < depth) {
                    maxStackDepth = depth;
                }
            }
            return maxStackDepth;
        }

        private int stackDepth(MethodData methodData, org.jetbrains.org.objectweb.asm.commons.Method methodBeingInstrumented) {
            org.jetbrains.org.objectweb.asm.commons.Method method = getAsmMethod(methodData);
            // array * 2 (dup) + index + value (may be long/double)
            int allArgsStackDepth = methodData.getAllArgsParameterIndex() >= 0 ? 5 : 0;
            int argsSize = 0;
            for (Type type : method.getArgumentTypes()) {
                argsSize += type.getSize();
            }
            int receiverSize = 1;
            // return value must be kept on the stack OR exception, so we have to reserve at least 1
            int exceptionSize = 1;
            int returnValueSize = methodBeingInstrumented.getReturnType().getSize();
            return argsSize + allArgsStackDepth + receiverSize + Math.max(returnValueSize, exceptionSize);
        }

        private void checkMultipleMatches(MethodInstrumenter instrumenter, String name, String desc) {
            if (!instrumenter.allowsMultipleMatches()) {
                String erasedSignature = name + desc;
                String alreadyMatched = matchedMethods.put(instrumenter, erasedSignature);
                if (alreadyMatched != null) {
                    throw new IllegalStateException(instrumenter + " matched two methods in " + cr.getClassName() + ":\n" + alreadyMatched + "\n" + erasedSignature);
                }
            }
        }

        private TraceMethodVisitor getDumpingVisitorWrapper(MethodVisitor mv, final String methodName, final String methodDesc) {
            return new TraceMethodVisitor(mv, new Textifier(ASM5) {

                @Override
                public void visitMethodEnd() {
                    System.out.println(cr.getClassName() + ":" + methodName + methodDesc);
                    for (Object line : getText()) {
                        System.out.print(line);
                    }
                    System.out.println();
                    System.out.println();
                    super.visitMethodEnd();
                }
            });
        }
    }, 0);
    return cw.toByteArray();
}
Also used : Textifier(org.jetbrains.org.objectweb.asm.util.Textifier) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) Method(java.lang.reflect.Method) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) InstructionAdapter(org.jetbrains.org.objectweb.asm.commons.InstructionAdapter) org.jetbrains.org.objectweb.asm(org.jetbrains.org.objectweb.asm)

Example 3 with TraceMethodVisitor

use of org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor in project kotlin by JetBrains.

the class CodegenTestCase method verifyWithAsm.

private static boolean verifyWithAsm(@NotNull OutputFile file, ClassLoader loader) {
    ClassNode classNode = new ClassNode();
    new ClassReader(file.asByteArray()).accept(classNode, 0);
    SimpleVerifier verifier = new SimpleVerifier();
    verifier.setClassLoader(loader);
    Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
    boolean noErrors = true;
    for (MethodNode method : classNode.methods) {
        try {
            analyzer.analyze(classNode.name, method);
        } catch (Throwable e) {
            System.err.println(file.asText());
            System.err.println(classNode.name + "::" + method.name + method.desc);
            //noinspection InstanceofCatchParameter
            if (e instanceof AnalyzerException) {
                // Print the erroneous instruction
                TraceMethodVisitor tmv = new TraceMethodVisitor(new Textifier());
                ((AnalyzerException) e).node.accept(tmv);
                PrintWriter pw = new PrintWriter(System.err);
                tmv.p.print(pw);
                pw.flush();
            }
            e.printStackTrace();
            noErrors = false;
        }
    }
    return noErrors;
}
Also used : ClassNode(org.jetbrains.org.objectweb.asm.tree.ClassNode) AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException) SimpleVerifier(org.jetbrains.org.objectweb.asm.tree.analysis.SimpleVerifier) Analyzer(org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer) Textifier(org.jetbrains.org.objectweb.asm.util.Textifier) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) BasicValue(org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue) MethodNode(org.jetbrains.org.objectweb.asm.tree.MethodNode) ClassReader(org.jetbrains.org.objectweb.asm.ClassReader) PrintWriter(java.io.PrintWriter)

Example 4 with TraceMethodVisitor

use of org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor in project kotlin by JetBrains.

the class InlineCodegenUtil method getInsnText.

@NotNull
public static String getInsnText(@Nullable AbstractInsnNode node) {
    if (node == null)
        return "<null>";
    Textifier textifier = new Textifier();
    node.accept(new TraceMethodVisitor(textifier));
    StringWriter sw = new StringWriter();
    textifier.print(new PrintWriter(sw));
    sw.flush();
    return sw.toString().trim();
}
Also used : StringWriter(java.io.StringWriter) Textifier(org.jetbrains.org.objectweb.asm.util.Textifier) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) PrintWriter(java.io.PrintWriter) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with TraceMethodVisitor

use of org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor in project kotlin by JetBrains.

the class InternalFinallyBlockInliner method traceInterval.

private static String traceInterval(AbstractInsnNode startNode, AbstractInsnNode stopNode) {
    Textifier p = new Textifier();
    TraceMethodVisitor visitor = new TraceMethodVisitor(p);
    while (startNode != stopNode) {
        startNode.accept(visitor);
        startNode = startNode.getNext();
    }
    startNode.accept(visitor);
    StringWriter out = new StringWriter();
    p.print(new PrintWriter(out));
    return out.toString();
}
Also used : StringWriter(java.io.StringWriter) Textifier(org.jetbrains.org.objectweb.asm.util.Textifier) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) PrintWriter(java.io.PrintWriter)

Aggregations

TraceMethodVisitor (org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor)6 PrintWriter (java.io.PrintWriter)5 Textifier (org.jetbrains.org.objectweb.asm.util.Textifier)5 StringWriter (java.io.StringWriter)4 NotNull (org.jetbrains.annotations.NotNull)2 Method (java.lang.reflect.Method)1 org.jetbrains.org.objectweb.asm (org.jetbrains.org.objectweb.asm)1 ClassReader (org.jetbrains.org.objectweb.asm.ClassReader)1 InstructionAdapter (org.jetbrains.org.objectweb.asm.commons.InstructionAdapter)1 ClassNode (org.jetbrains.org.objectweb.asm.tree.ClassNode)1 MethodNode (org.jetbrains.org.objectweb.asm.tree.MethodNode)1 Analyzer (org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer)1 AnalyzerException (org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException)1 BasicValue (org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue)1 SimpleVerifier (org.jetbrains.org.objectweb.asm.tree.analysis.SimpleVerifier)1