operand
parameter of the
* {@link org.objectweb.asm.MethodVisitor#visitIntInsn} method when
* opcode
is NEWARRAY
.
*/
public static final String[] TYPES;
static {
String s = "NOP,ACONST_NULL,ICONST_M1,ICONST_0,ICONST_1,ICONST_2,"
+ "ICONST_3,ICONST_4,ICONST_5,LCONST_0,LCONST_1,FCONST_0,"
+ "FCONST_1,FCONST_2,DCONST_0,DCONST_1,BIPUSH,SIPUSH,LDC,,,"
+ "ILOAD,LLOAD,FLOAD,DLOAD,ALOAD,,,,,,,,,,,,,,,,,,,,,IALOAD,"
+ "LALOAD,FALOAD,DALOAD,AALOAD,BALOAD,CALOAD,SALOAD,ISTORE,"
+ "LSTORE,FSTORE,DSTORE,ASTORE,,,,,,,,,,,,,,,,,,,,,IASTORE,"
+ "LASTORE,FASTORE,DASTORE,AASTORE,BASTORE,CASTORE,SASTORE,POP,"
+ "POP2,DUP,DUP_X1,DUP_X2,DUP2,DUP2_X1,DUP2_X2,SWAP,IADD,LADD,"
+ "FADD,DADD,ISUB,LSUB,FSUB,DSUB,IMUL,LMUL,FMUL,DMUL,IDIV,LDIV,"
+ "FDIV,DDIV,IREM,LREM,FREM,DREM,INEG,LNEG,FNEG,DNEG,ISHL,LSHL,"
+ "ISHR,LSHR,IUSHR,LUSHR,IAND,LAND,IOR,LOR,IXOR,LXOR,IINC,I2L,"
+ "I2F,I2D,L2I,L2F,L2D,F2I,F2L,F2D,D2I,D2L,D2F,I2B,I2C,I2S,LCMP,"
+ "FCMPL,FCMPG,DCMPL,DCMPG,IFEQ,IFNE,IFLT,IFGE,IFGT,IFLE,"
+ "IF_ICMPEQ,IF_ICMPNE,IF_ICMPLT,IF_ICMPGE,IF_ICMPGT,IF_ICMPLE,"
+ "IF_ACMPEQ,IF_ACMPNE,GOTO,JSR,RET,TABLESWITCH,LOOKUPSWITCH,"
+ "IRETURN,LRETURN,FRETURN,DRETURN,ARETURN,RETURN,GETSTATIC,"
+ "PUTSTATIC,GETFIELD,PUTFIELD,INVOKEVIRTUAL,INVOKESPECIAL,"
+ "INVOKESTATIC,INVOKEINTERFACE,INVOKEDYNAMIC,NEW,NEWARRAY,"
+ "ANEWARRAY,ARRAYLENGTH,ATHROW,CHECKCAST,INSTANCEOF,"
+ "MONITORENTER,MONITOREXIT,,MULTIANEWARRAY,IFNULL,IFNONNULL,";
OPCODES = new String[200];
int i = 0;
int j = 0;
int l;
while ((l = s.indexOf(',', j)) > 0) {
OPCODES[i++] = j + 1 == l ? null : s.substring(j, l);
j = l + 1;
}
s = "T_BOOLEAN,T_CHAR,T_FLOAT,T_DOUBLE,T_BYTE,T_SHORT,T_INT,T_LONG,";
TYPES = new String[12];
j = 0;
i = 4;
while ((l = s.indexOf(',', j)) > 0) {
TYPES[i++] = s.substring(j, l);
j = l + 1;
}
}
/**
* The text to be printed. Since the code of methods is not necessarily
* visited in sequential order, one method after the other, but can be
* interlaced (some instructions from method one, then some instructions
* from method two, then some instructions from method one again...), it is
* not possible to print the visited instructions directly to a sequential
* stream. A class is therefore printed in a two steps process: a string
* tree is constructed during the visit, and printed to a sequential stream
* at the end of the visit. This string tree is stored in this field, as a
* string list that can contain other string lists, which can themselves
* contain other string lists, and so on.
*/
public final List text;
/**
* A buffer that can be used to create strings.
*/
protected final StringBuffer buf;
/**
* Constructs a new {@link AbstractVisitor}.
*/
protected AbstractVisitor() {
this.text = new ArrayList();
this.buf = new StringBuffer();
}
/**
* Returns the text constructed by this visitor.
*
* @return the text constructed by this visitor.
*/
public List getText() {
return text;
}
/**
* Prints the text constructed by this visitor.
*
* @param pw the print writer to be used.
*/
public void print(final PrintWriter pw) {
printList(pw, text);
}
/**
* Appends a quoted string to a given buffer.
*
* @param buf the buffer where the string must be added.
* @param s the string to be added.
*/
public static void appendString(final StringBuffer buf, final String s) {
buf.append('\"');
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (c == '\n') {
buf.append("\\n");
} else if (c == '\r') {
buf.append("\\r");
} else if (c == '\\') {
buf.append("\\\\");
} else if (c == '"') {
buf.append("\\\"");
} else if (c < 0x20 || c > 0x7f) {
buf.append("\\u");
if (c < 0x10) {
buf.append("000");
} else if (c < 0x100) {
buf.append("00");
} else if (c < 0x1000) {
buf.append('0');
}
buf.append(Integer.toString(c, 16));
} else {
buf.append(c);
}
}
buf.append('\"');
}
/**
* Prints the given string tree.
*
* @param pw the writer to be used to print the tree.
* @param l a string tree, i.e., a string list that can contain other string
* lists, and so on recursively.
*/
static void printList(final PrintWriter pw, final List l) {
for (int i = 0; i < l.size(); ++i) {
Object o = l.get(i);
if (o instanceof List) {
printList(pw, (List) o);
} else {
pw.print(o.toString());
}
}
}
/**
* Returns the default {@link ASMifiable} prototypes.
*
* @return the default {@link ASMifiable} prototypes.
*/
public static Attribute[] getDefaultAttributes() {
return new Attribute[0];
}
}
asm-3.3.2/src/org/objectweb/asm/util/ASMifierAbstractVisitor.java 0000644 0001750 0001750 00000020372 10701747173 024675 0 ustar twerner twerner /***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm.util;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Type;
import java.util.Map;
/**
* An abstract ASMifier visitor.
*
* @author Eric Bruneton
*/
public class ASMifierAbstractVisitor extends AbstractVisitor {
/**
* The name of the variable for this visitor in the produced code.
*/
protected String name;
/**
* The label names. This map associates String values to Label keys. It is
* used only in ASMifierMethodVisitor.
*/
Map labelNames;
/**
* Constructs a new {@link ASMifierAbstractVisitor}.
*
* @param name the name of the variable for this visitor in the produced
* code.
*/
protected ASMifierAbstractVisitor(final String name) {
this.name = name;
}
/**
* Prints the ASM code that generates the given annotation.
*
* @param desc the class descriptor of the annotation class.
* @param visible true if the annotation is visible at runtime.
* @return a visitor to visit the annotation values.
*/
public AnnotationVisitor visitAnnotation(
final String desc,
final boolean visible)
{
buf.setLength(0);
buf.append("{\n")
.append("av0 = ")
.append(name)
.append(".visitAnnotation(");
appendConstant(desc);
buf.append(", ").append(visible).append(");\n");
text.add(buf.toString());
ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
text.add(av.getText());
text.add("}\n");
return av;
}
/**
* Prints the ASM code that generates the given attribute.
*
* @param attr an attribute.
*/
public void visitAttribute(final Attribute attr) {
buf.setLength(0);
buf.append("// ATTRIBUTE ").append(attr.type).append('\n');
if (attr instanceof ASMifiable) {
buf.append("{\n");
((ASMifiable) attr).asmify(buf, "attr", labelNames);
buf.append(name).append(".visitAttribute(attr);\n");
buf.append("}\n");
}
text.add(buf.toString());
}
/**
* Prints the ASM code to end the visit.
*/
public void visitEnd() {
buf.setLength(0);
buf.append(name).append(".visitEnd();\n");
text.add(buf.toString());
}
/**
* Appends a string representation of the given constant to the given
* buffer.
*
* @param cst an {@link Integer}, {@link Float}, {@link Long},
* {@link Double} or {@link String} object. May be null.
*/
void appendConstant(final Object cst) {
appendConstant(buf, cst);
}
/**
* Appends a string representation of the given constant to the given
* buffer.
*
* @param buf a string buffer.
* @param cst an {@link Integer}, {@link Float}, {@link Long},
* {@link Double} or {@link String} object. May be null.
*/
static void appendConstant(final StringBuffer buf, final Object cst) {
if (cst == null) {
buf.append("null");
} else if (cst instanceof String) {
appendString(buf, (String) cst);
} else if (cst instanceof Type) {
buf.append("Type.getType(\"");
buf.append(((Type) cst).getDescriptor());
buf.append("\")");
} else if (cst instanceof Byte) {
buf.append("new Byte((byte)").append(cst).append(')');
} else if (cst instanceof Boolean) {
buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE");
} else if (cst instanceof Short) {
buf.append("new Short((short)").append(cst).append(')');
} else if (cst instanceof Character) {
int c = ((Character) cst).charValue();
buf.append("new Character((char)").append(c).append(')');
} else if (cst instanceof Integer) {
buf.append("new Integer(").append(cst).append(')');
} else if (cst instanceof Float) {
buf.append("new Float(\"").append(cst).append("\")");
} else if (cst instanceof Long) {
buf.append("new Long(").append(cst).append("L)");
} else if (cst instanceof Double) {
buf.append("new Double(\"").append(cst).append("\")");
} else if (cst instanceof byte[]) {
byte[] v = (byte[]) cst;
buf.append("new byte[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",").append(v[i]);
}
buf.append('}');
} else if (cst instanceof boolean[]) {
boolean[] v = (boolean[]) cst;
buf.append("new boolean[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",").append(v[i]);
}
buf.append('}');
} else if (cst instanceof short[]) {
short[] v = (short[]) cst;
buf.append("new short[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]);
}
buf.append('}');
} else if (cst instanceof char[]) {
char[] v = (char[]) cst;
buf.append("new char[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",")
.append("(char)")
.append((int) v[i]);
}
buf.append('}');
} else if (cst instanceof int[]) {
int[] v = (int[]) cst;
buf.append("new int[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",").append(v[i]);
}
buf.append('}');
} else if (cst instanceof long[]) {
long[] v = (long[]) cst;
buf.append("new long[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",").append(v[i]).append('L');
}
buf.append('}');
} else if (cst instanceof float[]) {
float[] v = (float[]) cst;
buf.append("new float[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",").append(v[i]).append('f');
}
buf.append('}');
} else if (cst instanceof double[]) {
double[] v = (double[]) cst;
buf.append("new double[] {");
for (int i = 0; i < v.length; i++) {
buf.append(i == 0 ? "" : ",").append(v[i]).append('d');
}
buf.append('}');
}
}
}
asm-3.3.2/src/org/objectweb/asm/util/package.html 0000644 0001750 0001750 00000003771 10177716604 021616 0 ustar twerner twerner
Provides ASM visitors that can be useful for programming and
debugging purposes. These class visitors are normally not used by applications
at runtime. This is why they are bundled in an optional asm-util.jar
library that is separated from (but requires) the asm.jar library,
which contains the core ASM framework.
@since ASM 1.3.2
asm-3.3.2/src/org/objectweb/asm/util/TraceSignatureVisitor.java 0000644 0001750 0001750 00000021417 10701747173 024473 0 ustar twerner twerner /***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm.util;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* A {@link SignatureVisitor} that prints a disassembled view of the signature
* it visits.
*
* @author Eugene Kuleshov
* @author Eric Bruneton
*/
public class TraceSignatureVisitor implements SignatureVisitor {
private final StringBuffer declaration;
private boolean isInterface;
private boolean seenFormalParameter;
private boolean seenInterfaceBound;
private boolean seenParameter;
private boolean seenInterface;
private StringBuffer returnType;
private StringBuffer exceptions;
/**
* Stack used to keep track of class types that have arguments. Each element
* of this stack is a boolean encoded in one bit. The top of the stack is
* the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
* /2.
*/
private int argumentStack;
/**
* Stack used to keep track of array class types. Each element of this stack
* is a boolean encoded in one bit. The top of the stack is the lowest order
* bit. Pushing false = *2, pushing true = *2+1, popping = /2.
*/
private int arrayStack;
private String separator = "";
public TraceSignatureVisitor(final int access) {
isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
this.declaration = new StringBuffer();
}
private TraceSignatureVisitor(final StringBuffer buf) {
this.declaration = buf;
}
public void visitFormalTypeParameter(final String name) {
declaration.append(seenFormalParameter ? ", " : "<").append(name);
seenFormalParameter = true;
seenInterfaceBound = false;
}
public SignatureVisitor visitClassBound() {
separator = " extends ";
startType();
return this;
}
public SignatureVisitor visitInterfaceBound() {
separator = seenInterfaceBound ? ", " : " extends ";
seenInterfaceBound = true;
startType();
return this;
}
public SignatureVisitor visitSuperclass() {
endFormals();
separator = " extends ";
startType();
return this;
}
public SignatureVisitor visitInterface() {
separator = seenInterface ? ", " : isInterface
? " extends "
: " implements ";
seenInterface = true;
startType();
return this;
}
public SignatureVisitor visitParameterType() {
endFormals();
if (seenParameter) {
declaration.append(", ");
} else {
seenParameter = true;
declaration.append('(');
}
startType();
return this;
}
public SignatureVisitor visitReturnType() {
endFormals();
if (seenParameter) {
seenParameter = false;
} else {
declaration.append('(');
}
declaration.append(')');
returnType = new StringBuffer();
return new TraceSignatureVisitor(returnType);
}
public SignatureVisitor visitExceptionType() {
if (exceptions == null) {
exceptions = new StringBuffer();
} else {
exceptions.append(", ");
}
// startType();
return new TraceSignatureVisitor(exceptions);
}
public void visitBaseType(final char descriptor) {
switch (descriptor) {
case 'V':
declaration.append("void");
break;
case 'B':
declaration.append("byte");
break;
case 'J':
declaration.append("long");
break;
case 'Z':
declaration.append("boolean");
break;
case 'I':
declaration.append("int");
break;
case 'S':
declaration.append("short");
break;
case 'C':
declaration.append("char");
break;
case 'F':
declaration.append("float");
break;
// case 'D':
default:
declaration.append("double");
break;
}
endType();
}
public void visitTypeVariable(final String name) {
declaration.append(name);
endType();
}
public SignatureVisitor visitArrayType() {
startType();
arrayStack |= 1;
return this;
}
public void visitClassType(final String name) {
if ("java/lang/Object".equals(name)) {
// MapCheckClassAdapter
can be also used to verify bytecode
* transformations in order to make sure transformed bytecode is sane. For
* example:
*
*
* InputStream is = ...; // get bytes for the source class * ClassReader cr = new ClassReader(is); * ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); * ClassVisitor cv = new MyClassAdapter(new CheckClassAdapter(cw)); * cr.accept(cv, 0); * * StringWriter sw = new StringWriter(); * PrintWriter pw = new PrintWriter(sw); * CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw); * assertTrue(sw.toString(), sw.toString().length()==0); ** * Above code runs transformed bytecode trough the *
CheckClassAdapter
. It won't be exactly the same verification
* as JVM does, but it run data flow analysis for the code of each method and
* checks that expectations are met for each method instruction.
*
* If method bytecode has errors, assertion text will show the erroneous * instruction number and dump of the failed method with information about * locals and stack slot for each instruction. For example (format is - * insnNumber locals : stack): * *
* org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found . * at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289) * at org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135) * ... * remove()V * 00000 LinkedBlockingQueue$Itr . . . . . . . . : * ICONST_0 * 00001 LinkedBlockingQueue$Itr . . . . . . . . : I * ISTORE 2 * 00001 LinkedBlockingQueue$Itr . I . . . . . . : * ... * * 00071 LinkedBlockingQueue$Itr . I . . . . . . : * ILOAD 1 * 00072 ? * INVOKESPECIAL java/lang/Integer.* * In the above output you can see that variable 1 loaded by *(I)V * ... *
ILOAD 1
instruction at position 00071
is not
* initialized. You can also see that at the beginning of the method (code
* inserted by the transformation) variable 2 is initialized.
*
* Note that when used like that, CheckClassAdapter.verify()
* can trigger additional class loading, because it is using
* SimpleVerifier
.
*
* @author Eric Bruneton
*/
public class CheckClassAdapter extends ClassAdapter {
/**
* The class version number.
*/
private int version;
/**
* true if the visit method has been called.
*/
private boolean start;
/**
* true if the visitSource method has been called.
*/
private boolean source;
/**
* true if the visitOuterClass method has been called.
*/
private boolean outer;
/**
* true if the visitEnd method has been called.
*/
private boolean end;
/**
* The already visited labels. This map associate Integer values to Label
* keys.
*/
private Map labels;
/**
* true if the method code must be checked with a BasicVerifier.
*/
private boolean checkDataFlow;
/**
* Checks a given class.
Usage: CheckClassAdapter <binary
* class name or class file name>
*
* @param args the command line arguments.
*
* @throws Exception if the class cannot be found, or if an IO exception
* occurs.
*/
public static void main(final String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Verifies the given class.");
System.err.println("Usage: CheckClassAdapter "
+ " Usage: ASMifierClassVisitor [-debug] <binary
* class name or class file name>
*
* @param args the command line arguments.
*
* @throws Exception if the class cannot be found, or if an IO exception
* occurs.
*/
public static void main(final String[] args) throws Exception {
int i = 0;
int flags = ClassReader.SKIP_DEBUG;
boolean ok = true;
if (args.length < 1 || args.length > 2) {
ok = false;
}
if (ok && "-debug".equals(args[0])) {
i = 1;
flags = 0;
if (args.length != 2) {
ok = false;
}
}
if (!ok) {
System.err.println("Prints the ASM code to generate the given class.");
System.err.println("Usage: ASMifierClassVisitor [-debug] "
+ " The trace printed when
* visiting the Hello class is the following:
* Usage: TraceClassVisitor [-debug] <binary class name or class
* file name >
*
* @param args the command line arguments.
*
* @throws Exception if the class cannot be found, or if an IO exception
* occurs.
*/
public static void main(final String[] args) throws Exception {
int i = 0;
int flags = ClassReader.SKIP_DEBUG;
boolean ok = true;
if (args.length < 1 || args.length > 2) {
ok = false;
}
if (ok && "-debug".equals(args[0])) {
i = 1;
flags = 0;
if (args.length != 2) {
ok = false;
}
}
if (!ok) {
System.err.println("Prints a disassembled view of the given class.");
System.err.println("Usage: TraceClassVisitor [-debug] "
+ "ClassReader
that contains bytecode for the
* analysis.
* @param loader a ClassLoader
which will be used to load
* referenced classes. This is useful if you are verifiying multiple
* interdependent classes.
* @param dump true if bytecode should be printed out not only when errors
* are found.
* @param pw write where results going to be printed
*/
public static void verify(
final ClassReader cr,
final ClassLoader loader,
final boolean dump,
final PrintWriter pw)
{
ClassNode cn = new ClassNode();
cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG);
Type syperType = cn.superName == null
? null
: Type.getObjectType(cn.superName);
List methods = cn.methods;
List interfaces = new ArrayList();
for (Iterator i = cn.interfaces.iterator(); i.hasNext();) {
interfaces.add(Type.getObjectType(i.next().toString()));
}
for (int i = 0; i < methods.size(); ++i) {
MethodNode method = (MethodNode) methods.get(i);
SimpleVerifier verifier = new SimpleVerifier(Type.getObjectType(cn.name),
syperType,
interfaces,
(cn.access | Opcodes.ACC_INTERFACE) != 0);
Analyzer a = new Analyzer(verifier);
if (loader != null) {
verifier.setClassLoader(loader);
}
try {
a.analyze(cn.name, method);
if (!dump) {
continue;
}
} catch (Exception e) {
e.printStackTrace(pw);
}
printAnalyzerResult(method, a, pw);
}
pw.flush();
}
/**
* Checks a given class
*
* @param cr a ClassReader
that contains bytecode for the
* analysis.
* @param dump true if bytecode should be printed out not only when errors
* are found.
* @param pw write where results going to be printed
*/
public static void verify(
final ClassReader cr,
final boolean dump,
final PrintWriter pw)
{
verify(cr, null, dump, pw);
}
static void printAnalyzerResult(
MethodNode method,
Analyzer a,
final PrintWriter pw)
{
Frame[] frames = a.getFrames();
TraceMethodVisitor mv = new TraceMethodVisitor();
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 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 + " : " + mv.buf); // mv.text.get(j));
}
for (int j = 0; j < method.tryCatchBlocks.size(); ++j) {
((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv);
pw.print(" " + mv.buf);
}
pw.println();
}
private static String getShortName(final String name) {
int n = name.lastIndexOf('/');
int k = name.length();
if (name.charAt(k - 1) == ';') {
k--;
}
return n == -1 ? name : name.substring(n + 1, k);
}
/**
* Constructs a new {@link CheckClassAdapter}.
*
* @param cv the class visitor to which this adapter must delegate calls.
*/
public CheckClassAdapter(final ClassVisitor cv) {
this(cv, true);
}
/**
* Constructs a new {@link CheckClassAdapter}.
*
* @param cv the class visitor to which this adapter must delegate calls.
* @param checkDataFlow true to perform basic data flow checks, or
* false to not perform any data flow check (see
* {@link CheckMethodAdapter}). This option requires valid maxLocals
* and maxStack values.
*/
public CheckClassAdapter(final ClassVisitor cv, boolean checkDataFlow) {
super(cv);
this.labels = new HashMap();
this.checkDataFlow = checkDataFlow;
}
// ------------------------------------------------------------------------
// Implementation of the ClassVisitor interface
// ------------------------------------------------------------------------
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces)
{
if (start) {
throw new IllegalStateException("visit must be called only once");
}
start = true;
checkState();
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
+ Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
+ Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
+ Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
+ Opcodes.ACC_DEPRECATED
+ 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
if (name == null || !name.endsWith("package-info")) {
CheckMethodAdapter.checkInternalName(name, "class name");
}
if ("java/lang/Object".equals(name)) {
if (superName != null) {
throw new IllegalArgumentException("The super class name of the Object class must be 'null'");
}
} else {
CheckMethodAdapter.checkInternalName(superName, "super class name");
}
if (signature != null) {
CheckMethodAdapter.checkClassSignature(signature);
}
if ((access & Opcodes.ACC_INTERFACE) != 0) {
if (!"java/lang/Object".equals(superName)) {
throw new IllegalArgumentException("The super class name of interfaces must be 'java/lang/Object'");
}
}
if (interfaces != null) {
for (int i = 0; i < interfaces.length; ++i) {
CheckMethodAdapter.checkInternalName(interfaces[i],
"interface name at index " + i);
}
}
this.version = version;
cv.visit(version, access, name, signature, superName, interfaces);
}
public void visitSource(final String file, final String debug) {
checkState();
if (source) {
throw new IllegalStateException("visitSource can be called only once.");
}
source = true;
cv.visitSource(file, debug);
}
public void visitOuterClass(
final String owner,
final String name,
final String desc)
{
checkState();
if (outer) {
throw new IllegalStateException("visitOuterClass can be called only once.");
}
outer = true;
if (owner == null) {
throw new IllegalArgumentException("Illegal outer class owner");
}
if (desc != null) {
CheckMethodAdapter.checkMethodDesc(desc);
}
cv.visitOuterClass(owner, name, desc);
}
public void visitInnerClass(
final String name,
final String outerName,
final String innerName,
final int access)
{
checkState();
CheckMethodAdapter.checkInternalName(name, "class name");
if (outerName != null) {
CheckMethodAdapter.checkInternalName(outerName, "outer class name");
}
if (innerName != null) {
CheckMethodAdapter.checkIdentifier(innerName, "inner class name");
}
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
+ Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE
+ Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
+ Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM);
cv.visitInnerClass(name, outerName, innerName, access);
}
public FieldVisitor visitField(
final int access,
final String name,
final String desc,
final String signature,
final Object value)
{
checkState();
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
+ Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE
+ Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC
+ Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED
+ 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
CheckMethodAdapter.checkDesc(desc, false);
if (signature != null) {
CheckMethodAdapter.checkFieldSignature(signature);
}
if (value != null) {
CheckMethodAdapter.checkConstant(value);
}
FieldVisitor av = cv.visitField(access, name, desc, signature, value);
return new CheckFieldAdapter(av);
}
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions)
{
checkState();
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
+ Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED
+ Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE
+ Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT
+ Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED
+ 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
CheckMethodAdapter.checkMethodIdentifier(version, name, "method name");
CheckMethodAdapter.checkMethodDesc(desc);
if (signature != null) {
CheckMethodAdapter.checkMethodSignature(signature);
}
if (exceptions != null) {
for (int i = 0; i < exceptions.length; ++i) {
CheckMethodAdapter.checkInternalName(exceptions[i],
"exception name at index " + i);
}
}
CheckMethodAdapter cma;
if (checkDataFlow) {
cma = new CheckMethodAdapter(access,
name,
desc,
cv.visitMethod(access, name, desc, signature, exceptions),
labels);
} else {
cma = new CheckMethodAdapter(cv.visitMethod(access,
name,
desc,
signature,
exceptions), labels);
}
cma.version = version;
return cma;
}
public AnnotationVisitor visitAnnotation(
final String desc,
final boolean visible)
{
checkState();
CheckMethodAdapter.checkDesc(desc, false);
return new CheckAnnotationAdapter(cv.visitAnnotation(desc, visible));
}
public void visitAttribute(final Attribute attr) {
checkState();
if (attr == null) {
throw new IllegalArgumentException("Invalid attribute (must not be null)");
}
cv.visitAttribute(attr);
}
public void visitEnd() {
checkState();
end = true;
cv.visitEnd();
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Checks that the visit method has been called and that visitEnd has not
* been called.
*/
private void checkState() {
if (!start) {
throw new IllegalStateException("Cannot visit member before visit has been called.");
}
if (end) {
throw new IllegalStateException("Cannot visit member after visitEnd has been called.");
}
}
/**
* Checks that the given access flags do not contain invalid flags. This
* method also checks that mutually incompatible flags are not set
* simultaneously.
*
* @param access the access flags to be checked
* @param possibleAccess the valid access flags.
*/
static void checkAccess(final int access, final int possibleAccess) {
if ((access & ~possibleAccess) != 0) {
throw new IllegalArgumentException("Invalid access flags: "
+ access);
}
int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1;
int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1;
int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1;
if (pub + pri + pro > 1) {
throw new IllegalArgumentException("public private and protected are mutually exclusive: "
+ access);
}
int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1;
int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1;
if (fin + abs > 1) {
throw new IllegalArgumentException("final and abstract are mutually exclusive: "
+ access);
}
}
}
asm-3.3.2/src/org/objectweb/asm/util/ASMifierClassVisitor.java 0000644 0001750 0001750 00000043716 11525262537 024207 0 ustar twerner twerner /***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm.util;
import java.io.FileInputStream;
import java.io.PrintWriter;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A {@link ClassVisitor} that prints the ASM code that generates the classes it
* visits. This class visitor can be used to quickly write ASM code to generate
* some given bytecode:
The source code printed when visiting the
* Hello class is the following:
*
*
where Hello is defined by:
* import org.objectweb.asm.*;
*
* public class HelloDump implements Opcodes {
*
* public static byte[] dump() throws Exception {
*
* ClassWriter cw = new ClassWriter(0);
* FieldVisitor fv;
* MethodVisitor mv;
* AnnotationVisitor av0;
*
* cw.visit(49,
* ACC_PUBLIC + ACC_SUPER,
* "Hello",
* null,
* "java/lang/Object",
* null);
*
* cw.visitSource("Hello.java", null);
*
* {
* mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
* mv.visitVarInsn(ALOAD, 0);
* mv.visitMethodInsn(INVOKESPECIAL,
* "java/lang/Object",
* "<init>",
* "()V");
* mv.visitInsn(RETURN);
* mv.visitMaxs(1, 1);
* mv.visitEnd();
* }
* {
* mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
* "main",
* "([Ljava/lang/String;)V",
* null,
* null);
* mv.visitFieldInsn(GETSTATIC,
* "java/lang/System",
* "out",
* "Ljava/io/PrintStream;");
* mv.visitLdcInsn("hello");
* mv.visitMethodInsn(INVOKEVIRTUAL,
* "java/io/PrintStream",
* "println",
* "(Ljava/lang/String;)V");
* mv.visitInsn(RETURN);
* mv.visitMaxs(2, 1);
* mv.visitEnd();
* }
* cw.visitEnd();
*
* return cw.toByteArray();
* }
* }
*
*
*
*
*
*
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public class ASMifierClassVisitor extends ASMifierAbstractVisitor implements
ClassVisitor
{
/**
* Pseudo access flag used to distinguish class access flags.
*/
private static final int ACCESS_CLASS = 262144;
/**
* Pseudo access flag used to distinguish field access flags.
*/
private static final int ACCESS_FIELD = 524288;
/**
* Pseudo access flag used to distinguish inner class flags.
*/
private static final int ACCESS_INNER = 1048576;
/**
* The print writer to be used to print the class.
*/
protected final PrintWriter pw;
/**
* Prints the ASM source code to generate the given class to the standard
* output.
* public class Hello {
*
* public static void main(String[] args) {
* System.out.println("hello");
* }
* }
*
*
*
*
*
where Hello is defined by:
* // class version 49.0 (49)
* // access flags 0x21
* public class Hello {
*
* // compiled from: Hello.java
*
* // access flags 0x1
* public <init> ()V
* ALOAD 0
* INVOKESPECIAL java/lang/Object <init> ()V
* RETURN
* MAXSTACK = 1
* MAXLOCALS = 1
*
* // access flags 0x9
* public static main ([Ljava/lang/String;)V
* GETSTATIC java/lang/System out Ljava/io/PrintStream;
* LDC "hello"
* INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V
* RETURN
* MAXSTACK = 2
* MAXLOCALS = 1
* }
*
*
*
*
*
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public class TraceClassVisitor extends TraceAbstractVisitor implements
ClassVisitor
{
/**
* The {@link ClassVisitor} to which this visitor delegates calls. May be
* null.
*/
protected final ClassVisitor cv;
/**
* The print writer to be used to print the class.
*/
protected final PrintWriter pw;
/**
* Prints a disassembled view of the given class to the standard output.
* public class Hello {
*
* public static void main(String[] args) {
* System.out.println("hello");
* }
* }
*
*
*
* ClassWriter cw = new ClassWriter(...);
* ClassVisitor sv = new SerialVersionUIDAdder(cw);
* ClassVisitor ca = new MyClassAdapter(sv);
* new ClassReader(orginalClass).accept(ca, false);
*
*
* The SVUID algorithm can be found http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html:
*
*
* The serialVersionUID is computed using the signature of a stream of bytes
* that reflect the class definition. The National Institute of Standards and
* Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
* signature for the stream. The first two 32-bit quantities are used to form a
* 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
* types to a sequence of bytes. The values input to the stream are defined by
* the Java Virtual Machine (VM) specification for classes.
*
* The sequence of items in the stream is as follows:
*
* 1. The class name written using UTF encoding.
* 2. The class modifiers written as a 32-bit integer.
* 3. The name of each interface sorted by name written using UTF encoding.
* 4. For each field of the class sorted by field name (except private static
* and private transient fields):
* 1. The name of the field in UTF encoding.
* 2. The modifiers of the field written as a 32-bit integer.
* 3. The descriptor of the field in UTF encoding
* 5. If a class initializer exists, write out the following:
* 1. The name of the method, <clinit>, in UTF encoding.
* 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
* written as a 32-bit integer.
* 3. The descriptor of the method, ()V, in UTF encoding.
* 6. For each non-private constructor sorted by method name and signature:
* 1. The name of the method, <init>, in UTF encoding.
* 2. The modifiers of the method written as a 32-bit integer.
* 3. The descriptor of the method in UTF encoding.
* 7. For each non-private method sorted by method name and signature:
* 1. The name of the method in UTF encoding.
* 2. The modifiers of the method written as a 32-bit integer.
* 3. The descriptor of the method in UTF encoding.
* 8. The SHA-1 algorithm is executed on the stream of bytes produced by
* DataOutputStream and produces five 32-bit values sha[0..4].
*
* 9. The hash value is assembled from the first and second 32-bit values of
* the SHA-1 message digest. If the result of the message digest, the five
* 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
* sha, the hash value would be computed as follows:
*
* long hash = ((sha[0] >>> 24) & 0xFF) |
* ((sha[0] >>> 16) & 0xFF) << 8 |
* ((sha[0] >>> 8) & 0xFF) << 16 |
* ((sha[0] >>> 0) & 0xFF) << 24 |
* ((sha[1] >>> 24) & 0xFF) << 32 |
* ((sha[1] >>> 16) & 0xFF) << 40 |
* ((sha[1] >>> 8) & 0xFF) << 48 |
* ((sha[1] >>> 0) & 0xFF) << 56;
*
*
* @author Rajendra Inamdar, Vishal Vishnoi
*/
public class SerialVersionUIDAdder extends ClassAdapter {
/**
* Flag that indicates if we need to compute SVUID.
*/
protected boolean computeSVUID;
/**
* Set to true if the class already has SVUID.
*/
protected boolean hasSVUID;
/**
* Classes access flags.
*/
protected int access;
/**
* Internal name of the class
*/
protected String name;
/**
* Interfaces implemented by the class.
*/
protected String[] interfaces;
/**
* Collection of fields. (except private static and private transient
* fields)
*/
protected Collection svuidFields;
/**
* Set to true if the class has static initializer.
*/
protected boolean hasStaticInitializer;
/**
* Collection of non-private constructors.
*/
protected Collection svuidConstructors;
/**
* Collection of non-private methods.
*/
protected Collection svuidMethods;
/**
* Creates a new {@link SerialVersionUIDAdder}.
*
* @param cv a {@link ClassVisitor} to which this visitor will delegate
* calls.
*/
public SerialVersionUIDAdder(final ClassVisitor cv) {
super(cv);
svuidFields = new ArrayList();
svuidConstructors = new ArrayList();
svuidMethods = new ArrayList();
}
// ------------------------------------------------------------------------
// Overriden methods
// ------------------------------------------------------------------------
/*
* Visit class header and get class name, access , and interfaces
* information (step 1,2, and 3) for SVUID computation.
*/
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces)
{
computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0;
if (computeSVUID) {
this.name = name;
this.access = access;
this.interfaces = interfaces;
}
super.visit(version, access, name, signature, superName, interfaces);
}
/*
* Visit the methods and get constructor and method information (step 5 and
* 7). Also determine if there is a class initializer (step 6).
*/
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions)
{
if (computeSVUID) {
if ("isHasSVUID
to determine if the class already had an SVUID.
*
* @return Returns the serial version UID
*/
protected long computeSVUID() throws IOException {
ByteArrayOutputStream bos;
DataOutputStream dos = null;
long svuid = 0;
try {
bos = new ByteArrayOutputStream();
dos = new DataOutputStream(bos);
/*
* 1. The class name written using UTF encoding.
*/
dos.writeUTF(name.replace('/', '.'));
/*
* 2. The class modifiers written as a 32-bit integer.
*/
dos.writeInt(access
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
| Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
/*
* 3. The name of each interface sorted by name written using UTF
* encoding.
*/
Arrays.sort(interfaces);
for (int i = 0; i < interfaces.length; i++) {
dos.writeUTF(interfaces[i].replace('/', '.'));
}
/*
* 4. For each field of the class sorted by field name (except
* private static and private transient fields):
*
* 1. The name of the field in UTF encoding. 2. The modifiers of the
* field written as a 32-bit integer. 3. The descriptor of the field
* in UTF encoding
*
* Note that field signatures are not dot separated. Method and
* constructor signatures are dot separated. Go figure...
*/
writeItems(svuidFields, dos, false);
/*
* 5. If a class initializer exists, write out the following: 1. The
* name of the method, DataOutputStream
value
* @param dotted a boolean
value
* @exception IOException if an error occurs
*/
private static void writeItems(
final Collection itemCollection,
final DataOutput dos,
final boolean dotted) throws IOException
{
int size = itemCollection.size();
Item[] items = (Item[]) itemCollection.toArray(new Item[size]);
Arrays.sort(items);
for (int i = 0; i < size; i++) {
dos.writeUTF(items[i].name);
dos.writeInt(items[i].access);
dos.writeUTF(dotted
? items[i].desc.replace('/', '.')
: items[i].desc);
}
}
// ------------------------------------------------------------------------
// Inner classes
// ------------------------------------------------------------------------
static class Item implements Comparable {
final String name;
final int access;
final String desc;
Item(final String name, final int access, final String desc) {
this.name = name;
this.access = access;
this.desc = desc;
}
public int compareTo(final Object o) {
Item other = (Item) o;
int retVal = name.compareTo(other.name);
if (retVal == 0) {
retVal = desc.compareTo(other.desc);
}
return retVal;
}
}
}
asm-3.3.2/src/org/objectweb/asm/commons/RemappingFieldAdapter.java 0000644 0001750 0001750 00000005033 11302173367 025050 0 ustar twerner twerner /***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm.commons;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.FieldVisitor;
/**
* A FieldVisitor
adapter for type remapping.
*
* @author Eugene Kuleshov
*/
public class RemappingFieldAdapter implements FieldVisitor {
private final FieldVisitor fv;
private final Remapper remapper;
public RemappingFieldAdapter(FieldVisitor fv, Remapper remapper) {
this.fv = fv;
this.remapper = remapper;
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), visible);
return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
}
public void visitAttribute(Attribute attr) {
fv.visitAttribute(attr);
}
public void visitEnd() {
fv.visitEnd();
}
}
asm-3.3.2/src/org/objectweb/asm/commons/EmptyVisitor.java 0000644 0001750 0001750 00000013616 10701747173 023351 0 ustar twerner twerner /***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm.commons;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
/**
* An empty implementation of the ASM visitor interfaces.
*
* @author Eric Bruneton
*/
public class EmptyVisitor implements
ClassVisitor,
FieldVisitor,
MethodVisitor,
AnnotationVisitor
{
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces)
{
}
public void visitSource(final String source, final String debug) {
}
public void visitOuterClass(
final String owner,
final String name,
final String desc)
{
}
public AnnotationVisitor visitAnnotation(
final String desc,
final boolean visible)
{
return this;
}
public void visitAttribute(final Attribute attr) {
}
public void visitInnerClass(
final String name,
final String outerName,
final String innerName,
final int access)
{
}
public FieldVisitor visitField(
final int access,
final String name,
final String desc,
final String signature,
final Object value)
{
return this;
}
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions)
{
return this;
}
public void visitEnd() {
}
public AnnotationVisitor visitAnnotationDefault() {
return this;
}
public AnnotationVisitor visitParameterAnnotation(
final int parameter,
final String desc,
final boolean visible)
{
return this;
}
public void visitCode() {
}
public void visitFrame(
final int type,
final int nLocal,
final Object[] local,
final int nStack,
final Object[] stack)
{
}
public void visitInsn(final int opcode) {
}
public void visitIntInsn(final int opcode, final int operand) {
}
public void visitVarInsn(final int opcode, final int var) {
}
public void visitTypeInsn(final int opcode, final String type) {
}
public void visitFieldInsn(
final int opcode,
final String owner,
final String name,
final String desc)
{
}
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String desc)
{
}
public void visitJumpInsn(final int opcode, final Label label) {
}
public void visitLabel(final Label label) {
}
public void visitLdcInsn(final Object cst) {
}
public void visitIincInsn(final int var, final int increment) {
}
public void visitTableSwitchInsn(
final int min,
final int max,
final Label dflt,
final Label[] labels)
{
}
public void visitLookupSwitchInsn(
final Label dflt,
final int[] keys,
final Label[] labels)
{
}
public void visitMultiANewArrayInsn(final String desc, final int dims) {
}
public void visitTryCatchBlock(
final Label start,
final Label end,
final Label handler,
final String type)
{
}
public void visitLocalVariable(
final String name,
final String desc,
final String signature,
final Label start,
final Label end,
final int index)
{
}
public void visitLineNumber(final int line, final Label start) {
}
public void visitMaxs(final int maxStack, final int maxLocals) {
}
public void visit(final String name, final Object value) {
}
public void visitEnum(
final String name,
final String desc,
final String value)
{
}
public AnnotationVisitor visitAnnotation(
final String name,
final String desc)
{
return this;
}
public AnnotationVisitor visitArray(final String name) {
return this;
}
}
asm-3.3.2/src/org/objectweb/asm/commons/GeneratorAdapter.java 0000644 0001750 0001750 00000135404 11211477631 024116 0 ustar twerner twerner /***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm.commons;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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;
/**
* A {@link org.objectweb.asm.MethodAdapter} with convenient methods to generate
* code. For example, using this adapter, the class below
*
*
* public class Example {
* public static void main(String[] args) {
* System.out.println("Hello world!");
* }
* }
*
*
* can be generated as follows:
*
*
* ClassWriter cw = new ClassWriter(true);
* cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);
*
* Method m = Method.getMethod("void <init> ()");
* GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
* mg.loadThis();
* mg.invokeConstructor(Type.getType(Object.class), m);
* mg.returnValue();
* mg.endMethod();
*
* m = Method.getMethod("void main (String[])");
* mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
* mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
* mg.push("Hello world!");
* mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)"));
* mg.returnValue();
* mg.endMethod();
*
* cw.visitEnd();
*
*
* @author Juozas Baliuka
* @author Chris Nokleberg
* @author Eric Bruneton
*/
public class GeneratorAdapter extends LocalVariablesSorter {
private static final String CLDESC = "Ljava/lang/Class;";
private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
private static final Method INT_VALUE = Method.getMethod("int intValue()");
private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()");
private static final Method LONG_VALUE = Method.getMethod("long longValue()");
private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
/**
* Constant for the {@link #math math} method.
*/
public static final int ADD = Opcodes.IADD;
/**
* Constant for the {@link #math math} method.
*/
public static final int SUB = Opcodes.ISUB;
/**
* Constant for the {@link #math math} method.
*/
public static final int MUL = Opcodes.IMUL;
/**
* Constant for the {@link #math math} method.
*/
public static final int DIV = Opcodes.IDIV;
/**
* Constant for the {@link #math math} method.
*/
public static final int REM = Opcodes.IREM;
/**
* Constant for the {@link #math math} method.
*/
public static final int NEG = Opcodes.INEG;
/**
* Constant for the {@link #math math} method.
*/
public static final int SHL = Opcodes.ISHL;
/**
* Constant for the {@link #math math} method.
*/
public static final int SHR = Opcodes.ISHR;
/**
* Constant for the {@link #math math} method.
*/
public static final int USHR = Opcodes.IUSHR;
/**
* Constant for the {@link #math math} method.
*/
public static final int AND = Opcodes.IAND;
/**
* Constant for the {@link #math math} method.
*/
public static final int OR = Opcodes.IOR;
/**
* Constant for the {@link #math math} method.
*/
public static final int XOR = Opcodes.IXOR;
/**
* Constant for the {@link #ifCmp ifCmp} method.
*/
public static final int EQ = Opcodes.IFEQ;
/**
* Constant for the {@link #ifCmp ifCmp} method.
*/
public static final int NE = Opcodes.IFNE;
/**
* Constant for the {@link #ifCmp ifCmp} method.
*/
public static final int LT = Opcodes.IFLT;
/**
* Constant for the {@link #ifCmp ifCmp} method.
*/
public static final int GE = Opcodes.IFGE;
/**
* Constant for the {@link #ifCmp ifCmp} method.
*/
public static final int GT = Opcodes.IFGT;
/**
* Constant for the {@link #ifCmp ifCmp} method.
*/
public static final int LE = Opcodes.IFLE;
/**
* Access flags of the method visited by this adapter.
*/
private final int access;
/**
* Return type of the method visited by this adapter.
*/
private final Type returnType;
/**
* Argument types of the method visited by this adapter.
*/
private final Type[] argumentTypes;
/**
* Types of the local variables of the method visited by this adapter.
*/
private final List localTypes = new ArrayList();
/**
* Creates a new {@link GeneratorAdapter}.
*
* @param mv the method visitor to which this adapter delegates calls.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}).
*/
public GeneratorAdapter(
final MethodVisitor mv,
final int access,
final String name,
final String desc)
{
super(access, desc, mv);
this.access = access;
this.returnType = Type.getReturnType(desc);
this.argumentTypes = Type.getArgumentTypes(desc);
}
/**
* Creates a new {@link GeneratorAdapter}.
*
* @param access access flags of the adapted method.
* @param method the adapted method.
* @param mv the method visitor to which this adapter delegates calls.
*/
public GeneratorAdapter(
final int access,
final Method method,
final MethodVisitor mv)
{
super(access, method.getDescriptor(), mv);
this.access = access;
this.returnType = method.getReturnType();
this.argumentTypes = method.getArgumentTypes();
}
/**
* Creates a new {@link GeneratorAdapter}.
*
* @param access access flags of the adapted method.
* @param method the adapted method.
* @param signature the signature of the adapted method (may be
* null).
* @param exceptions the exceptions thrown by the adapted method (may be
* null).
* @param cv the class visitor to which this adapter delegates calls.
*/
public GeneratorAdapter(
final int access,
final Method method,
final String signature,
final Type[] exceptions,
final ClassVisitor cv)
{
this(access, method, cv.visitMethod(access,
method.getName(),
method.getDescriptor(),
signature,
getInternalNames(exceptions)));
}
/**
* Returns the internal names of the given types.
*
* @param types a set of types.
* @return the internal names of the given types.
*/
private static String[] getInternalNames(final Type[] types) {
if (types == null) {
return null;
}
String[] names = new String[types.length];
for (int i = 0; i < names.length; ++i) {
names[i] = types[i].getInternalName();
}
return names;
}
// ------------------------------------------------------------------------
// Instructions to push constants on the stack
// ------------------------------------------------------------------------
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final boolean value) {
push(value ? 1 : 0);
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final long value) {
if (value == 0L || value == 1L) {
mv.visitInsn(Opcodes.LCONST_0 + (int) value);
} else {
mv.visitLdcInsn(new Long(value));
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final float value) {
int bits = Float.floatToIntBits(value);
if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
mv.visitInsn(Opcodes.FCONST_0 + (int) value);
} else {
mv.visitLdcInsn(new Float(value));
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final double value) {
long bits = Double.doubleToLongBits(value);
if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
mv.visitInsn(Opcodes.DCONST_0 + (int) value);
} else {
mv.visitLdcInsn(new Double(value));
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack. May be null.
*/
public void push(final String value) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
mv.visitLdcInsn(value);
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final Type value) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
switch (value.getSort()) {
case Type.BOOLEAN:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Boolean",
"TYPE",
CLDESC);
break;
case Type.CHAR:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Character",
"TYPE",
CLDESC);
break;
case Type.BYTE:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Byte",
"TYPE",
CLDESC);
break;
case Type.SHORT:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Short",
"TYPE",
CLDESC);
break;
case Type.INT:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Integer",
"TYPE",
CLDESC);
break;
case Type.FLOAT:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Float",
"TYPE",
CLDESC);
break;
case Type.LONG:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Long",
"TYPE",
CLDESC);
break;
case Type.DOUBLE:
mv.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/Double",
"TYPE",
CLDESC);
break;
default:
mv.visitLdcInsn(value);
}
}
}
// ------------------------------------------------------------------------
// Instructions to load and store method arguments
// ------------------------------------------------------------------------
/**
* Returns the index of the given method argument in the frame's local
* variables array.
*
* @param arg the index of a method argument.
* @return the index of the given method argument in the frame's local
* variables array.
*/
private int getArgIndex(final int arg) {
int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
/**
* Generates the instruction to push a local variable on the stack.
*
* @param type the type of the local variable to be loaded.
* @param index an index in the frame's local variables array.
*/
private void loadInsn(final Type type, final int index) {
mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
}
/**
* Generates the instruction to store the top stack value in a local
* variable.
*
* @param type the type of the local variable to be stored.
* @param index an index in the frame's local variables array.
*/
private void storeInsn(final Type type, final int index) {
mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
}
/**
* Generates the instruction to load 'this' on the stack.
*/
public void loadThis() {
if ((access & Opcodes.ACC_STATIC) != 0) {
throw new IllegalStateException("no 'this' pointer within static method");
}
mv.visitVarInsn(Opcodes.ALOAD, 0);
}
/**
* Generates the instruction to load the given method argument on the stack.
*
* @param arg the index of a method argument.
*/
public void loadArg(final int arg) {
loadInsn(argumentTypes[arg], getArgIndex(arg));
}
/**
* Generates the instructions to load the given method arguments on the
* stack.
*
* @param arg the index of the first method argument to be loaded.
* @param count the number of method arguments to be loaded.
*/
public void loadArgs(final int arg, final int count) {
int index = getArgIndex(arg);
for (int i = 0; i < count; ++i) {
Type t = argumentTypes[arg + i];
loadInsn(t, index);
index += t.getSize();
}
}
/**
* Generates the instructions to load all the method arguments on the stack.
*/
public void loadArgs() {
loadArgs(0, argumentTypes.length);
}
/**
* Generates the instructions to load all the method arguments on the stack,
* as a single object array.
*/
public void loadArgArray() {
push(argumentTypes.length);
newArray(OBJECT_TYPE);
for (int i = 0; i < argumentTypes.length; i++) {
dup();
push(i);
loadArg(i);
box(argumentTypes[i]);
arrayStore(OBJECT_TYPE);
}
}
/**
* Generates the instruction to store the top stack value in the given
* method argument.
*
* @param arg the index of a method argument.
*/
public void storeArg(final int arg) {
storeInsn(argumentTypes[arg], getArgIndex(arg));
}
// ------------------------------------------------------------------------
// Instructions to load and store local variables
// ------------------------------------------------------------------------
/**
* Returns the type of the given local variable.
*
* @param local a local variable identifier, as returned by
* {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
* @return the type of the given local variable.
*/
public Type getLocalType(final int local) {
return (Type) localTypes.get(local - firstLocal);
}
protected void setLocalType(final int local, final Type type) {
int index = local - firstLocal;
while (localTypes.size() < index + 1) {
localTypes.add(null);
}
localTypes.set(index, type);
}
/**
* Generates the instruction to load the given local variable on the stack.
*
* @param local a local variable identifier, as returned by
* {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
*/
public void loadLocal(final int local) {
loadInsn(getLocalType(local), local);
}
/**
* Generates the instruction to load the given local variable on the stack.
*
* @param local a local variable identifier, as returned by
* {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
* @param type the type of this local variable.
*/
public void loadLocal(final int local, final Type type) {
setLocalType(local, type);
loadInsn(type, local);
}
/**
* Generates the instruction to store the top stack value in the given local
* variable.
*
* @param local a local variable identifier, as returned by
* {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
*/
public void storeLocal(final int local) {
storeInsn(getLocalType(local), local);
}
/**
* Generates the instruction to store the top stack value in the given local
* variable.
*
* @param local a local variable identifier, as returned by
* {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
* @param type the type of this local variable.
*/
public void storeLocal(final int local, final Type type) {
setLocalType(local, type);
storeInsn(type, local);
}
/**
* Generates the instruction to load an element from an array.
*
* @param type the type of the array element to be loaded.
*/
public void arrayLoad(final Type type) {
mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
}
/**
* Generates the instruction to store an element in an array.
*
* @param type the type of the array element to be stored.
*/
public void arrayStore(final Type type) {
mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
}
// ------------------------------------------------------------------------
// Instructions to manage the stack
// ------------------------------------------------------------------------
/**
* Generates a POP instruction.
*/
public void pop() {
mv.visitInsn(Opcodes.POP);
}
/**
* Generates a POP2 instruction.
*/
public void pop2() {
mv.visitInsn(Opcodes.POP2);
}
/**
* Generates a DUP instruction.
*/
public void dup() {
mv.visitInsn(Opcodes.DUP);
}
/**
* Generates a DUP2 instruction.
*/
public void dup2() {
mv.visitInsn(Opcodes.DUP2);
}
/**
* Generates a DUP_X1 instruction.
*/
public void dupX1() {
mv.visitInsn(Opcodes.DUP_X1);
}
/**
* Generates a DUP_X2 instruction.
*/
public void dupX2() {
mv.visitInsn(Opcodes.DUP_X2);
}
/**
* Generates a DUP2_X1 instruction.
*/
public void dup2X1() {
mv.visitInsn(Opcodes.DUP2_X1);
}
/**
* Generates a DUP2_X2 instruction.
*/
public void dup2X2() {
mv.visitInsn(Opcodes.DUP2_X2);
}
/**
* Generates a SWAP instruction.
*/
public void swap() {
mv.visitInsn(Opcodes.SWAP);
}
/**
* Generates the instructions to swap the top two stack values.
*
* @param prev type of the top - 1 stack value.
* @param type type of the top stack value.
*/
public void swap(final Type prev, final Type type) {
if (type.getSize() == 1) {
if (prev.getSize() == 1) {
swap(); // same as dupX1(), pop();
} else {
dupX2();
pop();
}
} else {
if (prev.getSize() == 1) {
dup2X1();
pop2();
} else {
dup2X2();
pop2();
}
}
}
// ------------------------------------------------------------------------
// Instructions to do mathematical and logical operations
// ------------------------------------------------------------------------
/**
* Generates the instruction to do the specified mathematical or logical
* operation.
*
* @param op a mathematical or logical operation. Must be one of ADD, SUB,
* MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
* @param type the type of the operand(s) for this operation.
*/
public void math(final int op, final Type type) {
mv.visitInsn(type.getOpcode(op));
}
/**
* Generates the instructions to compute the bitwise negation of the top
* stack value.
*/
public void not() {
mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.IXOR);
}
/**
* Generates the instruction to increment the given local variable.
*
* @param local the local variable to be incremented.
* @param amount the amount by which the local variable must be incremented.
*/
public void iinc(final int local, final int amount) {
mv.visitIincInsn(local, amount);
}
/**
* Generates the instructions to cast a numerical value from one type to
* another.
*
* @param from the type of the top stack value
* @param to the type into which this value must be cast.
*/
public void cast(final Type from, final Type to) {
if (from != to) {
if (from == Type.DOUBLE_TYPE) {
if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.D2F);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.D2L);
} else {
mv.visitInsn(Opcodes.D2I);
cast(Type.INT_TYPE, to);
}
} else if (from == Type.FLOAT_TYPE) {
if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.F2D);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.F2L);
} else {
mv.visitInsn(Opcodes.F2I);
cast(Type.INT_TYPE, to);
}
} else if (from == Type.LONG_TYPE) {
if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.L2D);
} else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.L2F);
} else {
mv.visitInsn(Opcodes.L2I);
cast(Type.INT_TYPE, to);
}
} else {
if (to == Type.BYTE_TYPE) {
mv.visitInsn(Opcodes.I2B);
} else if (to == Type.CHAR_TYPE) {
mv.visitInsn(Opcodes.I2C);
} else if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.I2D);
} else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.I2F);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.I2L);
} else if (to == Type.SHORT_TYPE) {
mv.visitInsn(Opcodes.I2S);
}
}
}
}
// ------------------------------------------------------------------------
// Instructions to do boxing and unboxing operations
// ------------------------------------------------------------------------
private static Type getBoxedType(final Type type) {
switch (type.getSort()) {
case Type.BYTE:
return BYTE_TYPE;
case Type.BOOLEAN:
return BOOLEAN_TYPE;
case Type.SHORT:
return SHORT_TYPE;
case Type.CHAR:
return CHARACTER_TYPE;
case Type.INT:
return INTEGER_TYPE;
case Type.FLOAT:
return FLOAT_TYPE;
case Type.LONG:
return LONG_TYPE;
case Type.DOUBLE:
return DOUBLE_TYPE;
}
return type;
}
/**
* Generates the instructions to box the top stack value. This value is
* replaced by its boxed equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void box(final Type type) {
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
return;
}
if (type == Type.VOID_TYPE) {
push((String) null);
} else {
Type boxed = getBoxedType(type);
newInstance(boxed);
if (type.getSize() == 2) {
// Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
dupX2();
dupX2();
pop();
} else {
// p -> po -> opo -> oop -> o
dupX1();
swap();
}
invokeConstructor(boxed, new Method("List
of the local variable slots for current execution
* frame. Primitive types are represented by {@link Opcodes#TOP},
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
* two elements, the second one being TOP). Reference types are represented
* by String objects (representing internal names), and uninitialized types
* by Label objects (this label designates the NEW instruction that created
* this uninitialized value). This field is null for unreacheable
* instructions.
*/
public List locals;
/**
* List
of the operand stack slots for current execution
* frame. Primitive types are represented by {@link Opcodes#TOP},
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
* two elements, the second one being TOP). Reference types are represented
* by String objects (representing internal names), and uninitialized types
* by Label objects (this label designates the NEW instruction that created
* this uninitialized value). This field is null for unreacheable
* instructions.
*/
public List stack;
/**
* The labels that designate the next instruction to be visited. May be
* null.
*/
private List labels;
/**
* Information about uninitialized types in the current execution frame.
* This map associates internal names to Label objects. Each label
* designates a NEW instruction that created the currently uninitialized
* types, and the associated internal name represents the NEW operand, i.e.
* the final, initialized type value.
*/
public Map uninitializedTypes;
/**
* The maximum stack size of this method.
*/
private int maxStack;
/**
* The maximum number of local variables of this method.
*/
private int maxLocals;
/**
* The owner's class name.
*/
private String owner;
/**
* Creates a new {@link AnalyzerAdapter}.
*
* @param owner the owner's class name.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}).
* @param mv the method visitor to which this adapter delegates calls. May
* be null.
*/
public AnalyzerAdapter(
final String owner,
final int access,
final String name,
final String desc,
final MethodVisitor mv)
{
super(mv);
this.owner = owner;
locals = new ArrayList();
stack = new ArrayList();
uninitializedTypes = new HashMap();
if ((access & Opcodes.ACC_STATIC) == 0) {
if ("