Commit 8f3833a6 authored by andrei's avatar andrei

Update to the latest ASM 4.0 RC2 API state. ASMifier code does not support...

Update to the latest ASM 4.0 RC2 API state. ASMifier code does not support navigation yet (missing indices)
parent bab64a41
......@@ -8,31 +8,26 @@
*******************************************************************************/
package de.loskutov.bco.asm;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.BitSet;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.ASMifierClassVisitor;
import org.objectweb.asm.util.ASMifierVisitor;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.util.ASMifier;
import de.loskutov.bco.preferences.BCOConstants;
/**
* @author Andrei
*/
public class CommentedASMifierClassVisitor extends ASMifierVisitor implements ICommentedClassVisitor {
protected BitSet modes;
protected boolean raw;
protected boolean showLines;
protected boolean showLocals;
protected boolean showStackMap;
private ASMifierClassVisitor classVisitor;
public class CommentedASMifierClassVisitor extends ASMifier implements ICommentedClassVisitor {
protected final boolean showLines;
protected final boolean showLocals;
protected final boolean showStackMap;
private final DecompilerOptions options;
private String javaVersion;
private int accessFlags;
@Override
public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) {
if (showStackMap) {
......@@ -40,12 +35,14 @@ public class CommentedASMifierClassVisitor extends ASMifierVisitor implements IC
}
}
@Override
public void visitLineNumber(int line, Label start) {
if (showLines) {
super.visitLineNumber(line, start);
}
}
@Override
public void visitLocalVariable(String name1, String desc,
String signature, Label start, Label end, int index) {
if (showLocals) {
......@@ -54,41 +51,52 @@ public class CommentedASMifierClassVisitor extends ASMifierVisitor implements IC
}
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
//if (showLocals) {
super.visitMaxs(maxStack, maxLocals);
//}
// if (showLocals) {
super.visitMaxs(maxStack, maxLocals);
// }
}
private CommentedASMifierClassVisitor(final BitSet modes, String name, int id) {
private CommentedASMifierClassVisitor(final DecompilerOptions options, String name, int id) {
super(Opcodes.ASM4, name, id);
this.modes = modes;
raw = !modes.get(BCOConstants.F_SHOW_RAW_BYTECODE);
showLines = modes.get(BCOConstants.F_SHOW_LINE_INFO);
showLocals = modes.get(BCOConstants.F_SHOW_VARIABLES);
showStackMap = modes.get(BCOConstants.F_SHOW_STACKMAP);
this.options = options;
showLines = options.modes.get(BCOConstants.F_SHOW_LINE_INFO);
showLocals = options.modes.get(BCOConstants.F_SHOW_VARIABLES);
showStackMap = options.modes.get(BCOConstants.F_SHOW_STACKMAP);
}
public CommentedASMifierClassVisitor(final BitSet modes) {
this(modes, "cw", 0);
public CommentedASMifierClassVisitor(ClassNode classNode, final DecompilerOptions options) {
this(options, "cw", 0);
}
public void visitEnd() {
text.add("cw.visitEnd();\n\n");
text.add("return cw.toByteArray();\n");
text.add("}\n");
text.add("}\n");
@Override
public void visit(int version, int access, String name1, String signature,
String superName, String[] interfaces) {
if(decompilingEntireClass()) {
super.visit(version, access, name1, signature, superName, interfaces);
}
int major = version & 0xFFFF;
//int minor = version >>> 16;
// 1.1 is 45, 1.2 is 46 etc.
int javaV = major % 44;
if (javaV > 0 && javaV < 10) {
javaVersion = "1." + javaV;
}
this.accessFlags = access;
}
public ClassVisitor getClassVisitor() {
if(classVisitor == null) {
// TODO ASM 4.0 transition: PrintWriter should be optional
classVisitor = new ASMifierClassVisitor(this, new PrintWriter(new StringWriter()));
}
return classVisitor;
private boolean decompilingEntireClass() {
return options.methodFilter == null && options.fieldFilter == null;
}
@Override
protected ASMifier createASMifier(String name1, int id1) {
return new CommentedASMifierClassVisitor(options, name1, id1);
}
protected ASMifierVisitor createASMifierVisitor(String name1, int id1) {
return new CommentedASMifierClassVisitor(modes, name1, id1);
@Override
public DecompiledClassInfo getClassInfo() {
return new DecompiledClassInfo(javaVersion, accessFlags);
}
}
/*******************************************************************************
* Copyright (c) 2011 Andrey Loskutov. All rights reserved. This program and the
* accompanying materials are made available under the terms of the BSD License which
* accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php Contributor: Andrey Loskutov -
* initial API and implementation
*******************************************************************************/
package de.loskutov.bco.asm;
public class DecompiledClassInfo {
public final String javaVersion;
public final int accessFlags;
public DecompiledClassInfo(String javaVersion, int accessFlags) {
this.javaVersion = javaVersion;
this.accessFlags = accessFlags;
}
}
/*******************************************************************************
* Copyright (c) 2011 Eric Bruneton.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the BSD License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php
* Contributor: Eric Bruneton - initial API and implementation
* Contributor: Andrey Loskutov - fixes
*******************************************************************************/
package de.loskutov.bco.asm;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
......@@ -9,6 +17,7 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.LocalVariableNode;
......@@ -70,7 +79,7 @@ public class DecompiledMethod {
*/
private int lastSourceLine;
private final MethodNode meth;
MethodNode meth;
private Frame[] frames;
......@@ -81,9 +90,20 @@ public class DecompiledMethod {
private final String owner;
public DecompiledMethod(final String owner, final List inputText,
final Map lineNumbers, final MethodNode meth, final ClassLoader cl, BitSet modes) {
private final Map lineNumbers;
private final DecompilerOptions options;
private final int access;
public DecompiledMethod(final String owner,
final Map lineNumbers, final MethodNode meth, DecompilerOptions options, int access) {
this.meth = meth;
this.owner = owner;
this.lineNumbers = lineNumbers;
this.options = options;
this.access = access;
this.text = new ArrayList();
this.localVariables = meth.localVariables;
this.sourceLines = new HashMap();
......@@ -91,17 +111,22 @@ public class DecompiledMethod {
this.insns = new HashMap();
this.opcodes = new HashMap();
this.insnLines = new HashMap();
}
this.meth = meth;
void setText(final List inputText) {
formatText(inputText, new HashMap(), new StringBuffer(), this.text);
computeMaps(lineNumbers);
if (modes.get(BCOConstants.F_SHOW_ANALYZER)
&& (meth.access & Opcodes.ACC_ABSTRACT) == 0) {
analyzeMethod(cl);
if (options.modes.get(BCOConstants.F_SHOW_ANALYZER)
&& (access & Opcodes.ACC_ABSTRACT) == 0) {
analyzeMethod(options.cl);
}
}
void addLineNumber(Label start, Integer integer) {
lineNumbers.put(start, integer);
}
public boolean isInit() {
return ("<init>".equals(meth.name) && "()V".equals(meth.desc))
|| "<clinit>".equals(meth.name);
......@@ -164,6 +189,7 @@ public class DecompiledMethod {
private void analyzeMethod(final ClassLoader cl) {
Analyzer a = new Analyzer(new SimpleVerifier() {
@Override
protected Class getClass(final Type t) {
try {
if (t.getSort() == Type.ARRAY) {
......@@ -231,12 +257,7 @@ public class DecompiledMethod {
}
}
/**
* @param i
* @param input
* @return
*/
private Index getNextIndex(List input, int startOffset) {
private static Index getNextIndex(List input, int startOffset) {
for (int i = startOffset + 1; i < input.size(); i++) {
Object object = input.get(i);
if(object instanceof Index){
......@@ -257,20 +278,20 @@ public class DecompiledMethod {
}
}
private void computeMaps(final Map lineNumbers) {
private void computeMaps(final Map lineNumbers1) {
int currentDecompiledLine = 0;
int firstLine = -1;
int lastLine = -1;
for (int i = 0; i < text.size(); ++i) {
int currentOpcode = -1;
int currentInsn = -1;
int currentInsn1 = -1;
int currentSourceLine = -1;
Object o = text.get(i);
if (o instanceof Index) {
Index index = (Index) o;
Integer sourceLine = null;
if(index.labelNode != null) {
sourceLine = (Integer) lineNumbers.get(index.labelNode.getLabel());
sourceLine = (Integer) lineNumbers1.get(index.labelNode.getLabel());
}
if (sourceLine != null) {
currentSourceLine = sourceLine.intValue();
......@@ -281,13 +302,13 @@ public class DecompiledMethod {
lastLine = currentSourceLine;
}
}
currentInsn = index.insn;
currentInsn1 = index.insn;
currentOpcode = index.opcode;
} else {
++currentDecompiledLine;
}
Integer cdl = new Integer(currentDecompiledLine);
Integer ci = new Integer(currentInsn);
Integer ci = new Integer(currentInsn1);
Integer co = new Integer(currentOpcode);
if(currentSourceLine >= 0){
Integer csl = new Integer(currentSourceLine);
......@@ -383,7 +404,7 @@ public class DecompiledMethod {
: i.intValue();
}
private void appendFrame(final StringBuffer buf, final Frame f) {
private static void appendFrame(final StringBuffer buf, final Frame f) {
try {
for (int i = 0; i < f.getLocals(); ++i) {
appendValue(buf, f.getLocal(i));
......@@ -393,12 +414,11 @@ public class DecompiledMethod {
appendValue(buf, f.getStack(i));
}
} catch (IndexOutOfBoundsException e) {
// TODO should we keep this?
BytecodeOutlinePlugin.log(e, IStatus.WARNING);
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
}
private void appendValue(final StringBuffer buf, final Value v) {
private static void appendValue(final StringBuffer buf, final Value v) {
if (((BasicValue) v).isReference()) {
buf.append("R");
} else {
......@@ -463,8 +483,7 @@ public class DecompiledMethod {
}
return new String[] {localsBuf.toString(), stackBuf.toString()};
} catch (IndexOutOfBoundsException e) {
// TODO should we keep this?
BytecodeOutlinePlugin.log(e, IStatus.WARNING);
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
}
return null;
......@@ -536,7 +555,6 @@ public class DecompiledMethod {
(String[][]) locals.toArray( new String[ 3][]),
(String[][]) stack.toArray( new String[ 2][])};
} catch (IndexOutOfBoundsException e) {
// TODO should we keep this?
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
}
......@@ -552,7 +570,7 @@ public class DecompiledMethod {
* @param buf buffer to append
* @param s string with bytecode type name, like "Ljava/lang/Object;"
*/
private void appendTypeName(int n, final boolean useQualifiedNames, StringBuffer buf, String s) {
private static void appendTypeName(int n, final boolean useQualifiedNames, StringBuffer buf, String s) {
buf.append(n).append( " ");
if(!useQualifiedNames) {
int idx = s.lastIndexOf('/');
......@@ -569,7 +587,7 @@ public class DecompiledMethod {
}
}
private String getTypeName(final boolean useQualifiedNames, String s) {
private static String getTypeName(final boolean useQualifiedNames, String s) {
if (!useQualifiedNames) {
// get leading array symbols
String arraySymbols = "";
......@@ -606,6 +624,7 @@ public class DecompiledMethod {
*
* @return <code>true</code> if this <code>DecompiledMethod</code> is the same as the o argument.
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
......@@ -618,6 +637,7 @@ public class DecompiledMethod {
&& (owner != null? owner.equals(another.owner) : true);
}
@Override
public int hashCode() {
return getSignature().hashCode() + (owner != null? owner.hashCode() : 0);
}
......
package de.loskutov.bco.asm;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.util.ASMifierMethodVisitor;
import org.objectweb.asm.util.TraceAnnotationVisitor;
import org.objectweb.asm.util.TraceMethodVisitor;
/**
* @author Eric Bruneton
*/
public class DecompilerMethodVisitor extends MethodVisitor {
private final String owner;
private final List text;
private final MethodNode meth;
private LabelNode currentLabel;
private int currentInsn;
private final Map lineNumbers;
private final BitSet modes;
public DecompilerMethodVisitor(final String owner, final MethodNode meth,
final MethodVisitor mv, BitSet modes) {
super(Opcodes.ASM4, mv);
this.owner = owner;
this.modes = modes;
// TODO ASM 4.0 transition: "tv" and "sv" fields are invisible for us in ASM 4.0 RC2
if(mv instanceof TraceMethodVisitor) {
this.text = ((TraceMethodVisitor)mv).tv.text;
} else {
this.text = ((ASMifierMethodVisitor)mv).sv.text;
}
this.meth = meth;
this.lineNumbers = new HashMap();
}
public DecompiledMethod getResult(final ClassLoader cl) {
return new DecompiledMethod(owner, text, lineNumbers, meth, cl, modes);
}
public AnnotationVisitor visitAnnotationDefault() {
AnnotationVisitor annVisitor = super.visitAnnotationDefault();
AnnotationVisitor visitor = meth.visitAnnotationDefault();
if (annVisitor instanceof TraceAnnotationVisitor) {
TraceAnnotationVisitor av = (TraceAnnotationVisitor) annVisitor;
// TODO ASM 4.0 transition: setNext() is invisible for us in ASM 4.0 RC2
av.setNext(visitor);
}
return annVisitor;
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor annVisitor = super.visitAnnotation(desc, visible);
AnnotationVisitor visitor = meth.visitAnnotation(desc, visible);
if (annVisitor instanceof TraceAnnotationVisitor) {
TraceAnnotationVisitor av = (TraceAnnotationVisitor) annVisitor;
// TODO ASM 4.0 transition: setNext() is invisible for us in ASM 4.0 RC2
av.setNext(visitor);
}
return annVisitor;
}
public AnnotationVisitor visitParameterAnnotation(int parameter,
String desc, boolean visible) {
AnnotationVisitor annVisitor = super.visitParameterAnnotation(
parameter, desc, visible);
AnnotationVisitor visitor = meth.visitParameterAnnotation(
parameter, desc, visible);
if (annVisitor instanceof TraceAnnotationVisitor) {
TraceAnnotationVisitor av = (TraceAnnotationVisitor) annVisitor;
// TODO ASM 4.0 transition: setNext() is invisible for us in ASM 4.0 RC2
av.setNext(visitor);
}
return annVisitor;
}
public void visitCode() {
super.visitCode();
meth.visitCode();
}
public void visitEnd() {
super.visitEnd();
meth.visitEnd();
}
public void visitAttribute(Attribute attr) {
super.visitAttribute(attr);
meth.visitAttribute(attr);
}
public void visitInsn(final int opcode) {
addIndex(opcode);
super.visitInsn(opcode);
meth.visitInsn(opcode);
}
public void visitIntInsn(final int opcode, final int operand) {
addIndex(opcode);
super.visitIntInsn(opcode, operand);
meth.visitIntInsn(opcode, operand);
}
public void visitVarInsn(final int opcode, final int var) {
addIndex(opcode);
super.visitVarInsn(opcode, var);
meth.visitVarInsn(opcode, var);
}
public void visitTypeInsn(final int opcode, final String desc) {
addIndex(opcode);
super.visitTypeInsn(opcode, desc);
meth.visitTypeInsn(opcode, desc);
}
public void visitFieldInsn(final int opcode, final String owner1,
final String name, final String desc) {
addIndex(opcode);
super.visitFieldInsn(opcode, owner1, name, desc);
meth.visitFieldInsn(opcode, owner1, name, desc);
}
public void visitMethodInsn(final int opcode, final String owner1,
final String name, final String desc) {
addIndex(opcode);
super.visitMethodInsn(opcode, owner1, name, desc);
meth.visitMethodInsn(opcode, owner1, name, desc);
}
public void visitJumpInsn(final int opcode, final Label label) {
addIndex(opcode);
super.visitJumpInsn(opcode, label);
meth.visitJumpInsn(opcode, label);
}
public void visitLabel(final Label label) {
addIndex(-1);
super.visitLabel(label);
meth.visitLabel(label);
currentLabel = (LabelNode) meth.instructions.getLast();
}
public void visitLdcInsn(final Object cst) {
addIndex(Opcodes.LDC);
super.visitLdcInsn(cst);
meth.visitLdcInsn(cst);
}
public void visitIincInsn(final int var, final int increment) {
addIndex(Opcodes.IINC);
super.visitIincInsn(var, increment);
meth.visitIincInsn(var, increment);
}
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label[] labels) {
addIndex(Opcodes.TABLESWITCH);
super.visitTableSwitchInsn(min, max, dflt, labels);
meth.visitTableSwitchInsn(min, max, dflt, labels);
}
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
addIndex(Opcodes.LOOKUPSWITCH);
super.visitLookupSwitchInsn(dflt, keys, labels);
meth.visitLookupSwitchInsn(dflt, keys, labels);
}
public void visitMultiANewArrayInsn(final String desc, final int dims) {
addIndex(Opcodes.MULTIANEWARRAY);
super.visitMultiANewArrayInsn(desc, dims);
meth.visitMultiANewArrayInsn(desc, dims);
}
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
super.visitTryCatchBlock(start, end, handler, type);
meth.visitTryCatchBlock(start, end, handler, type);
}
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
// localVariables.add(new LocalVariableNode(
// name, desc, signature, new LabelNode(start), new LabelNode(end), index));
super.visitLocalVariable(name, desc, signature, start, end, index);
meth.visitLocalVariable(name, desc, signature, start, end, index);
}
public void visitLineNumber(final int line, final Label start) {
addIndex(-1);
lineNumbers.put(start, new Integer(line));
super.visitLineNumber(line, start);
meth.visitLineNumber(line, start);
}
public void visitMaxs(final int maxStack, final int maxLocals) {
super.visitMaxs(maxStack, maxLocals);
meth.visitMaxs(maxStack, maxLocals);
}
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
Object[] stack) {
addIndex(-1);
super.visitFrame(type, nLocal, local, nStack, stack);
meth.visitFrame(type, nLocal, local, nStack, stack);
}
protected void addIndex(final int opcode) {
text.add(new Index(currentLabel, currentInsn++, opcode));
}
}
/*******************************************************************************
* Copyright (c) 2011 Andrey Loskutov. All rights reserved. This program and the
* accompanying materials are made available under the terms of the BSD License which
* accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php Contributor: Andrey Loskutov -
* initial API and implementation
*******************************************************************************/
package de.loskutov.bco.asm;
import java.util.BitSet;
public class DecompilerOptions {
public final String fieldFilter;
public final String methodFilter;
public final BitSet modes;
public final ClassLoader cl;
public DecompilerOptions(final String fieldFilter, final String methodFilter,
final BitSet modes, final ClassLoader cl) {
this.fieldFilter = fieldFilter;
this.methodFilter = methodFilter;
this.modes = modes;
this.cl = cl;
}
}
/*******************************************************************************
* Copyright (c) 2011 Andrey Loskutov.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the BSD License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php
* Contributor: Andrey Loskutov - initial API and implementation
*******************************************************************************/
package de.loskutov.bco.asm;
import java.util.List;
import org.objectweb.asm.ClassVisitor;
public interface ICommentedClassVisitor {
ClassVisitor getClassVisitor();
List getText();
DecompiledClassInfo getClassInfo();
}
/*****************************************************************************************
* Copyright (c) 2004 Andrei Loskutov. All rights reserved. This program and the
* Copyright (c) 2011 Andrey Loskutov. All rights reserved. This program and the
* accompanying materials are made available under the terms of the BSD License which
* accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php Contributor: Andrei Loskutov -
* http://www.opensource.org/licenses/bsd-license.php Contributor: Andrey Loskutov -
* initial API and implementation
****************************************************************************************/
......@@ -27,6 +27,7 @@ import org.eclipse.swt.widgets.Display;
import de.loskutov.bco.BytecodeOutlinePlugin;
import de.loskutov.bco.asm.DecompiledClass;
import de.loskutov.bco.asm.DecompilerClassVisitor;
import de.loskutov.bco.asm.DecompilerOptions;
import de.loskutov.bco.ui.JdtUtils;
/**
......@@ -72,6 +73,7 @@ public class TypedElement extends BufferedContent
/**
* @see org.eclipse.compare.ITypedElement#getName()
*/
@Override
public String getName() {
return name;
}
......@@ -80,6 +82,7 @@ public class TypedElement extends BufferedContent
/**
* @see org.eclipse.compare.ITypedElement#getType()
*/
@Override
public String getType() {
return type;
}
......@@ -98,15 +101,18 @@ public class TypedElement extends BufferedContent
return JdtUtils.getElementName(element);
}
@Override
public Image getImage() {
// default image for .class files
return CompareUI.getImage("class");
}
@Override
public Object[] getChildren() {
return new TypedElement[0];
}
@Override
protected InputStream createStream() throws CoreException {
InputStream stream = JdtUtils.createInputStream(element);
if (stream == null) {
......@@ -117,7 +123,7 @@ public class TypedElement extends BufferedContent
DecompiledClass decompiledClass = null;
try {