edu.ubc.mirrors.holograms.FrameAnalyzerAdaptor.java Source code

Java tutorial

Introduction

Here is the source code for edu.ubc.mirrors.holograms.FrameAnalyzerAdaptor.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Robin Salkeld
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/
package edu.ubc.mirrors.holograms;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.JSRInlinerAdapter;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceMethodVisitor;

import edu.ubc.mirrors.ClassMirrorLoader;
import edu.ubc.mirrors.VirtualMachineMirror;

public class FrameAnalyzerAdaptor extends ClassVisitor {

    private final VirtualMachineMirror vm;
    private final ClassMirrorLoader loader;
    private final boolean insertFrames;
    private final boolean holograms;
    private Type thisType = null;

    public FrameAnalyzerAdaptor(VirtualMachineMirror vm, ClassMirrorLoader loader, ClassVisitor cv,
            boolean insertFrames, boolean holograms) {
        super(Opcodes.ASM4, cv);
        this.vm = vm;
        this.loader = loader;
        this.insertFrames = insertFrames;
        this.holograms = holograms;
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        this.thisType = Type.getObjectType(name);
        super.visit(version, access, name, signature, superName, interfaces);
    }

    static void printAnalyzerResult(MethodNode method, Frame<FrameValue>[] frames, final PrintWriter pw) {
        Textifier t = new Textifier();
        TraceMethodVisitor mv = new TraceMethodVisitor(t);

        pw.println(method.name + method.desc);
        for (int j = 0; j < method.instructions.size(); ++j) {
            method.instructions.get(j).accept(mv);

            StringBuffer s = new StringBuffer();
            Frame<FrameValue> f = frames[j];
            if (f == null) {
                s.append('?');
            } else {
                for (int k = 0; k < f.getLocals(); ++k) {
                    s.append(getShortName(f.getLocal(k).toString())).append(' ');
                }
                s.append(" : ");
                for (int k = 0; k < f.getStackSize(); ++k) {
                    s.append(getShortName(f.getStack(k).toString())).append(' ');
                }
            }
            while (s.length() < method.maxStack + method.maxLocals + 1) {
                s.append(' ');
            }
            pw.print(Integer.toString(j + 100000).substring(1));
            pw.print(" " + s + " : " + t.text.get(t.text.size() - 1));
        }
        for (int j = 0; j < method.tryCatchBlocks.size(); ++j) {
            method.tryCatchBlocks.get(j).accept(mv);
            pw.print(" " + t.text.get(t.text.size() - 1));
        }
        pw.println();
    }

    private static String getShortName(final String name) {
        int n = name.lastIndexOf('/');
        int k = name.length();
        if (name.charAt(k - 1) == ';') {
            k--;
        }
        return (name.startsWith("(uninitialized)") ? "(U)" : "") + (n == -1 ? name : name.substring(n + 1, k));
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        final MethodVisitor superVisitor = super.visitMethod(access, name, desc, signature, exceptions);
        final Map<Label, LabelNode> labelNodes = new HashMap<Label, LabelNode>();
        final FrameVerifier verifier = new FrameVerifier(vm, loader, holograms);

        MethodNode analyzer = new MethodNode(access, name, desc, null, null) {
            @Override
            public void visitEnd() {
                FrameAnalyzer a = new FrameAnalyzer(verifier);
                Frame<FrameValue>[] frames = null;
                try {
                    frames = a.analyze(thisType.getInternalName(), this);
                    if (superVisitor != null) {
                        if (insertFrames) {
                            frames = a.insertFrames();
                        }
                        accept(superVisitor);
                    }
                } catch (Throwable e) {
                    if (e instanceof IndexOutOfBoundsException && maxLocals == 0 && maxStack == 0) {
                        throw new RuntimeException(
                                "Data flow checking option requires valid, non zero maxLocals and maxStack values.");
                    }
                    if (frames == null) {
                        frames = a.getFrames();
                    }
                    StringWriter sw = new StringWriter();
                    PrintWriter pw = new PrintWriter(sw, true);
                    printAnalyzerResult(this, frames, pw);
                    pw.close();
                    throw new RuntimeException(sw.toString(), e);
                }
            }

            @Override
            protected LabelNode getLabelNode(Label l) {
                LabelNode node = labelNodes.get(l);
                if (node == null) {
                    node = new LabelNode(l);
                    labelNodes.put(l, node);
                }
                return node;
            }
        };

        analyzer.instructions = new FrameInsnList();

        // Inline subroutines since other pieces of the pipeline can't handle them
        return new JSRInlinerAdapter(analyzer, access, name, desc, signature, exceptions);
    }

    private class FrameInsnList extends InsnList {

        @Override
        public void accept(MethodVisitor mv) {
            final int size = size();
            for (int i = 0; i < size; i++) {
                try {
                    get(i).accept(mv);
                } catch (RuntimeException e) {
                    throw new RuntimeException("Error at instruction " + i, e);
                }
            }
        }

    }
}