Moved to Maven

This commit is contained in:
JKetelaar
2015-09-13 22:51:13 +02:00
parent a3bf8d0d0d
commit 52836a3e9a
303 changed files with 56775 additions and 35 deletions
@@ -0,0 +1,326 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a bytecode instruction. <i>An instruction can appear
* at most once in at most one {@link InsnList} at a time</i>.
*
* @author Eric Bruneton
*/
public abstract class AbstractInsnNode {
/**
* The type of {@link InsnNode} instructions.
*/
public static final int INSN = 0;
/**
* The type of {@link IntInsnNode} instructions.
*/
public static final int INT_INSN = 1;
/**
* The type of {@link VarInsnNode} instructions.
*/
public static final int VAR_INSN = 2;
/**
* The type of {@link TypeInsnNode} instructions.
*/
public static final int TYPE_INSN = 3;
/**
* The type of {@link FieldInsnNode} instructions.
*/
public static final int FIELD_INSN = 4;
/**
* The type of {@link MethodInsnNode} instructions.
*/
public static final int METHOD_INSN = 5;
/**
* The type of {@link InvokeDynamicInsnNode} instructions.
*/
public static final int INVOKE_DYNAMIC_INSN = 6;
/**
* The type of {@link JumpInsnNode} instructions.
*/
public static final int JUMP_INSN = 7;
/**
* The type of {@link LabelNode} "instructions".
*/
public static final int LABEL = 8;
/**
* The type of {@link LdcInsnNode} instructions.
*/
public static final int LDC_INSN = 9;
/**
* The type of {@link IincInsnNode} instructions.
*/
public static final int IINC_INSN = 10;
/**
* The type of {@link TableSwitchInsnNode} instructions.
*/
public static final int TABLESWITCH_INSN = 11;
/**
* The type of {@link LookupSwitchInsnNode} instructions.
*/
public static final int LOOKUPSWITCH_INSN = 12;
/**
* The type of {@link MultiANewArrayInsnNode} instructions.
*/
public static final int MULTIANEWARRAY_INSN = 13;
/**
* The type of {@link FrameNode} "instructions".
*/
public static final int FRAME = 14;
/**
* The type of {@link LineNumberNode} "instructions".
*/
public static final int LINE = 15;
/**
* The opcode of this instruction.
*/
protected int opcode;
/**
* The runtime visible type annotations of this instruction. This field is
* only used for real instructions (i.e. not for labels, frames, or line
* number nodes). This list is a list of {@link TypeAnnotationNode} objects.
* May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations of this instruction. This field is
* only used for real instructions (i.e. not for labels, frames, or line
* number nodes). This list is a list of {@link TypeAnnotationNode} objects.
* May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* Previous instruction in the list to which this instruction belongs.
*/
AbstractInsnNode prev;
/**
* Next instruction in the list to which this instruction belongs.
*/
AbstractInsnNode next;
/**
* Index of this instruction in the list to which it belongs. The value of
* this field is correct only when {@link InsnList#cache} is not null. A
* value of -1 indicates that this instruction does not belong to any
* {@link InsnList}.
*/
int index;
/**
* Constructs a new {@link AbstractInsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed.
*/
protected AbstractInsnNode(final int opcode) {
this.opcode = opcode;
this.index = -1;
}
/**
* Returns the opcode of this instruction.
*
* @return the opcode of this instruction.
*/
public int getOpcode() {
return opcode;
}
/**
* Returns the type of this instruction.
*
* @return the type of this instruction, i.e. one the constants defined in
* this class.
*/
public abstract int getType();
/**
* Returns the previous instruction in the list to which this instruction
* belongs, if any.
*
* @return the previous instruction in the list to which this instruction
* belongs, if any. May be <tt>null</tt>.
*/
public AbstractInsnNode getPrevious() {
return prev;
}
/**
* Returns the next instruction in the list to which this instruction
* belongs, if any.
*
* @return the next instruction in the list to which this instruction
* belongs, if any. May be <tt>null</tt>.
*/
public AbstractInsnNode getNext() {
return next;
}
/**
* Makes the given code visitor visit this instruction.
*
* @param cv
* a code visitor.
*/
public abstract void accept(final MethodVisitor cv);
/**
* Makes the given visitor visit the annotations of this instruction.
*
* @param mv
* a method visitor.
*/
protected final void acceptAnnotations(final MethodVisitor mv) {
int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
true));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
false));
}
}
/**
* Returns a copy of this instruction.
*
* @param labels
* a map from LabelNodes to cloned LabelNodes.
* @return a copy of this instruction. The returned instruction does not
* belong to any {@link InsnList}.
*/
public abstract AbstractInsnNode clone(
final Map<LabelNode, LabelNode> labels);
/**
* Returns the clone of the given label.
*
* @param label
* a label.
* @param map
* a map from LabelNodes to cloned LabelNodes.
* @return the clone of the given label.
*/
static LabelNode clone(final LabelNode label,
final Map<LabelNode, LabelNode> map) {
return map.get(label);
}
/**
* Returns the clones of the given labels.
*
* @param labels
* a list of labels.
* @param map
* a map from LabelNodes to cloned LabelNodes.
* @return the clones of the given labels.
*/
static LabelNode[] clone(final List<LabelNode> labels,
final Map<LabelNode, LabelNode> map) {
LabelNode[] clones = new LabelNode[labels.size()];
for (int i = 0; i < clones.length; ++i) {
clones[i] = map.get(labels.get(i));
}
return clones;
}
/**
* Clones the annotations of the given instruction into this instruction.
*
* @param insn
* the source instruction.
* @return this instruction.
*/
protected final AbstractInsnNode cloneAnnotations(
final AbstractInsnNode insn) {
if (insn.visibleTypeAnnotations != null) {
this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
for (int i = 0; i < insn.visibleTypeAnnotations.size(); ++i) {
TypeAnnotationNode src = insn.visibleTypeAnnotations.get(i);
TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
src.typePath, src.desc);
src.accept(ann);
this.visibleTypeAnnotations.add(ann);
}
}
if (insn.invisibleTypeAnnotations != null) {
this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
for (int i = 0; i < insn.invisibleTypeAnnotations.size(); ++i) {
TypeAnnotationNode src = insn.invisibleTypeAnnotations.get(i);
TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
src.typePath, src.desc);
src.accept(ann);
this.invisibleTypeAnnotations.add(ann);
}
}
return this;
}
}
@@ -0,0 +1,226 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents an annotationn.
*
* @author Eric Bruneton
*/
public class AnnotationNode extends AnnotationVisitor {
/**
* The class descriptor of the annotation class.
*/
public String desc;
/**
* The name value pairs of this annotation. Each name value pair is stored
* as two consecutive elements in the list. The name is a {@link String},
* and the value may be a {@link Byte}, {@link Boolean}, {@link Character},
* {@link Short}, {@link Integer}, {@link Long}, {@link Float},
* {@link Double}, {@link String} or {@link org.objectweb.asm.Type}, or an
* two elements String array (for enumeration values), a
* {@link AnnotationNode}, or a {@link List} of values of one of the
* preceding types. The list may be <tt>null</tt> if there is no name value
* pair.
*/
public List<Object> values;
/**
* Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #AnnotationNode(int, String)} version.
*
* @param desc
* the class descriptor of the annotation class.
*/
public AnnotationNode(final String desc) {
this(Opcodes.ASM5, desc);
}
/**
* Constructs a new {@link AnnotationNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param desc
* the class descriptor of the annotation class.
*/
public AnnotationNode(final int api, final String desc) {
super(api);
this.desc = desc;
}
/**
* Constructs a new {@link AnnotationNode} to visit an array value.
*
* @param values
* where the visited values must be stored.
*/
AnnotationNode(final List<Object> values) {
super(Opcodes.ASM5);
this.values = values;
}
// ------------------------------------------------------------------------
// Implementation of the AnnotationVisitor abstract class
// ------------------------------------------------------------------------
@Override
public void visit(final String name, final Object value) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
}
values.add(value);
}
@Override
public void visitEnum(final String name, final String desc,
final String value) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
}
values.add(new String[] { desc, value });
}
@Override
public AnnotationVisitor visitAnnotation(final String name,
final String desc) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
}
AnnotationNode annotation = new AnnotationNode(desc);
values.add(annotation);
return annotation;
}
@Override
public AnnotationVisitor visitArray(final String name) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
}
List<Object> array = new ArrayList<Object>();
values.add(array);
return new AnnotationNode(array);
}
@Override
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Accept methods
// ------------------------------------------------------------------------
/**
* Checks that this annotation node is compatible with the given ASM API
* version. This methods checks that this node, and all its nodes
* recursively, do not contain elements that were introduced in more recent
* versions of the ASM API than the given version.
*
* @param api
* an ASM API version. Must be one of {@link Opcodes#ASM4} or
* {@link Opcodes#ASM5}.
*/
public void check(final int api) {
// nothing to do
}
/**
* Makes the given visitor visit this annotation.
*
* @param av
* an annotation visitor. Maybe <tt>null</tt>.
*/
public void accept(final AnnotationVisitor av) {
if (av != null) {
if (values != null) {
for (int i = 0; i < values.size(); i += 2) {
String name = (String) values.get(i);
Object value = values.get(i + 1);
accept(av, name, value);
}
}
av.visitEnd();
}
}
/**
* Makes the given visitor visit a given annotation value.
*
* @param av
* an annotation visitor. Maybe <tt>null</tt>.
* @param name
* the value name.
* @param value
* the actual value.
*/
static void accept(final AnnotationVisitor av, final String name,
final Object value) {
if (av != null) {
if (value instanceof String[]) {
String[] typeconst = (String[]) value;
av.visitEnum(name, typeconst[0], typeconst[1]);
} else if (value instanceof AnnotationNode) {
AnnotationNode an = (AnnotationNode) value;
an.accept(av.visitAnnotation(name, an.desc));
} else if (value instanceof List) {
AnnotationVisitor v = av.visitArray(name);
List<?> array = (List<?>) value;
for (int j = 0; j < array.size(); ++j) {
accept(v, null, array.get(j));
}
v.visitEnd();
} else {
av.visit(name, value);
}
}
}
}
@@ -0,0 +1,411 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
/**
* A node that represents a class.
*
* @author Eric Bruneton
*/
public class ClassNode extends ClassVisitor {
/**
* The class version.
*/
public int version;
/**
* The class's access flags (see {@link Opcodes}). This
* field also indicates if the class is deprecated.
*/
public int access;
/**
* The internal name of the class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
public String name;
/**
* The signature of the class. May be <tt>null</tt>.
*/
public String signature;
/**
* The internal of name of the super class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}). For
* interfaces, the super class is {@link Object}. May be <tt>null</tt>, but
* only for the {@link Object} class.
*/
public String superName;
/**
* The internal names of the class's interfaces (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}). This
* list is a list of {@link String} objects.
*/
public List<String> interfaces;
/**
* The name of the source file from which this class was compiled. May be
* <tt>null</tt>.
*/
public String sourceFile;
/**
* Debug information to compute the correspondence between source and
* compiled elements of the class. May be <tt>null</tt>.
*/
public String sourceDebug;
/**
* The internal name of the enclosing class of the class. May be
* <tt>null</tt>.
*/
public String outerClass;
/**
* The name of the method that contains the class, or <tt>null</tt> if the
* class is not enclosed in a method.
*/
public String outerMethod;
/**
* The descriptor of the method that contains the class, or <tt>null</tt> if
* the class is not enclosed in a method.
*/
public String outerMethodDesc;
/**
* The runtime visible annotations of this class. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label visible
*/
public List<AnnotationNode> visibleAnnotations;
/**
* The runtime invisible annotations of this class. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label invisible
*/
public List<AnnotationNode> invisibleAnnotations;
/**
* The runtime visible type annotations of this class. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations of this class. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* The non standard attributes of this class. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.Attribute
*/
public List<Attribute> attrs;
/**
* Informations about the inner classes of this class. This list is a list
* of {@link InnerClassNode} objects.
*
* @associates org.objectweb.asm.tree.InnerClassNode
*/
public List<InnerClassNode> innerClasses;
/**
* The fields of this class. This list is a list of {@link FieldNode}
* objects.
*
* @associates org.objectweb.asm.tree.FieldNode
*/
public List<FieldNode> fields;
/**
* The methods of this class. This list is a list of {@link MethodNode}
* objects.
*
* @associates org.objectweb.asm.tree.MethodNode
*/
public List<MethodNode> methods;
/**
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #ClassNode(int)}
* version.
*/
public ClassNode() {
this(Opcodes.ASM5);
}
/**
* Constructs a new {@link ClassNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public ClassNode(final int api) {
super(api);
this.interfaces = new ArrayList<String>();
this.innerClasses = new ArrayList<InnerClassNode>();
this.fields = new ArrayList<FieldNode>();
this.methods = new ArrayList<MethodNode>();
}
// ------------------------------------------------------------------------
// Implementation of the ClassVisitor abstract class
// ------------------------------------------------------------------------
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
this.version = version;
this.access = access;
this.name = name;
this.signature = signature;
this.superName = superName;
if (interfaces != null) {
this.interfaces.addAll(Arrays.asList(interfaces));
}
}
@Override
public void visitSource(final String file, final String debug) {
sourceFile = file;
sourceDebug = debug;
}
@Override
public void visitOuterClass(final String owner, final String name,
final String desc) {
outerClass = owner;
outerMethod = name;
outerMethodDesc = desc;
}
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(an);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
}
return an;
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
if (visible) {
if (visibleTypeAnnotations == null) {
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
visibleTypeAnnotations.add(an);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(an);
}
return an;
}
@Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attr);
}
@Override
public void visitInnerClass(final String name, final String outerName,
final String innerName, final int access) {
InnerClassNode icn = new InnerClassNode(name, outerName, innerName,
access);
innerClasses.add(icn);
}
@Override
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
FieldNode fn = new FieldNode(access, name, desc, signature, value);
fields.add(fn);
return fn;
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodNode mn = new MethodNode(access, name, desc, signature,
exceptions);
methods.add(mn);
return mn;
}
@Override
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Accept method
// ------------------------------------------------------------------------
/**
* Checks that this class node is compatible with the given ASM API version.
* This methods checks that this node, and all its nodes recursively, do not
* contain elements that were introduced in more recent versions of the ASM
* API than the given version.
*
* @param api
* an ASM API version. Must be one of {@link Opcodes#ASM4} or
* {@link Opcodes#ASM5}.
*/
public void check(final int api) {
if (api == Opcodes.ASM4) {
if (visibleTypeAnnotations != null
&& visibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
if (invisibleTypeAnnotations != null
&& invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
for (FieldNode f : fields) {
f.check(api);
}
for (MethodNode m : methods) {
m.check(api);
}
}
}
/**
* Makes the given class visitor visit this class.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
// visits header
String[] interfaces = new String[this.interfaces.size()];
this.interfaces.toArray(interfaces);
cv.visit(version, access, name, signature, superName, interfaces);
// visits source
if (sourceFile != null || sourceDebug != null) {
cv.visitSource(sourceFile, sourceDebug);
}
// visits outer class
if (outerClass != null) {
cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
}
// visits attributes
int i, n;
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = visibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, true));
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, false));
}
n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
true));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
false));
}
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
cv.visitAttribute(attrs.get(i));
}
// visits inner classes
for (i = 0; i < innerClasses.size(); ++i) {
innerClasses.get(i).accept(cv);
}
// visits fields
for (i = 0; i < fields.size(); ++i) {
fields.get(i).accept(cv);
}
// visits methods
for (i = 0; i < methods.size(); ++i) {
methods.get(i).accept(cv);
}
// visits end
cv.visitEnd();
}
}
@@ -0,0 +1,110 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a field instruction. A field instruction is an
* instruction that loads or stores the value of a field of an object.
*
* @author Eric Bruneton
*/
public class FieldInsnNode extends AbstractInsnNode {
/**
* The internal name of the field's owner class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
public String owner;
/**
* The field's name.
*/
public String name;
/**
* The field's descriptor (see {@link org.objectweb.asm.Type}).
*/
public String desc;
/**
* Constructs a new {@link FieldInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner
* the internal name of the field's owner class (see
* {@link org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link org.objectweb.asm.Type}).
*/
public FieldInsnNode(final int opcode, final String owner,
final String name, final String desc) {
super(opcode);
this.owner = owner;
this.name = name;
this.desc = desc;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be GETSTATIC,
* PUTSTATIC, GETFIELD or PUTFIELD.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return FIELD_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitFieldInsn(opcode, owner, name, desc);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new FieldInsnNode(opcode, owner, name, desc)
.cloneAnnotations(this);
}
}
@@ -0,0 +1,303 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
/**
* A node that represents a field.
*
* @author Eric Bruneton
*/
public class FieldNode extends FieldVisitor {
/**
* The field's access flags (see {@link Opcodes}). This
* field also indicates if the field is synthetic and/or deprecated.
*/
public int access;
/**
* The field's name.
*/
public String name;
/**
* The field's descriptor (see {@link org.objectweb.asm.Type}).
*/
public String desc;
/**
* The field's signature. May be <tt>null</tt>.
*/
public String signature;
/**
* The field's initial value. This field, which may be <tt>null</tt> if the
* field does not have an initial value, must be an {@link Integer}, a
* {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
*/
public Object value;
/**
* The runtime visible annotations of this field. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label visible
*/
public List<AnnotationNode> visibleAnnotations;
/**
* The runtime invisible annotations of this field. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label invisible
*/
public List<AnnotationNode> invisibleAnnotations;
/**
* The runtime visible type annotations of this field. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations of this field. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* The non standard attributes of this field. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.Attribute
*/
public List<Attribute> attrs;
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #FieldNode(int, int, String, String, String, Object)} version.
*
* @param access
* the field's access flags (see
* {@link Opcodes}). This parameter also
* indicates if the field is synthetic and/or deprecated.
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link org.objectweb.asm.Type
* Type}).
* @param signature
* the field's signature.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
*/
public FieldNode(final int access, final String name, final String desc,
final String signature, final Object value) {
this(Opcodes.ASM5, access, name, desc, signature, value);
}
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #FieldNode(int, int, String, String, String, Object)} version.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param access
* the field's access flags (see
* {@link Opcodes}). This parameter also
* indicates if the field is synthetic and/or deprecated.
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link org.objectweb.asm.Type
* Type}).
* @param signature
* the field's signature.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
*/
public FieldNode(final int api, final int access, final String name,
final String desc, final String signature, final Object value) {
super(api);
this.access = access;
this.name = name;
this.desc = desc;
this.signature = signature;
this.value = value;
}
// ------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(an);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
}
return an;
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
if (visible) {
if (visibleTypeAnnotations == null) {
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
visibleTypeAnnotations.add(an);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(an);
}
return an;
}
@Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attr);
}
@Override
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Accept methods
// ------------------------------------------------------------------------
/**
* Checks that this field node is compatible with the given ASM API version.
* This methods checks that this node, and all its nodes recursively, do not
* contain elements that were introduced in more recent versions of the ASM
* API than the given version.
*
* @param api
* an ASM API version. Must be one of {@link Opcodes#ASM4} or
* {@link Opcodes#ASM5}.
*/
public void check(final int api) {
if (api == Opcodes.ASM4) {
if (visibleTypeAnnotations != null
&& visibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
if (invisibleTypeAnnotations != null
&& invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
}
}
/**
* Makes the given class visitor visit this field.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
FieldVisitor fv = cv.visitField(access, name, desc, signature, value);
if (fv == null) {
return;
}
int i, n;
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = visibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, true));
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, false));
}
n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
true));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
false));
}
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
fv.visitAttribute(attrs.get(i));
}
fv.visitEnd();
}
}
@@ -0,0 +1,210 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents a stack map frame. These nodes are pseudo instruction
* nodes in order to be inserted in an instruction list. In fact these nodes
* must(*) be inserted <i>just before</i> any instruction node <b>i</b> that
* follows an unconditionnal branch instruction such as GOTO or THROW, that is
* the target of a jump instruction, or that starts an exception handler block.
* The stack map frame types must describe the values of the local variables and
* of the operand stack elements <i>just before</i> <b>i</b> is executed. <br>
* <br>
* (*) this is mandatory only for classes whose version is greater than or equal
* to {@link Opcodes#V1_6 V1_6}.
*
* @author Eric Bruneton
*/
public class FrameNode extends AbstractInsnNode {
/**
* The type of this frame. Must be {@link Opcodes#F_NEW} for expanded
* frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
* {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
*/
public int type;
/**
* The types of the local variables of this stack map frame. Elements of
* this list can be Integer, String or LabelNode objects (for primitive,
* reference and uninitialized types respectively - see
* {@link MethodVisitor}).
*/
public List<Object> local;
/**
* The types of the operand stack elements of this stack map frame. Elements
* of this list can be Integer, String or LabelNode objects (for primitive,
* reference and uninitialized types respectively - see
* {@link MethodVisitor}).
*/
public List<Object> stack;
private FrameNode() {
super(-1);
}
/**
* Constructs a new {@link FrameNode}.
*
* @param type
* the type of this frame. Must be {@link Opcodes#F_NEW} for
* expanded frames, or {@link Opcodes#F_FULL},
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP},
* {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND},
* {@link Opcodes#F_SAME1} for compressed frames.
* @param nLocal
* number of local variables of this stack map frame.
* @param local
* the types of the local variables of this stack map frame.
* Elements of this list can be Integer, String or LabelNode
* objects (for primitive, reference and uninitialized types
* respectively - see {@link MethodVisitor}).
* @param nStack
* number of operand stack elements of this stack map frame.
* @param stack
* the types of the operand stack elements of this stack map
* frame. Elements of this list can be Integer, String or
* LabelNode objects (for primitive, reference and uninitialized
* types respectively - see {@link MethodVisitor}).
*/
public FrameNode(final int type, final int nLocal, final Object[] local,
final int nStack, final Object[] stack) {
super(-1);
this.type = type;
switch (type) {
case Opcodes.F_NEW:
case Opcodes.F_FULL:
this.local = asList(nLocal, local);
this.stack = asList(nStack, stack);
break;
case Opcodes.F_APPEND:
this.local = asList(nLocal, local);
break;
case Opcodes.F_CHOP:
this.local = Arrays.asList(new Object[nLocal]);
break;
case Opcodes.F_SAME:
break;
case Opcodes.F_SAME1:
this.stack = asList(1, stack);
break;
}
}
@Override
public int getType() {
return FRAME;
}
/**
* Makes the given visitor visit this stack map frame.
*
* @param mv
* a method visitor.
*/
@Override
public void accept(final MethodVisitor mv) {
switch (type) {
case Opcodes.F_NEW:
case Opcodes.F_FULL:
mv.visitFrame(type, local.size(), asArray(local), stack.size(),
asArray(stack));
break;
case Opcodes.F_APPEND:
mv.visitFrame(type, local.size(), asArray(local), 0, null);
break;
case Opcodes.F_CHOP:
mv.visitFrame(type, local.size(), null, 0, null);
break;
case Opcodes.F_SAME:
mv.visitFrame(type, 0, null, 0, null);
break;
case Opcodes.F_SAME1:
mv.visitFrame(type, 0, null, 1, asArray(stack));
break;
}
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
FrameNode clone = new FrameNode();
clone.type = type;
if (local != null) {
clone.local = new ArrayList<Object>();
for (int i = 0; i < local.size(); ++i) {
Object l = local.get(i);
if (l instanceof LabelNode) {
l = labels.get(l);
}
clone.local.add(l);
}
}
if (stack != null) {
clone.stack = new ArrayList<Object>();
for (int i = 0; i < stack.size(); ++i) {
Object s = stack.get(i);
if (s instanceof LabelNode) {
s = labels.get(s);
}
clone.stack.add(s);
}
}
return clone;
}
// ------------------------------------------------------------------------
private static List<Object> asList(final int n, final Object[] o) {
return Arrays.asList(o).subList(0, n);
}
private static Object[] asArray(final List<Object> l) {
Object[] objs = new Object[l.size()];
for (int i = 0; i < objs.length; ++i) {
Object o = l.get(i);
if (o instanceof LabelNode) {
o = ((LabelNode) o).getLabel();
}
objs[i] = o;
}
return objs;
}
}
@@ -0,0 +1,83 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents an IINC instruction.
*
* @author Eric Bruneton
*/
public class IincInsnNode extends AbstractInsnNode {
/**
* Index of the local variable to be incremented.
*/
public int var;
/**
* Amount to increment the local variable by.
*/
public int incr;
/**
* Constructs a new {@link IincInsnNode}.
*
* @param var
* index of the local variable to be incremented.
* @param incr
* increment amount to increment the local variable by.
*/
public IincInsnNode(final int var, final int incr) {
super(Opcodes.IINC);
this.var = var;
this.incr = incr;
}
@Override
public int getType() {
return IINC_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitIincInsn(var, incr);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new IincInsnNode(var, incr).cloneAnnotations(this);
}
}
@@ -0,0 +1,101 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import org.objectweb.asm.ClassVisitor;
/**
* A node that represents an inner class.
*
* @author Eric Bruneton
*/
public class InnerClassNode {
/**
* The internal name of an inner class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
public String name;
/**
* The internal name of the class to which the inner class belongs (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public String outerName;
/**
* The (simple) name of the inner class inside its enclosing class. May be
* <tt>null</tt> for anonymous inner classes.
*/
public String innerName;
/**
* The access flags of the inner class as originally declared in the
* enclosing class.
*/
public int access;
/**
* Constructs a new {@link InnerClassNode}.
*
* @param name
* the internal name of an inner class (see
* {@link org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param outerName
* the internal name of the class to which the inner class
* belongs (see {@link org.objectweb.asm.Type#getInternalName()
* getInternalName}). May be <tt>null</tt>.
* @param innerName
* the (simple) name of the inner class inside its enclosing
* class. May be <tt>null</tt> for anonymous inner classes.
* @param access
* the access flags of the inner class as originally declared in
* the enclosing class.
*/
public InnerClassNode(final String name, final String outerName,
final String innerName, final int access) {
this.name = name;
this.outerName = outerName;
this.innerName = innerName;
this.access = access;
}
/**
* Makes the given class visitor visit this inner class.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
cv.visitInnerClass(name, outerName, innerName, access);
}
}
@@ -0,0 +1,601 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.objectweb.asm.MethodVisitor;
/**
* A doubly linked list of {@link AbstractInsnNode} objects. <i>This
* implementation is not thread safe</i>.
*/
public class InsnList {
/**
* The number of instructions in this list.
*/
private int size;
/**
* The first instruction in this list. May be <tt>null</tt>.
*/
private AbstractInsnNode first;
/**
* The last instruction in this list. May be <tt>null</tt>.
*/
private AbstractInsnNode last;
/**
* A cache of the instructions of this list. This cache is used to improve
* the performance of the {@link #get} method.
*/
AbstractInsnNode[] cache;
/**
* Returns the number of instructions in this list.
*
* @return the number of instructions in this list.
*/
public int size() {
return size;
}
/**
* Returns the first instruction in this list.
*
* @return the first instruction in this list, or <tt>null</tt> if the list
* is empty.
*/
public AbstractInsnNode getFirst() {
return first;
}
/**
* Returns the last instruction in this list.
*
* @return the last instruction in this list, or <tt>null</tt> if the list
* is empty.
*/
public AbstractInsnNode getLast() {
return last;
}
/**
* Returns the instruction whose index is given. This method builds a cache
* of the instructions in this list to avoid scanning the whole list each
* time it is called. Once the cache is built, this method run in constant
* time. This cache is invalidated by all the methods that modify the list.
*
* @param index
* the index of the instruction that must be returned.
* @return the instruction whose index is given.
* @throws IndexOutOfBoundsException
* if (index &lt; 0 || index &gt;= size()).
*/
public AbstractInsnNode get(final int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
if (cache == null) {
cache = toArray();
}
return cache[index];
}
/**
* Returns <tt>true</tt> if the given instruction belongs to this list. This
* method always scans the instructions of this list until it finds the
* given instruction or reaches the end of the list.
*
* @param insn
* an instruction.
* @return <tt>true</tt> if the given instruction belongs to this list.
*/
public boolean contains(final AbstractInsnNode insn) {
AbstractInsnNode i = first;
while (i != null && i != insn) {
i = i.next;
}
return i != null;
}
/**
* Returns the index of the given instruction in this list. This method
* builds a cache of the instruction indexes to avoid scanning the whole
* list each time it is called. Once the cache is built, this method run in
* constant time. The cache is invalidated by all the methods that modify
* the list.
*
* @param insn
* an instruction <i>of this list</i>.
* @return the index of the given instruction in this list. <i>The result of
* this method is undefined if the given instruction does not belong
* to this list</i>. Use {@link #contains contains} to test if an
* instruction belongs to an instruction list or not.
*/
public int indexOf(final AbstractInsnNode insn) {
if (cache == null) {
cache = toArray();
}
return insn.index;
}
/**
* Makes the given visitor visit all of the instructions in this list.
*
* @param mv
* the method visitor that must visit the instructions.
*/
public void accept(final MethodVisitor mv) {
AbstractInsnNode insn = first;
while (insn != null) {
insn.accept(mv);
insn = insn.next;
}
}
/**
* Returns an iterator over the instructions in this list.
*
* @return an iterator over the instructions in this list.
*/
public ListIterator<AbstractInsnNode> iterator() {
return iterator(0);
}
/**
* Returns an iterator over the instructions in this list.
*
* @return an iterator over the instructions in this list.
*/
@SuppressWarnings("unchecked")
public ListIterator<AbstractInsnNode> iterator(int index) {
return new InsnListIterator(index);
}
/**
* Returns an array containing all of the instructions in this list.
*
* @return an array containing all of the instructions in this list.
*/
public AbstractInsnNode[] toArray() {
int i = 0;
AbstractInsnNode elem = first;
AbstractInsnNode[] insns = new AbstractInsnNode[size];
while (elem != null) {
insns[i] = elem;
elem.index = i++;
elem = elem.next;
}
return insns;
}
/**
* Replaces an instruction of this list with another instruction.
*
* @param location
* an instruction <i>of this list</i>.
* @param insn
* another instruction, <i>which must not belong to any
* {@link InsnList}</i>.
*/
public void set(final AbstractInsnNode location, final AbstractInsnNode insn) {
AbstractInsnNode next = location.next;
insn.next = next;
if (next != null) {
next.prev = insn;
} else {
last = insn;
}
AbstractInsnNode prev = location.prev;
insn.prev = prev;
if (prev != null) {
prev.next = insn;
} else {
first = insn;
}
if (cache != null) {
int index = location.index;
cache[index] = insn;
insn.index = index;
} else {
insn.index = 0; // insn now belongs to an InsnList
}
location.index = -1; // i no longer belongs to an InsnList
location.prev = null;
location.next = null;
}
/**
* Adds the given instruction to the end of this list.
*
* @param insn
* an instruction, <i>which must not belong to any
* {@link InsnList}</i>.
*/
public void add(final AbstractInsnNode insn) {
++size;
if (last == null) {
first = insn;
last = insn;
} else {
last.next = insn;
insn.prev = last;
}
last = insn;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Adds the given instructions to the end of this list.
*
* @param insns
* an instruction list, which is cleared during the process. This
* list must be different from 'this'.
*/
public void add(final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
if (last == null) {
first = insns.first;
last = insns.last;
} else {
AbstractInsnNode elem = insns.first;
last.next = elem;
elem.prev = last;
last = insns.last;
}
cache = null;
insns.removeAll(false);
}
/**
* Inserts the given instruction at the begining of this list.
*
* @param insn
* an instruction, <i>which must not belong to any
* {@link InsnList}</i>.
*/
public void insert(final AbstractInsnNode insn) {
++size;
if (first == null) {
first = insn;
last = insn;
} else {
first.prev = insn;
insn.next = first;
}
first = insn;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Inserts the given instructions at the begining of this list.
*
* @param insns
* an instruction list, which is cleared during the process. This
* list must be different from 'this'.
*/
public void insert(final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
if (first == null) {
first = insns.first;
last = insns.last;
} else {
AbstractInsnNode elem = insns.last;
first.prev = elem;
elem.next = first;
first = insns.first;
}
cache = null;
insns.removeAll(false);
}
/**
* Inserts the given instruction after the specified instruction.
*
* @param location
* an instruction <i>of this list</i> after which insn must be
* inserted.
* @param insn
* the instruction to be inserted, <i>which must not belong to
* any {@link InsnList}</i>.
*/
public void insert(final AbstractInsnNode location,
final AbstractInsnNode insn) {
++size;
AbstractInsnNode next = location.next;
if (next == null) {
last = insn;
} else {
next.prev = insn;
}
location.next = insn;
insn.next = next;
insn.prev = location;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Inserts the given instructions after the specified instruction.
*
* @param location
* an instruction <i>of this list</i> after which the
* instructions must be inserted.
* @param insns
* the instruction list to be inserted, which is cleared during
* the process. This list must be different from 'this'.
*/
public void insert(final AbstractInsnNode location, final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
AbstractInsnNode ifirst = insns.first;
AbstractInsnNode ilast = insns.last;
AbstractInsnNode next = location.next;
if (next == null) {
last = ilast;
} else {
next.prev = ilast;
}
location.next = ifirst;
ilast.next = next;
ifirst.prev = location;
cache = null;
insns.removeAll(false);
}
/**
* Inserts the given instruction before the specified instruction.
*
* @param location
* an instruction <i>of this list</i> before which insn must be
* inserted.
* @param insn
* the instruction to be inserted, <i>which must not belong to
* any {@link InsnList}</i>.
*/
public void insertBefore(final AbstractInsnNode location,
final AbstractInsnNode insn) {
++size;
AbstractInsnNode prev = location.prev;
if (prev == null) {
first = insn;
} else {
prev.next = insn;
}
location.prev = insn;
insn.next = location;
insn.prev = prev;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Inserts the given instructions before the specified instruction.
*
* @param location
* an instruction <i>of this list</i> before which the
* instructions must be inserted.
* @param insns
* the instruction list to be inserted, which is cleared during
* the process. This list must be different from 'this'.
*/
public void insertBefore(final AbstractInsnNode location,
final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
AbstractInsnNode ifirst = insns.first;
AbstractInsnNode ilast = insns.last;
AbstractInsnNode prev = location.prev;
if (prev == null) {
first = ifirst;
} else {
prev.next = ifirst;
}
location.prev = ilast;
ilast.next = location;
ifirst.prev = prev;
cache = null;
insns.removeAll(false);
}
/**
* Removes the given instruction from this list.
*
* @param insn
* the instruction <i>of this list</i> that must be removed.
*/
public void remove(final AbstractInsnNode insn) {
--size;
AbstractInsnNode next = insn.next;
AbstractInsnNode prev = insn.prev;
if (next == null) {
if (prev == null) {
first = null;
last = null;
} else {
prev.next = null;
last = prev;
}
} else {
if (prev == null) {
first = next;
next.prev = null;
} else {
prev.next = next;
next.prev = prev;
}
}
cache = null;
insn.index = -1; // insn no longer belongs to an InsnList
insn.prev = null;
insn.next = null;
}
/**
* Removes all of the instructions of this list.
*
* @param mark
* if the instructions must be marked as no longer belonging to
* any {@link InsnList}.
*/
void removeAll(final boolean mark) {
if (mark) {
AbstractInsnNode insn = first;
while (insn != null) {
AbstractInsnNode next = insn.next;
insn.index = -1; // insn no longer belongs to an InsnList
insn.prev = null;
insn.next = null;
insn = next;
}
}
size = 0;
first = null;
last = null;
cache = null;
}
/**
* Removes all of the instructions of this list.
*/
public void clear() {
removeAll(false);
}
/**
* Reset all labels in the instruction list. This method should be called
* before reusing same instructions list between several
* <code>ClassWriter</code>s.
*/
public void resetLabels() {
AbstractInsnNode insn = first;
while (insn != null) {
if (insn instanceof LabelNode) {
((LabelNode) insn).resetLabel();
}
insn = insn.next;
}
}
// this class is not generified because it will create bridges
@SuppressWarnings("rawtypes")
private final class InsnListIterator implements ListIterator {
AbstractInsnNode next;
AbstractInsnNode prev;
InsnListIterator(int index) {
if (index == size()) {
next = null;
prev = getLast();
} else {
next = get(index);
prev = next.prev;
}
}
public boolean hasNext() {
return next != null;
}
public Object next() {
if (next == null) {
throw new NoSuchElementException();
}
AbstractInsnNode result = next;
prev = result;
next = result.next;
return result;
}
public void remove() {
InsnList.this.remove(prev);
prev = prev.prev;
}
public boolean hasPrevious() {
return prev != null;
}
public Object previous() {
AbstractInsnNode result = prev;
next = result;
prev = result.prev;
return result;
}
public int nextIndex() {
if (next == null) {
return size();
}
if (cache == null) {
cache = toArray();
}
return next.index;
}
public int previousIndex() {
if (prev == null) {
return -1;
}
if (cache == null) {
cache = toArray();
}
return prev.index;
}
public void add(Object o) {
InsnList.this.insertBefore(next, (AbstractInsnNode) o);
prev = (AbstractInsnNode) o;
}
public void set(Object o) {
InsnList.this.set(next.prev, (AbstractInsnNode) o);
prev = (AbstractInsnNode) o;
}
}
}
@@ -0,0 +1,88 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a zero operand instruction.
*
* @author Eric Bruneton
*/
public class InsnNode extends AbstractInsnNode {
/**
* Constructs a new {@link InsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed. This opcode
* must be 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, IALOAD,
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
* 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, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
* or MONITOREXIT.
*/
public InsnNode(final int opcode) {
super(opcode);
}
@Override
public int getType() {
return INSN;
}
/**
* Makes the given visitor visit this instruction.
*
* @param mv
* a method visitor.
*/
@Override
public void accept(final MethodVisitor mv) {
mv.visitInsn(opcode);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new InsnNode(opcode).cloneAnnotations(this);
}
}
@@ -0,0 +1,88 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents an instruction with a single int operand.
*
* @author Eric Bruneton
*/
public class IntInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction.
*/
public int operand;
/**
* Constructs a new {@link IntInsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed. This opcode
* must be BIPUSH, SIPUSH or NEWARRAY.
* @param operand
* the operand of the instruction to be constructed.
*/
public IntInsnNode(final int opcode, final int operand) {
super(opcode);
this.operand = operand;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be BIPUSH, SIPUSH
* or NEWARRAY.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return INT_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitIntInsn(opcode, operand);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new IntInsnNode(opcode, operand).cloneAnnotations(this);
}
}
@@ -0,0 +1,102 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents an invokedynamic instruction.
*
* @author Remi Forax
*/
public class InvokeDynamicInsnNode extends AbstractInsnNode {
/**
* Invokedynamic name.
*/
public String name;
/**
* Invokedynamic descriptor.
*/
public String desc;
/**
* Bootstrap method
*/
public Handle bsm;
/**
* Bootstrap constant arguments
*/
public Object[] bsmArgs;
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name
* invokedynamic name.
* @param desc
* invokedynamic descriptor (see {@link org.objectweb.asm.Type}).
* @param bsm
* the bootstrap method.
* @param bsmArgs
* the boostrap constant arguments.
*/
public InvokeDynamicInsnNode(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = desc;
this.bsm = bsm;
this.bsmArgs = bsmArgs;
}
@Override
public int getType() {
return INVOKE_DYNAMIC_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)
.cloneAnnotations(this);
}
}
@@ -0,0 +1,97 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a jump instruction. A jump instruction is an
* instruction that may jump to another instruction.
*
* @author Eric Bruneton
*/
public class JumpInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction. This operand is a label that designates
* the instruction to which this instruction may jump.
*/
public LabelNode label;
/**
* Constructs a new {@link JumpInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label
* the operand of the instruction to be constructed. This operand
* is a label that designates the instruction to which the jump
* instruction may jump.
*/
public JumpInsnNode(final int opcode, final LabelNode label) {
super(opcode);
this.label = label;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be IFEQ, IFNE,
* IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT,
* IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO,
* JSR, IFNULL or IFNONNULL.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return JUMP_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitJumpInsn(opcode, label.getLabel());
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new JumpInsnNode(opcode, clone(label, labels))
.cloneAnnotations(this);
}
}
@@ -0,0 +1,78 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
/**
* An {@link AbstractInsnNode} that encapsulates a {@link Label}.
*/
public class LabelNode extends AbstractInsnNode {
private Label label;
public LabelNode() {
super(-1);
}
public LabelNode(final Label label) {
super(-1);
this.label = label;
}
@Override
public int getType() {
return LABEL;
}
public Label getLabel() {
if (label == null) {
label = new Label();
}
return label;
}
@Override
public void accept(final MethodVisitor cv) {
cv.visitLabel(getLabel());
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return labels.get(this);
}
public void resetLabel() {
label = null;
}
}
@@ -0,0 +1,79 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents an LDC instruction.
*
* @author Eric Bruneton
*/
public class LdcInsnNode extends AbstractInsnNode {
/**
* The constant to be loaded on the stack. This parameter must be a non null
* {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a
* {@link String} or a {@link org.objectweb.asm.Type}.
*/
public Object cst;
/**
* Constructs a new {@link LdcInsnNode}.
*
* @param cst
* the constant to be loaded on the stack. This parameter must be
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
*/
public LdcInsnNode(final Object cst) {
super(Opcodes.LDC);
this.cst = cst;
}
@Override
public int getType() {
return LDC_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitLdcInsn(cst);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new LdcInsnNode(cst).cloneAnnotations(this);
}
}
@@ -0,0 +1,84 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a line number declaration. These nodes are pseudo
* instruction nodes in order to be inserted in an instruction list.
*
* @author Eric Bruneton
*/
public class LineNumberNode extends AbstractInsnNode {
/**
* A line number. This number refers to the source file from which the class
* was compiled.
*/
public int line;
/**
* The first instruction corresponding to this line number.
*/
public LabelNode start;
/**
* Constructs a new {@link LineNumberNode}.
*
* @param line
* a line number. This number refers to the source file from
* which the class was compiled.
* @param start
* the first instruction corresponding to this line number.
*/
public LineNumberNode(final int line, final LabelNode start) {
super(-1);
this.line = line;
this.start = start;
}
@Override
public int getType() {
return LINE;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitLineNumber(line, start.getLabel());
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new LineNumberNode(line, clone(start, labels));
}
}
@@ -0,0 +1,157 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
import org.objectweb.asm.TypeReference;
/**
* A node that represents a type annotation on a local or resource variable.
*
* @author Eric Bruneton
*/
public class LocalVariableAnnotationNode extends TypeAnnotationNode {
/**
* The fist instructions corresponding to the continuous ranges that make
* the scope of this local variable (inclusive). Must not be <tt>null</tt>.
*/
public List<LabelNode> start;
/**
* The last instructions corresponding to the continuous ranges that make
* the scope of this local variable (exclusive). This list must have the
* same size as the 'start' list. Must not be <tt>null</tt>.
*/
public List<LabelNode> end;
/**
* The local variable's index in each range. This list must have the same
* size as the 'start' list. Must not be <tt>null</tt>.
*/
public List<Integer> index;
/**
* Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must
* not use this constructor</i>. Instead, they must use the
* {@link #LocalVariableAnnotationNode(int, TypePath, LabelNode[], LabelNode[], int[], String)}
* version.
*
* @param typeRef
* a reference to the annotated type. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param start
* the fist instructions corresponding to the continuous ranges
* that make the scope of this local variable (inclusive).
* @param end
* the last instructions corresponding to the continuous ranges
* that make the scope of this local variable (exclusive). This
* array must have the same size as the 'start' array.
* @param index
* the local variable's index in each range. This array must have
* the same size as the 'start' array.
* @param desc
* the class descriptor of the annotation class.
*/
public LocalVariableAnnotationNode(int typeRef, TypePath typePath,
LabelNode[] start, LabelNode[] end, int[] index, String desc) {
this(Opcodes.ASM5, typeRef, typePath, start, end, index, desc);
}
/**
* Constructs a new {@link LocalVariableAnnotationNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param typeRef
* a reference to the annotated type. See {@link TypeReference}.
* @param start
* the fist instructions corresponding to the continuous ranges
* that make the scope of this local variable (inclusive).
* @param end
* the last instructions corresponding to the continuous ranges
* that make the scope of this local variable (exclusive). This
* array must have the same size as the 'start' array.
* @param index
* the local variable's index in each range. This array must have
* the same size as the 'start' array.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
*/
public LocalVariableAnnotationNode(int api, int typeRef, TypePath typePath,
LabelNode[] start, LabelNode[] end, int[] index, String desc) {
super(api, typeRef, typePath, desc);
this.start = new ArrayList<LabelNode>(start.length);
this.start.addAll(Arrays.asList(start));
this.end = new ArrayList<LabelNode>(end.length);
this.end.addAll(Arrays.asList(end));
this.index = new ArrayList<Integer>(index.length);
for (int i : index) {
this.index.add(i);
}
}
/**
* Makes the given visitor visit this type annotation.
*
* @param mv
* the visitor that must visit this annotation.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
*/
public void accept(final MethodVisitor mv, boolean visible) {
Label[] start = new Label[this.start.size()];
Label[] end = new Label[this.end.size()];
int[] index = new int[this.index.size()];
for (int i = 0; i < start.length; ++i) {
start[i] = this.start.get(i).getLabel();
end[i] = this.end.get(i).getLabel();
index[i] = this.index.get(i);
}
accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
index, desc, true));
}
}
@@ -0,0 +1,112 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a local variable declaration.
*
* @author Eric Bruneton
*/
public class LocalVariableNode {
/**
* The name of a local variable.
*/
public String name;
/**
* The type descriptor of this local variable.
*/
public String desc;
/**
* The signature of this local variable. May be <tt>null</tt>.
*/
public String signature;
/**
* The first instruction corresponding to the scope of this local variable
* (inclusive).
*/
public LabelNode start;
/**
* The last instruction corresponding to the scope of this local variable
* (exclusive).
*/
public LabelNode end;
/**
* The local variable's index.
*/
public int index;
/**
* Constructs a new {@link LocalVariableNode}.
*
* @param name
* the name of a local variable.
* @param desc
* the type descriptor of this local variable.
* @param signature
* the signature of this local variable. May be <tt>null</tt>.
* @param start
* the first instruction corresponding to the scope of this local
* variable (inclusive).
* @param end
* the last instruction corresponding to the scope of this local
* variable (exclusive).
* @param index
* the local variable's index.
*/
public LocalVariableNode(final String name, final String desc,
final String signature, final LabelNode start, final LabelNode end,
final int index) {
this.name = name;
this.desc = desc;
this.signature = signature;
this.start = start;
this.end = end;
this.index = index;
}
/**
* Makes the given visitor visit this local variable declaration.
*
* @param mv
* a method visitor.
*/
public void accept(final MethodVisitor mv) {
mv.visitLocalVariable(name, desc, signature, start.getLabel(),
end.getLabel(), index);
}
}
@@ -0,0 +1,118 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents a LOOKUPSWITCH instruction.
*
* @author Eric Bruneton
*/
public class LookupSwitchInsnNode extends AbstractInsnNode {
/**
* Beginning of the default handler block.
*/
public LabelNode dflt;
/**
* The values of the keys. This list is a list of {@link Integer} objects.
*/
public List<Integer> keys;
/**
* Beginnings of the handler blocks. This list is a list of
* {@link LabelNode} objects.
*/
public List<LabelNode> labels;
/**
* Constructs a new {@link LookupSwitchInsnNode}.
*
* @param dflt
* beginning of the default handler block.
* @param keys
* the values of the keys.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>keys[i]</tt> key.
*/
public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys,
final LabelNode[] labels) {
super(Opcodes.LOOKUPSWITCH);
this.dflt = dflt;
this.keys = new ArrayList<Integer>(keys == null ? 0 : keys.length);
this.labels = new ArrayList<LabelNode>(labels == null ? 0
: labels.length);
if (keys != null) {
for (int i = 0; i < keys.length; ++i) {
this.keys.add(new Integer(keys[i]));
}
}
if (labels != null) {
this.labels.addAll(Arrays.asList(labels));
}
}
@Override
public int getType() {
return LOOKUPSWITCH_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
int[] keys = new int[this.keys.size()];
for (int i = 0; i < keys.length; ++i) {
keys[i] = this.keys.get(i).intValue();
}
Label[] labels = new Label[this.labels.size()];
for (int i = 0; i < labels.length; ++i) {
labels[i] = this.labels.get(i).getLabel();
}
mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
LookupSwitchInsnNode clone = new LookupSwitchInsnNode(clone(dflt,
labels), null, clone(this.labels, labels));
clone.keys.addAll(keys);
return clone.cloneAnnotations(this);
}
}
@@ -0,0 +1,109 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a method instruction. A method instruction is an
* instruction that invokes a method.
*
* @author Eric Bruneton
*/
public class MethodInsnNode extends AbstractInsnNode {
/**
* The internal name of the method's owner class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
public String owner;
/**
* The method's name.
*/
public String name;
/**
* The method's descriptor (see {@link org.objectweb.asm.Type}).
*/
public String desc;
/**
* Constructs a new {@link MethodInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link org.objectweb.asm.Type}).
*/
public MethodInsnNode(final int opcode, final String owner,
final String name, final String desc) {
super(opcode);
this.owner = owner;
this.name = name;
this.desc = desc;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be INVOKEVIRTUAL,
* INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return METHOD_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new MethodInsnNode(opcode, owner, name, desc);
}
}
@@ -0,0 +1,809 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.TypePath;
/**
* A node that represents a method.
*
* @author Eric Bruneton
*/
public class MethodNode extends MethodVisitor {
/**
* The method's access flags (see {@link Opcodes}). This field also
* indicates if the method is synthetic and/or deprecated.
*/
public int access;
/**
* The method's name.
*/
public String name;
/**
* The method's descriptor (see {@link Type}).
*/
public String desc;
/**
* The method's signature. May be <tt>null</tt>.
*/
public String signature;
/**
* The internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). This list is a list of
* {@link String} objects.
*/
public List<String> exceptions;
/**
* The method parameter info (access flags and name)
*/
public List<ParameterNode> parameters;
/**
* The runtime visible annotations of this method. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label visible
*/
public List<AnnotationNode> visibleAnnotations;
/**
* The runtime invisible annotations of this method. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label invisible
*/
public List<AnnotationNode> invisibleAnnotations;
/**
* The runtime visible type annotations of this method. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations of this method. This list is a
* list of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* The non standard attributes of this method. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.Attribute
*/
public List<Attribute> attrs;
/**
* The default value of this annotation interface method. This field must be
* a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short},
* {@link Integer}, {@link Long}, {@link Float}, {@link Double},
* {@link String} or {@link Type}, or an two elements String array (for
* enumeration values), a {@link AnnotationNode}, or a {@link List} of
* values of one of the preceding types. May be <tt>null</tt>.
*/
public Object annotationDefault;
/**
* The runtime visible parameter annotations of this method. These lists are
* lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label invisible parameters
*/
public List<AnnotationNode>[] visibleParameterAnnotations;
/**
* The runtime invisible parameter annotations of this method. These lists
* are lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label visible parameters
*/
public List<AnnotationNode>[] invisibleParameterAnnotations;
/**
* The instructions of this method. This list is a list of
* {@link AbstractInsnNode} objects.
*
* @associates org.objectweb.asm.tree.AbstractInsnNode
* @label instructions
*/
public InsnList instructions;
/**
* The try catch blocks of this method. This list is a list of
* {@link TryCatchBlockNode} objects.
*
* @associates org.objectweb.asm.tree.TryCatchBlockNode
*/
public List<TryCatchBlockNode> tryCatchBlocks;
/**
* The maximum stack size of this method.
*/
public int maxStack;
/**
* The maximum number of local variables of this method.
*/
public int maxLocals;
/**
* The local variables of this method. This list is a list of
* {@link LocalVariableNode} objects. May be <tt>null</tt>
*
* @associates org.objectweb.asm.tree.LocalVariableNode
*/
public List<LocalVariableNode> localVariables;
/**
* The visible local variable annotations of this method. This list is a
* list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
*
* @associates org.objectweb.asm.tree.LocalVariableAnnotationNode
*/
public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
/**
* The invisible local variable annotations of this method. This list is a
* list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
*
* @associates org.objectweb.asm.tree.LocalVariableAnnotationNode
*/
public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
/**
* If the accept method has been called on this object.
*/
private boolean visited;
/**
* Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
* use this constructor</i>. Instead, they must use the
* {@link #MethodNode(int)} version.
*/
public MethodNode() {
this(Opcodes.ASM5);
}
/**
* Constructs an uninitialized {@link MethodNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public MethodNode(final int api) {
super(api);
this.instructions = new InsnList();
}
/**
* Constructs a new {@link MethodNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #MethodNode(int, int, String, String, String, String[])} version.
*
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type}).
* @param signature
* the method's signature. May be <tt>null</tt>.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public MethodNode(final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
this(Opcodes.ASM5, access, name, desc, signature, exceptions);
}
/**
* Constructs a new {@link MethodNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type}).
* @param signature
* the method's signature. May be <tt>null</tt>.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public MethodNode(final int api, final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
super(api);
this.access = access;
this.name = name;
this.desc = desc;
this.signature = signature;
this.exceptions = new ArrayList<String>(exceptions == null ? 0
: exceptions.length);
boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0;
if (!isAbstract) {
this.localVariables = new ArrayList<LocalVariableNode>(5);
}
this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
if (exceptions != null) {
this.exceptions.addAll(Arrays.asList(exceptions));
}
this.instructions = new InsnList();
}
// ------------------------------------------------------------------------
// Implementation of the MethodVisitor abstract class
// ------------------------------------------------------------------------
@Override
public void visitParameter(String name, int access) {
if (parameters == null) {
parameters = new ArrayList<ParameterNode>(5);
}
parameters.add(new ParameterNode(name, access));
}
@SuppressWarnings("serial")
@Override
public AnnotationVisitor visitAnnotationDefault() {
return new AnnotationNode(new ArrayList<Object>(0) {
@Override
public boolean add(final Object o) {
annotationDefault = o;
return super.add(o);
}
});
}
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(an);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
}
return an;
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
if (visible) {
if (visibleTypeAnnotations == null) {
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
visibleTypeAnnotations.add(an);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(an);
}
return an;
}
@SuppressWarnings("unchecked")
@Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleParameterAnnotations == null) {
int params = Type.getArgumentTypes(this.desc).length;
visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
}
if (visibleParameterAnnotations[parameter] == null) {
visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
1);
}
visibleParameterAnnotations[parameter].add(an);
} else {
if (invisibleParameterAnnotations == null) {
int params = Type.getArgumentTypes(this.desc).length;
invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
}
if (invisibleParameterAnnotations[parameter] == null) {
invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
1);
}
invisibleParameterAnnotations[parameter].add(an);
}
return an;
}
@Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attr);
}
@Override
public void visitCode() {
}
@Override
public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) {
instructions.add(new FrameNode(type, nLocal, local == null ? null
: getLabelNodes(local), nStack, stack == null ? null
: getLabelNodes(stack)));
}
@Override
public void visitInsn(final int opcode) {
instructions.add(new InsnNode(opcode));
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
instructions.add(new IntInsnNode(opcode, operand));
}
@Override
public void visitVarInsn(final int opcode, final int var) {
instructions.add(new VarInsnNode(opcode, var));
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
instructions.add(new TypeInsnNode(opcode, type));
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
instructions.add(new FieldInsnNode(opcode, owner, name, desc));
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
instructions.add(new MethodInsnNode(opcode, owner, name, desc));
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
}
@Override
public void visitLabel(final Label label) {
instructions.add(getLabelNode(label));
}
@Override
public void visitLdcInsn(final Object cst) {
instructions.add(new LdcInsnNode(cst));
}
@Override
public void visitIincInsn(final int var, final int increment) {
instructions.add(new IincInsnNode(var, increment));
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt),
getLabelNodes(labels)));
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys,
getLabelNodes(labels)));
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
instructions.add(new MultiANewArrayInsnNode(desc, dims));
}
@Override
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
// Finds the last real instruction, i.e. the instruction targeted by
// this annotation.
AbstractInsnNode insn = instructions.getLast();
while (insn.getOpcode() == -1) {
insn = insn.getPrevious();
}
// Adds the annotation to this instruction.
TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
if (visible) {
if (insn.visibleTypeAnnotations == null) {
insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
1);
}
insn.visibleTypeAnnotations.add(an);
} else {
if (insn.invisibleTypeAnnotations == null) {
insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
1);
}
insn.invisibleTypeAnnotations.add(an);
}
return an;
}
@Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
getLabelNode(end), getLabelNode(handler), type));
}
@Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
TryCatchBlockNode tcb = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
if (visible) {
if (tcb.visibleTypeAnnotations == null) {
tcb.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
1);
}
tcb.visibleTypeAnnotations.add(an);
} else {
if (tcb.invisibleTypeAnnotations == null) {
tcb.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
1);
}
tcb.invisibleTypeAnnotations.add(an);
}
return an;
}
@Override
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,
getLabelNode(start), getLabelNode(end), index));
}
@Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
LocalVariableAnnotationNode an = new LocalVariableAnnotationNode(
typeRef, typePath, getLabelNodes(start), getLabelNodes(end),
index, desc);
if (visible) {
if (visibleLocalVariableAnnotations == null) {
visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
1);
}
visibleLocalVariableAnnotations.add(an);
} else {
if (invisibleLocalVariableAnnotations == null) {
invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
1);
}
invisibleLocalVariableAnnotations.add(an);
}
return an;
}
@Override
public void visitLineNumber(final int line, final Label start) {
instructions.add(new LineNumberNode(line, getLabelNode(start)));
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
this.maxStack = maxStack;
this.maxLocals = maxLocals;
}
@Override
public void visitEnd() {
}
/**
* Returns the LabelNode corresponding to the given Label. Creates a new
* LabelNode if necessary. The default implementation of this method uses
* the {@link Label#info} field to store associations between labels and
* label nodes.
*
* @param l
* a Label.
* @return the LabelNode corresponding to l.
*/
protected LabelNode getLabelNode(final Label l) {
if (!(l.info instanceof LabelNode)) {
l.info = new LabelNode();
}
return (LabelNode) l.info;
}
private LabelNode[] getLabelNodes(final Label[] l) {
LabelNode[] nodes = new LabelNode[l.length];
for (int i = 0; i < l.length; ++i) {
nodes[i] = getLabelNode(l[i]);
}
return nodes;
}
private Object[] getLabelNodes(final Object[] objs) {
Object[] nodes = new Object[objs.length];
for (int i = 0; i < objs.length; ++i) {
Object o = objs[i];
if (o instanceof Label) {
o = getLabelNode((Label) o);
}
nodes[i] = o;
}
return nodes;
}
// ------------------------------------------------------------------------
// Accept method
// ------------------------------------------------------------------------
/**
* Checks that this method node is compatible with the given ASM API
* version. This methods checks that this node, and all its nodes
* recursively, do not contain elements that were introduced in more recent
* versions of the ASM API than the given version.
*
* @param api
* an ASM API version. Must be one of {@link Opcodes#ASM4} or
* {@link Opcodes#ASM5}.
*/
public void check(final int api) {
if (api == Opcodes.ASM4) {
if (visibleTypeAnnotations != null
&& visibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
if (invisibleTypeAnnotations != null
&& invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
int n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
for (int i = 0; i < n; ++i) {
TryCatchBlockNode tcb = tryCatchBlocks.get(i);
if (tcb.visibleTypeAnnotations != null
&& tcb.visibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
if (tcb.invisibleTypeAnnotations != null
&& tcb.invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
}
for (int i = 0; i < instructions.size(); ++i) {
AbstractInsnNode insn = instructions.get(i);
if (insn.visibleTypeAnnotations != null
&& insn.visibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
if (insn.invisibleTypeAnnotations != null
&& insn.invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
}
if (visibleLocalVariableAnnotations != null
&& visibleLocalVariableAnnotations.size() > 0) {
throw new RuntimeException();
}
if (invisibleLocalVariableAnnotations != null
&& invisibleLocalVariableAnnotations.size() > 0) {
throw new RuntimeException();
}
}
}
/**
* Makes the given class visitor visit this method.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
String[] exceptions = new String[this.exceptions.size()];
this.exceptions.toArray(exceptions);
MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
if (mv != null) {
accept(mv);
}
}
/**
* Makes the given method visitor visit this method.
*
* @param mv
* a method visitor.
*/
public void accept(final MethodVisitor mv) {
// visits the method parameters
int i, j, n;
n = parameters == null ? 0 : parameters.size();
for (i = 0; i < n; i++) {
ParameterNode parameter = parameters.get(i);
mv.visitParameter(parameter.name, parameter.access);
}
// visits the method attributes
if (annotationDefault != null) {
AnnotationVisitor av = mv.visitAnnotationDefault();
AnnotationNode.accept(av, null, annotationDefault);
if (av != null) {
av.visitEnd();
}
}
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = visibleAnnotations.get(i);
an.accept(mv.visitAnnotation(an.desc, true));
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(mv.visitAnnotation(an.desc, false));
}
n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
true));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
false));
}
n = visibleParameterAnnotations == null ? 0
: visibleParameterAnnotations.length;
for (i = 0; i < n; ++i) {
List<?> l = visibleParameterAnnotations[i];
if (l == null) {
continue;
}
for (j = 0; j < l.size(); ++j) {
AnnotationNode an = (AnnotationNode) l.get(j);
an.accept(mv.visitParameterAnnotation(i, an.desc, true));
}
}
n = invisibleParameterAnnotations == null ? 0
: invisibleParameterAnnotations.length;
for (i = 0; i < n; ++i) {
List<?> l = invisibleParameterAnnotations[i];
if (l == null) {
continue;
}
for (j = 0; j < l.size(); ++j) {
AnnotationNode an = (AnnotationNode) l.get(j);
an.accept(mv.visitParameterAnnotation(i, an.desc, false));
}
}
if (visited) {
instructions.resetLabels();
}
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
mv.visitAttribute(attrs.get(i));
}
// visits the method's code
if (instructions.size() > 0) {
mv.visitCode();
// visits try catch blocks
n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
for (i = 0; i < n; ++i) {
tryCatchBlocks.get(i).updateIndex(i);
tryCatchBlocks.get(i).accept(mv);
}
// visits instructions
instructions.accept(mv);
// visits local variables
n = localVariables == null ? 0 : localVariables.size();
for (i = 0; i < n; ++i) {
localVariables.get(i).accept(mv);
}
// visits local variable annotations
n = visibleLocalVariableAnnotations == null ? 0
: visibleLocalVariableAnnotations.size();
for (i = 0; i < n; ++i) {
visibleLocalVariableAnnotations.get(i).accept(mv, true);
}
n = invisibleLocalVariableAnnotations == null ? 0
: invisibleLocalVariableAnnotations.size();
for (i = 0; i < n; ++i) {
invisibleLocalVariableAnnotations.get(i).accept(mv, false);
}
// visits maxs
mv.visitMaxs(maxStack, maxLocals);
visited = true;
}
mv.visitEnd();
}
}
@@ -0,0 +1,84 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents a MULTIANEWARRAY instruction.
*
* @author Eric Bruneton
*/
public class MultiANewArrayInsnNode extends AbstractInsnNode {
/**
* An array type descriptor (see {@link org.objectweb.asm.Type}).
*/
public String desc;
/**
* Number of dimensions of the array to allocate.
*/
public int dims;
/**
* Constructs a new {@link MultiANewArrayInsnNode}.
*
* @param desc
* an array type descriptor (see {@link org.objectweb.asm.Type}).
* @param dims
* number of dimensions of the array to allocate.
*/
public MultiANewArrayInsnNode(final String desc, final int dims) {
super(Opcodes.MULTIANEWARRAY);
this.desc = desc;
this.dims = dims;
}
@Override
public int getType() {
return MULTIANEWARRAY_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitMultiANewArrayInsn(desc, dims);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
}
}
@@ -0,0 +1,76 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a parameter access and name.
*
* @author Remi Forax
*/
public class ParameterNode {
/**
* The parameter's name.
*/
public String name;
/**
* The parameter's access flags (see {@link org.objectweb.asm.Opcodes}).
* Valid values are <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and
* <tt>ACC_MANDATED</tt>.
*/
public int access;
/**
* Constructs a new {@link ParameterNode}.
*
* @param access
* The parameter's access flags. Valid values are
* <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> or/and
* <tt>ACC_MANDATED</tt> (see {@link org.objectweb.asm.Opcodes}).
* @param name
* the parameter's name.
*/
public ParameterNode(final String name, final int access) {
this.name = name;
this.access = access;
}
/**
* Makes the given visitor visit this parameter declaration.
*
* @param mv
* a method visitor.
*/
public void accept(final MethodVisitor mv) {
mv.visitParameter(name, access);
}
}
@@ -0,0 +1,114 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents a TABLESWITCH instruction.
*
* @author Eric Bruneton
*/
public class TableSwitchInsnNode extends AbstractInsnNode {
/**
* The minimum key value.
*/
public int min;
/**
* The maximum key value.
*/
public int max;
/**
* Beginning of the default handler block.
*/
public LabelNode dflt;
/**
* Beginnings of the handler blocks. This list is a list of
* {@link LabelNode} objects.
*/
public List<LabelNode> labels;
/**
* Constructs a new {@link TableSwitchInsnNode}.
*
* @param min
* the minimum key value.
* @param max
* the maximum key value.
* @param dflt
* beginning of the default handler block.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>min + i</tt> key.
*/
public TableSwitchInsnNode(final int min, final int max,
final LabelNode dflt, final LabelNode... labels) {
super(Opcodes.TABLESWITCH);
this.min = min;
this.max = max;
this.dflt = dflt;
this.labels = new ArrayList<LabelNode>();
if (labels != null) {
this.labels.addAll(Arrays.asList(labels));
}
}
@Override
public int getType() {
return TABLESWITCH_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
Label[] labels = new Label[this.labels.size()];
for (int i = 0; i < labels.length; ++i) {
labels[i] = this.labels.get(i).getLabel();
}
mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone(
this.labels, labels)).cloneAnnotations(this);
}
}
@@ -0,0 +1,153 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.List;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a try catch block.
*
* @author Eric Bruneton
*/
public class TryCatchBlockNode {
/**
* Beginning of the exception handler's scope (inclusive).
*/
public LabelNode start;
/**
* End of the exception handler's scope (exclusive).
*/
public LabelNode end;
/**
* Beginning of the exception handler's code.
*/
public LabelNode handler;
/**
* Internal name of the type of exceptions handled by the handler. May be
* <tt>null</tt> to catch any exceptions (for "finally" blocks).
*/
public String type;
/**
* The runtime visible type annotations on the exception handler type. This
* list is a list of {@link TypeAnnotationNode} objects. May be
* <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations on the exception handler type.
* This list is a list of {@link TypeAnnotationNode} objects. May be
* <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* Constructs a new {@link TryCatchBlockNode}.
*
* @param start
* beginning of the exception handler's scope (inclusive).
* @param end
* end of the exception handler's scope (exclusive).
* @param handler
* beginning of the exception handler's code.
* @param type
* internal name of the type of exceptions handled by the
* handler, or <tt>null</tt> to catch any exceptions (for
* "finally" blocks).
*/
public TryCatchBlockNode(final LabelNode start, final LabelNode end,
final LabelNode handler, final String type) {
this.start = start;
this.end = end;
this.handler = handler;
this.type = type;
}
/**
* Updates the index of this try catch block in the method's list of try
* catch block nodes. This index maybe stored in the 'target' field of the
* type annotations of this block.
*
* @param index
* the new index of this try catch block in the method's list of
* try catch block nodes.
*/
public void updateIndex(final int index) {
int newTypeRef = 0x42000000 | (index << 8);
if (visibleTypeAnnotations != null) {
for (TypeAnnotationNode tan : visibleTypeAnnotations) {
tan.typeRef = newTypeRef;
}
}
if (invisibleTypeAnnotations != null) {
for (TypeAnnotationNode tan : invisibleTypeAnnotations) {
tan.typeRef = newTypeRef;
}
}
}
/**
* Makes the given visitor visit this try catch block.
*
* @param mv
* a method visitor.
*/
public void accept(final MethodVisitor mv) {
mv.visitTryCatchBlock(start.getLabel(), end.getLabel(),
handler == null ? null : handler.getLabel(), type);
int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
an.desc, true));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
an.desc, false));
}
}
}
@@ -0,0 +1,95 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
import org.objectweb.asm.TypeReference;
/**
* A node that represents a type annotationn.
*
* @author Eric Bruneton
*/
public class TypeAnnotationNode extends AnnotationNode {
/**
* A reference to the annotated type. See {@link TypeReference}.
*/
public int typeRef;
/**
* The path to the annotated type argument, wildcard bound, array element
* type, or static outer type within the referenced type. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
*/
public TypePath typePath;
/**
* Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
*
* @param typeRef
* a reference to the annotated type. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
*/
public TypeAnnotationNode(final int typeRef, final TypePath typePath,
final String desc) {
this(Opcodes.ASM5, typeRef, typePath, desc);
}
/**
* Constructs a new {@link AnnotationNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param typeRef
* a reference to the annotated type. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
*/
public TypeAnnotationNode(final int api, final int typeRef,
final TypePath typePath, final String desc) {
super(api, desc);
this.typeRef = typeRef;
this.typePath = typePath;
}
}
@@ -0,0 +1,91 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a type instruction. A type instruction is an
* instruction that takes a type descriptor as parameter.
*
* @author Eric Bruneton
*/
public class TypeInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction. This operand is an internal name (see
* {@link org.objectweb.asm.Type}).
*/
public String desc;
/**
* Constructs a new {@link TypeInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param desc
* the operand of the instruction to be constructed. This operand
* is an internal name (see {@link org.objectweb.asm.Type}).
*/
public TypeInsnNode(final int opcode, final String desc) {
super(opcode);
this.desc = desc;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be NEW,
* ANEWARRAY, CHECKCAST or INSTANCEOF.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return TYPE_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitTypeInsn(opcode, desc);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
}
}
@@ -0,0 +1,94 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a local variable instruction. A local variable
* instruction is an instruction that loads or stores the value of a local
* variable.
*
* @author Eric Bruneton
*/
public class VarInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction. This operand is the index of a local
* variable.
*/
public int var;
/**
* Constructs a new {@link VarInsnNode}.
*
* @param opcode
* the opcode of the local variable instruction to be
* constructed. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD,
* ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
* @param var
* the operand of the instruction to be constructed. This operand
* is the index of a local variable.
*/
public VarInsnNode(final int opcode, final int var) {
super(opcode);
this.var = var;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be ILOAD, LLOAD,
* FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or
* RET.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return VAR_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitVarInsn(opcode, var);
acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new VarInsnNode(opcode, var).cloneAnnotations(this);
}
}
@@ -0,0 +1,550 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LookupSwitchInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
import org.objectweb.asm.tree.VarInsnNode;
/**
* A semantic bytecode analyzer. <i>This class does not fully check that JSR and
* RET instructions are valid.</i>
*
* @param <V>
* type of the Value used for the analysis.
*
* @author Eric Bruneton
*/
public class Analyzer<V extends Value> implements Opcodes {
private final Interpreter<V> interpreter;
private int n;
private InsnList insns;
private List<TryCatchBlockNode>[] handlers;
private Frame<V>[] frames;
private Subroutine[] subroutines;
private boolean[] queued;
private int[] queue;
private int top;
/**
* Constructs a new {@link Analyzer}.
*
* @param interpreter
* the interpreter to be used to symbolically interpret the
* bytecode instructions.
*/
public Analyzer(final Interpreter<V> interpreter) {
this.interpreter = interpreter;
}
/**
* Analyzes the given method.
*
* @param owner
* the internal name of the class to which the method belongs.
* @param m
* the method to be analyzed.
* @return the symbolic state of the execution stack frame at each bytecode
* instruction of the method. The size of the returned array is
* equal to the number of instructions (and labels) of the method. A
* given frame is <tt>null</tt> if and only if the corresponding
* instruction cannot be reached (dead code).
* @throws AnalyzerException
* if a problem occurs during the analysis.
*/
@SuppressWarnings("unchecked")
public Frame<V>[] analyze(final String owner, final MethodNode m)
throws AnalyzerException {
if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
frames = (Frame<V>[]) new Frame<?>[0];
return frames;
}
n = m.instructions.size();
insns = m.instructions;
handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
frames = (Frame<V>[]) new Frame<?>[n];
subroutines = new Subroutine[n];
queued = new boolean[n];
queue = new int[n];
top = 0;
// computes exception handlers for each instruction
for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
int begin = insns.indexOf(tcb.start);
int end = insns.indexOf(tcb.end);
for (int j = begin; j < end; ++j) {
List<TryCatchBlockNode> insnHandlers = handlers[j];
if (insnHandlers == null) {
insnHandlers = new ArrayList<TryCatchBlockNode>();
handlers[j] = insnHandlers;
}
insnHandlers.add(tcb);
}
}
// computes the subroutine for each instruction:
Subroutine main = new Subroutine(null, m.maxLocals, null);
List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
findSubroutine(0, main, subroutineCalls);
while (!subroutineCalls.isEmpty()) {
JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
Subroutine sub = subroutineHeads.get(jsr.label);
if (sub == null) {
sub = new Subroutine(jsr.label, m.maxLocals, jsr);
subroutineHeads.put(jsr.label, sub);
findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
} else {
sub.callers.add(jsr);
}
}
for (int i = 0; i < n; ++i) {
if (subroutines[i] != null && subroutines[i].start == null) {
subroutines[i] = null;
}
}
// initializes the data structures for the control flow analysis
Frame<V> current = newFrame(m.maxLocals, m.maxStack);
Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
Type[] args = Type.getArgumentTypes(m.desc);
int local = 0;
if ((m.access & ACC_STATIC) == 0) {
Type ctype = Type.getObjectType(owner);
current.setLocal(local++, interpreter.newValue(ctype));
}
for (int i = 0; i < args.length; ++i) {
current.setLocal(local++, interpreter.newValue(args[i]));
if (args[i].getSize() == 2) {
current.setLocal(local++, interpreter.newValue(null));
}
}
while (local < m.maxLocals) {
current.setLocal(local++, interpreter.newValue(null));
}
merge(0, current, null);
init(owner, m);
// control flow analysis
while (top > 0) {
int insn = queue[--top];
Frame<V> f = frames[insn];
Subroutine subroutine = subroutines[insn];
queued[insn] = false;
AbstractInsnNode insnNode = null;
try {
insnNode = m.instructions.get(insn);
int insnOpcode = insnNode.getOpcode();
int insnType = insnNode.getType();
if (insnType == AbstractInsnNode.LABEL
|| insnType == AbstractInsnNode.LINE
|| insnType == AbstractInsnNode.FRAME) {
merge(insn + 1, f, subroutine);
newControlFlowEdge(insn, insn + 1);
} else {
current.init(f).execute(insnNode, interpreter);
subroutine = subroutine == null ? null : subroutine.copy();
if (insnNode instanceof JumpInsnNode) {
JumpInsnNode j = (JumpInsnNode) insnNode;
if (insnOpcode != GOTO && insnOpcode != JSR) {
merge(insn + 1, current, subroutine);
newControlFlowEdge(insn, insn + 1);
}
int jump = insns.indexOf(j.label);
if (insnOpcode == JSR) {
merge(jump, current, new Subroutine(j.label,
m.maxLocals, j));
} else {
merge(jump, current, subroutine);
}
newControlFlowEdge(insn, jump);
} else if (insnNode instanceof LookupSwitchInsnNode) {
LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
int jump = insns.indexOf(lsi.dflt);
merge(jump, current, subroutine);
newControlFlowEdge(insn, jump);
for (int j = 0; j < lsi.labels.size(); ++j) {
LabelNode label = lsi.labels.get(j);
jump = insns.indexOf(label);
merge(jump, current, subroutine);
newControlFlowEdge(insn, jump);
}
} else if (insnNode instanceof TableSwitchInsnNode) {
TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
int jump = insns.indexOf(tsi.dflt);
merge(jump, current, subroutine);
newControlFlowEdge(insn, jump);
for (int j = 0; j < tsi.labels.size(); ++j) {
LabelNode label = tsi.labels.get(j);
jump = insns.indexOf(label);
merge(jump, current, subroutine);
newControlFlowEdge(insn, jump);
}
} else if (insnOpcode == RET) {
if (subroutine == null) {
throw new AnalyzerException(insnNode,
"RET instruction outside of a sub routine");
}
for (int i = 0; i < subroutine.callers.size(); ++i) {
JumpInsnNode caller = subroutine.callers.get(i);
int call = insns.indexOf(caller);
if (frames[call] != null) {
merge(call + 1, frames[call], current,
subroutines[call], subroutine.access);
newControlFlowEdge(insn, call + 1);
}
}
} else if (insnOpcode != ATHROW
&& (insnOpcode < IRETURN || insnOpcode > RETURN)) {
if (subroutine != null) {
if (insnNode instanceof VarInsnNode) {
int var = ((VarInsnNode) insnNode).var;
subroutine.access[var] = true;
if (insnOpcode == LLOAD || insnOpcode == DLOAD
|| insnOpcode == LSTORE
|| insnOpcode == DSTORE) {
subroutine.access[var + 1] = true;
}
} else if (insnNode instanceof IincInsnNode) {
int var = ((IincInsnNode) insnNode).var;
subroutine.access[var] = true;
}
}
merge(insn + 1, current, subroutine);
newControlFlowEdge(insn, insn + 1);
}
}
List<TryCatchBlockNode> insnHandlers = handlers[insn];
if (insnHandlers != null) {
for (int i = 0; i < insnHandlers.size(); ++i) {
TryCatchBlockNode tcb = insnHandlers.get(i);
Type type;
if (tcb.type == null) {
type = Type.getObjectType("java/lang/Throwable");
} else {
type = Type.getObjectType(tcb.type);
}
int jump = insns.indexOf(tcb.handler);
if (newControlFlowExceptionEdge(insn, tcb)) {
handler.init(f);
handler.clearStack();
handler.push(interpreter.newValue(type));
merge(jump, handler, subroutine);
}
}
}
} catch (AnalyzerException e) {
throw new AnalyzerException(e.node, "Error at instruction "
+ insn + ": " + e.getMessage(), e);
} catch (Exception e) {
throw new AnalyzerException(insnNode, "Error at instruction "
+ insn + ": " + e.getMessage(), e);
}
}
return frames;
}
private void findSubroutine(int insn, final Subroutine sub,
final List<AbstractInsnNode> calls) throws AnalyzerException {
while (true) {
if (insn < 0 || insn >= n) {
throw new AnalyzerException(null,
"Execution can fall off end of the code");
}
if (subroutines[insn] != null) {
return;
}
subroutines[insn] = sub.copy();
AbstractInsnNode node = insns.get(insn);
// calls findSubroutine recursively on normal successors
if (node instanceof JumpInsnNode) {
if (node.getOpcode() == JSR) {
// do not follow a JSR, it leads to another subroutine!
calls.add(node);
} else {
JumpInsnNode jnode = (JumpInsnNode) node;
findSubroutine(insns.indexOf(jnode.label), sub, calls);
}
} else if (node instanceof TableSwitchInsnNode) {
TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
LabelNode l = tsnode.labels.get(i);
findSubroutine(insns.indexOf(l), sub, calls);
}
} else if (node instanceof LookupSwitchInsnNode) {
LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
LabelNode l = lsnode.labels.get(i);
findSubroutine(insns.indexOf(l), sub, calls);
}
}
// calls findSubroutine recursively on exception handler successors
List<TryCatchBlockNode> insnHandlers = handlers[insn];
if (insnHandlers != null) {
for (int i = 0; i < insnHandlers.size(); ++i) {
TryCatchBlockNode tcb = insnHandlers.get(i);
findSubroutine(insns.indexOf(tcb.handler), sub, calls);
}
}
// if insn does not falls through to the next instruction, return.
switch (node.getOpcode()) {
case GOTO:
case RET:
case TABLESWITCH:
case LOOKUPSWITCH:
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
case RETURN:
case ATHROW:
return;
}
insn++;
}
}
/**
* Returns the symbolic stack frame for each instruction of the last
* recently analyzed method.
*
* @return the symbolic state of the execution stack frame at each bytecode
* instruction of the method. The size of the returned array is
* equal to the number of instructions (and labels) of the method. A
* given frame is <tt>null</tt> if the corresponding instruction
* cannot be reached, or if an error occured during the analysis of
* the method.
*/
public Frame<V>[] getFrames() {
return frames;
}
/**
* Returns the exception handlers for the given instruction.
*
* @param insn
* the index of an instruction of the last recently analyzed
* method.
* @return a list of {@link TryCatchBlockNode} objects.
*/
public List<TryCatchBlockNode> getHandlers(final int insn) {
return handlers[insn];
}
/**
* Initializes this analyzer. This method is called just before the
* execution of control flow analysis loop in #analyze. The default
* implementation of this method does nothing.
*
* @param owner
* the internal name of the class to which the method belongs.
* @param m
* the method to be analyzed.
* @throws AnalyzerException
* if a problem occurs.
*/
protected void init(String owner, MethodNode m) throws AnalyzerException {
}
/**
* Constructs a new frame with the given size.
*
* @param nLocals
* the maximum number of local variables of the frame.
* @param nStack
* the maximum stack size of the frame.
* @return the created frame.
*/
protected Frame<V> newFrame(final int nLocals, final int nStack) {
return new Frame<V>(nLocals, nStack);
}
/**
* Constructs a new frame that is identical to the given frame.
*
* @param src
* a frame.
* @return the created frame.
*/
protected Frame<V> newFrame(final Frame<? extends V> src) {
return new Frame<V>(src);
}
/**
* Creates a control flow graph edge. The default implementation of this
* method does nothing. It can be overriden in order to construct the
* control flow graph of a method (this method is called by the
* {@link #analyze analyze} method during its visit of the method's code).
*
* @param insn
* an instruction index.
* @param successor
* index of a successor instruction.
*/
protected void newControlFlowEdge(final int insn, final int successor) {
}
/**
* Creates a control flow graph edge corresponding to an exception handler.
* The default implementation of this method does nothing. It can be
* overridden in order to construct the control flow graph of a method (this
* method is called by the {@link #analyze analyze} method during its visit
* of the method's code).
*
* @param insn
* an instruction index.
* @param successor
* index of a successor instruction.
* @return true if this edge must be considered in the data flow analysis
* performed by this analyzer, or false otherwise. The default
* implementation of this method always returns true.
*/
protected boolean newControlFlowExceptionEdge(final int insn,
final int successor) {
return true;
}
/**
* Creates a control flow graph edge corresponding to an exception handler.
* The default implementation of this method delegates to
* {@link #newControlFlowExceptionEdge(int, int)
* newControlFlowExceptionEdge(int, int)}. It can be overridden in order to
* construct the control flow graph of a method (this method is called by
* the {@link #analyze analyze} method during its visit of the method's
* code).
*
* @param insn
* an instruction index.
* @param tcb
* TryCatchBlockNode corresponding to this edge.
* @return true if this edge must be considered in the data flow analysis
* performed by this analyzer, or false otherwise. The default
* implementation of this method delegates to
* {@link #newControlFlowExceptionEdge(int, int)
* newControlFlowExceptionEdge(int, int)}.
*/
protected boolean newControlFlowExceptionEdge(final int insn,
final TryCatchBlockNode tcb) {
return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler));
}
// -------------------------------------------------------------------------
private void merge(final int insn, final Frame<V> frame,
final Subroutine subroutine) throws AnalyzerException {
Frame<V> oldFrame = frames[insn];
Subroutine oldSubroutine = subroutines[insn];
boolean changes;
if (oldFrame == null) {
frames[insn] = newFrame(frame);
changes = true;
} else {
changes = oldFrame.merge(frame, interpreter);
}
if (oldSubroutine == null) {
if (subroutine != null) {
subroutines[insn] = subroutine.copy();
changes = true;
}
} else {
if (subroutine != null) {
changes |= oldSubroutine.merge(subroutine);
}
}
if (changes && !queued[insn]) {
queued[insn] = true;
queue[top++] = insn;
}
}
private void merge(final int insn, final Frame<V> beforeJSR,
final Frame<V> afterRET, final Subroutine subroutineBeforeJSR,
final boolean[] access) throws AnalyzerException {
Frame<V> oldFrame = frames[insn];
Subroutine oldSubroutine = subroutines[insn];
boolean changes;
afterRET.merge(beforeJSR, access);
if (oldFrame == null) {
frames[insn] = newFrame(afterRET);
changes = true;
} else {
changes = oldFrame.merge(afterRET, interpreter);
}
if (oldSubroutine != null && subroutineBeforeJSR != null) {
changes |= oldSubroutine.merge(subroutineBeforeJSR);
}
if (changes && !queued[insn]) {
queued[insn] = true;
queue[top++] = insn;
}
}
}
@@ -0,0 +1,61 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import org.objectweb.asm.tree.AbstractInsnNode;
/**
* Thrown if a problem occurs during the analysis of a method.
*
* @author Bing Ran
* @author Eric Bruneton
*/
public class AnalyzerException extends Exception {
private static final long serialVersionUID = -1788355977291059681L;
public final AbstractInsnNode node;
public AnalyzerException(final AbstractInsnNode node, final String msg) {
super(msg);
this.node = node;
}
public AnalyzerException(final AbstractInsnNode node, final String msg,
final Throwable exception) {
super(msg, exception);
this.node = node;
}
public AnalyzerException(final AbstractInsnNode node, final String msg,
final Object expected, final Value encountered) {
super((msg == null ? "Expected " : msg + ": expected ") + expected
+ ", but found " + encountered);
this.node = node;
}
}
@@ -0,0 +1,358 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.List;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
/**
* An {@link Interpreter} for {@link BasicValue} values.
*
* @author Eric Bruneton
* @author Bing Ran
*/
public class BasicInterpreter extends Interpreter<BasicValue> implements
Opcodes {
public BasicInterpreter() {
super(ASM4);
}
protected BasicInterpreter(final int api) {
super(api);
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return BasicValue.INT_VALUE;
case Type.FLOAT:
return BasicValue.FLOAT_VALUE;
case Type.LONG:
return BasicValue.LONG_VALUE;
case Type.DOUBLE:
return BasicValue.DOUBLE_VALUE;
case Type.ARRAY:
case Type.OBJECT:
return BasicValue.REFERENCE_VALUE;
default:
throw new Error("Internal error");
}
}
@Override
public BasicValue newOperation(final AbstractInsnNode insn)
throws AnalyzerException {
switch (insn.getOpcode()) {
case ACONST_NULL:
return newValue(Type.getObjectType("null"));
case ICONST_M1:
case ICONST_0:
case ICONST_1:
case ICONST_2:
case ICONST_3:
case ICONST_4:
case ICONST_5:
return BasicValue.INT_VALUE;
case LCONST_0:
case LCONST_1:
return BasicValue.LONG_VALUE;
case FCONST_0:
case FCONST_1:
case FCONST_2:
return BasicValue.FLOAT_VALUE;
case DCONST_0:
case DCONST_1:
return BasicValue.DOUBLE_VALUE;
case BIPUSH:
case SIPUSH:
return BasicValue.INT_VALUE;
case LDC:
Object cst = ((LdcInsnNode) insn).cst;
if (cst instanceof Integer) {
return BasicValue.INT_VALUE;
} else if (cst instanceof Float) {
return BasicValue.FLOAT_VALUE;
} else if (cst instanceof Long) {
return BasicValue.LONG_VALUE;
} else if (cst instanceof Double) {
return BasicValue.DOUBLE_VALUE;
} else if (cst instanceof String) {
return newValue(Type.getObjectType("java/lang/String"));
} else if (cst instanceof Type) {
int sort = ((Type) cst).getSort();
if (sort == Type.OBJECT || sort == Type.ARRAY) {
return newValue(Type.getObjectType("java/lang/Class"));
} else if (sort == Type.METHOD) {
return newValue(Type
.getObjectType("java/lang/invoke/MethodType"));
} else {
throw new IllegalArgumentException("Illegal LDC constant "
+ cst);
}
} else if (cst instanceof Handle) {
return newValue(Type
.getObjectType("java/lang/invoke/MethodHandle"));
} else {
throw new IllegalArgumentException("Illegal LDC constant "
+ cst);
}
case JSR:
return BasicValue.RETURNADDRESS_VALUE;
case GETSTATIC:
return newValue(Type.getType(((FieldInsnNode) insn).desc));
case NEW:
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
default:
throw new Error("Internal error.");
}
}
@Override
public BasicValue copyOperation(final AbstractInsnNode insn,
final BasicValue value) throws AnalyzerException {
return value;
}
@Override
public BasicValue unaryOperation(final AbstractInsnNode insn,
final BasicValue value) throws AnalyzerException {
switch (insn.getOpcode()) {
case INEG:
case IINC:
case L2I:
case F2I:
case D2I:
case I2B:
case I2C:
case I2S:
return BasicValue.INT_VALUE;
case FNEG:
case I2F:
case L2F:
case D2F:
return BasicValue.FLOAT_VALUE;
case LNEG:
case I2L:
case F2L:
case D2L:
return BasicValue.LONG_VALUE;
case DNEG:
case I2D:
case L2D:
case F2D:
return BasicValue.DOUBLE_VALUE;
case IFEQ:
case IFNE:
case IFLT:
case IFGE:
case IFGT:
case IFLE:
case TABLESWITCH:
case LOOKUPSWITCH:
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
case PUTSTATIC:
return null;
case GETFIELD:
return newValue(Type.getType(((FieldInsnNode) insn).desc));
case NEWARRAY:
switch (((IntInsnNode) insn).operand) {
case T_BOOLEAN:
return newValue(Type.getType("[Z"));
case T_CHAR:
return newValue(Type.getType("[C"));
case T_BYTE:
return newValue(Type.getType("[B"));
case T_SHORT:
return newValue(Type.getType("[S"));
case T_INT:
return newValue(Type.getType("[I"));
case T_FLOAT:
return newValue(Type.getType("[F"));
case T_DOUBLE:
return newValue(Type.getType("[D"));
case T_LONG:
return newValue(Type.getType("[J"));
default:
throw new AnalyzerException(insn, "Invalid array type");
}
case ANEWARRAY:
String desc = ((TypeInsnNode) insn).desc;
return newValue(Type.getType("[" + Type.getObjectType(desc)));
case ARRAYLENGTH:
return BasicValue.INT_VALUE;
case ATHROW:
return null;
case CHECKCAST:
desc = ((TypeInsnNode) insn).desc;
return newValue(Type.getObjectType(desc));
case INSTANCEOF:
return BasicValue.INT_VALUE;
case MONITORENTER:
case MONITOREXIT:
case IFNULL:
case IFNONNULL:
return null;
default:
throw new Error("Internal error.");
}
}
@Override
public BasicValue binaryOperation(final AbstractInsnNode insn,
final BasicValue value1, final BasicValue value2)
throws AnalyzerException {
switch (insn.getOpcode()) {
case IALOAD:
case BALOAD:
case CALOAD:
case SALOAD:
case IADD:
case ISUB:
case IMUL:
case IDIV:
case IREM:
case ISHL:
case ISHR:
case IUSHR:
case IAND:
case IOR:
case IXOR:
return BasicValue.INT_VALUE;
case FALOAD:
case FADD:
case FSUB:
case FMUL:
case FDIV:
case FREM:
return BasicValue.FLOAT_VALUE;
case LALOAD:
case LADD:
case LSUB:
case LMUL:
case LDIV:
case LREM:
case LSHL:
case LSHR:
case LUSHR:
case LAND:
case LOR:
case LXOR:
return BasicValue.LONG_VALUE;
case DALOAD:
case DADD:
case DSUB:
case DMUL:
case DDIV:
case DREM:
return BasicValue.DOUBLE_VALUE;
case AALOAD:
return BasicValue.REFERENCE_VALUE;
case LCMP:
case FCMPL:
case FCMPG:
case DCMPL:
case DCMPG:
return BasicValue.INT_VALUE;
case IF_ICMPEQ:
case IF_ICMPNE:
case IF_ICMPLT:
case IF_ICMPGE:
case IF_ICMPGT:
case IF_ICMPLE:
case IF_ACMPEQ:
case IF_ACMPNE:
case PUTFIELD:
return null;
default:
throw new Error("Internal error.");
}
}
@Override
public BasicValue ternaryOperation(final AbstractInsnNode insn,
final BasicValue value1, final BasicValue value2,
final BasicValue value3) throws AnalyzerException {
return null;
}
@Override
public BasicValue naryOperation(final AbstractInsnNode insn,
final List<? extends BasicValue> values) throws AnalyzerException {
int opcode = insn.getOpcode();
if (opcode == MULTIANEWARRAY) {
return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
} else if (opcode == INVOKEDYNAMIC) {
return newValue(Type
.getReturnType(((InvokeDynamicInsnNode) insn).desc));
} else {
return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
}
}
@Override
public void returnOperation(final AbstractInsnNode insn,
final BasicValue value, final BasicValue expected)
throws AnalyzerException {
}
@Override
public BasicValue merge(final BasicValue v, final BasicValue w) {
if (!v.equals(w)) {
return BasicValue.UNINITIALIZED_VALUE;
}
return v;
}
}
@@ -0,0 +1,111 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import org.objectweb.asm.Type;
/**
* A {@link Value} that is represented by its type in a seven types type system.
* This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE,
* REFERENCE and RETURNADDRESS types.
*
* @author Eric Bruneton
*/
public class BasicValue implements Value {
public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
public static final BasicValue DOUBLE_VALUE = new BasicValue(
Type.DOUBLE_TYPE);
public static final BasicValue REFERENCE_VALUE = new BasicValue(
Type.getObjectType("java/lang/Object"));
public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(
Type.VOID_TYPE);
private final Type type;
public BasicValue(final Type type) {
this.type = type;
}
public Type getType() {
return type;
}
public int getSize() {
return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
}
public boolean isReference() {
return type != null
&& (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
}
@Override
public boolean equals(final Object value) {
if (value == this) {
return true;
} else if (value instanceof BasicValue) {
if (type == null) {
return ((BasicValue) value).type == null;
} else {
return type.equals(((BasicValue) value).type);
}
} else {
return false;
}
}
@Override
public int hashCode() {
return type == null ? 0 : type.hashCode();
}
@Override
public String toString() {
if (this == UNINITIALIZED_VALUE) {
return ".";
} else if (this == RETURNADDRESS_VALUE) {
return "A";
} else if (this == REFERENCE_VALUE) {
return "R";
} else {
return type.getDescriptor();
}
}
}
@@ -0,0 +1,433 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.List;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
/**
* An extended {@link BasicInterpreter} that checks that bytecode instructions
* are correctly used.
*
* @author Eric Bruneton
* @author Bing Ran
*/
public class BasicVerifier extends BasicInterpreter {
public BasicVerifier() {
super(ASM4);
}
protected BasicVerifier(final int api) {
super(api);
}
@Override
public BasicValue copyOperation(final AbstractInsnNode insn,
final BasicValue value) throws AnalyzerException {
Value expected;
switch (insn.getOpcode()) {
case ILOAD:
case ISTORE:
expected = BasicValue.INT_VALUE;
break;
case FLOAD:
case FSTORE:
expected = BasicValue.FLOAT_VALUE;
break;
case LLOAD:
case LSTORE:
expected = BasicValue.LONG_VALUE;
break;
case DLOAD:
case DSTORE:
expected = BasicValue.DOUBLE_VALUE;
break;
case ALOAD:
if (!value.isReference()) {
throw new AnalyzerException(insn, null, "an object reference",
value);
}
return value;
case ASTORE:
if (!value.isReference()
&& !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
throw new AnalyzerException(insn, null,
"an object reference or a return address", value);
}
return value;
default:
return value;
}
if (!expected.equals(value)) {
throw new AnalyzerException(insn, null, expected, value);
}
return value;
}
@Override
public BasicValue unaryOperation(final AbstractInsnNode insn,
final BasicValue value) throws AnalyzerException {
BasicValue expected;
switch (insn.getOpcode()) {
case INEG:
case IINC:
case I2F:
case I2L:
case I2D:
case I2B:
case I2C:
case I2S:
case IFEQ:
case IFNE:
case IFLT:
case IFGE:
case IFGT:
case IFLE:
case TABLESWITCH:
case LOOKUPSWITCH:
case IRETURN:
case NEWARRAY:
case ANEWARRAY:
expected = BasicValue.INT_VALUE;
break;
case FNEG:
case F2I:
case F2L:
case F2D:
case FRETURN:
expected = BasicValue.FLOAT_VALUE;
break;
case LNEG:
case L2I:
case L2F:
case L2D:
case LRETURN:
expected = BasicValue.LONG_VALUE;
break;
case DNEG:
case D2I:
case D2F:
case D2L:
case DRETURN:
expected = BasicValue.DOUBLE_VALUE;
break;
case GETFIELD:
expected = newValue(Type
.getObjectType(((FieldInsnNode) insn).owner));
break;
case CHECKCAST:
if (!value.isReference()) {
throw new AnalyzerException(insn, null, "an object reference",
value);
}
return super.unaryOperation(insn, value);
case ARRAYLENGTH:
if (!isArrayValue(value)) {
throw new AnalyzerException(insn, null, "an array reference",
value);
}
return super.unaryOperation(insn, value);
case ARETURN:
case ATHROW:
case INSTANCEOF:
case MONITORENTER:
case MONITOREXIT:
case IFNULL:
case IFNONNULL:
if (!value.isReference()) {
throw new AnalyzerException(insn, null, "an object reference",
value);
}
return super.unaryOperation(insn, value);
case PUTSTATIC:
expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
break;
default:
throw new Error("Internal error.");
}
if (!isSubTypeOf(value, expected)) {
throw new AnalyzerException(insn, null, expected, value);
}
return super.unaryOperation(insn, value);
}
@Override
public BasicValue binaryOperation(final AbstractInsnNode insn,
final BasicValue value1, final BasicValue value2)
throws AnalyzerException {
BasicValue expected1;
BasicValue expected2;
switch (insn.getOpcode()) {
case IALOAD:
expected1 = newValue(Type.getType("[I"));
expected2 = BasicValue.INT_VALUE;
break;
case BALOAD:
if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
expected1 = newValue(Type.getType("[Z"));
} else {
expected1 = newValue(Type.getType("[B"));
}
expected2 = BasicValue.INT_VALUE;
break;
case CALOAD:
expected1 = newValue(Type.getType("[C"));
expected2 = BasicValue.INT_VALUE;
break;
case SALOAD:
expected1 = newValue(Type.getType("[S"));
expected2 = BasicValue.INT_VALUE;
break;
case LALOAD:
expected1 = newValue(Type.getType("[J"));
expected2 = BasicValue.INT_VALUE;
break;
case FALOAD:
expected1 = newValue(Type.getType("[F"));
expected2 = BasicValue.INT_VALUE;
break;
case DALOAD:
expected1 = newValue(Type.getType("[D"));
expected2 = BasicValue.INT_VALUE;
break;
case AALOAD:
expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
expected2 = BasicValue.INT_VALUE;
break;
case IADD:
case ISUB:
case IMUL:
case IDIV:
case IREM:
case ISHL:
case ISHR:
case IUSHR:
case IAND:
case IOR:
case IXOR:
case IF_ICMPEQ:
case IF_ICMPNE:
case IF_ICMPLT:
case IF_ICMPGE:
case IF_ICMPGT:
case IF_ICMPLE:
expected1 = BasicValue.INT_VALUE;
expected2 = BasicValue.INT_VALUE;
break;
case FADD:
case FSUB:
case FMUL:
case FDIV:
case FREM:
case FCMPL:
case FCMPG:
expected1 = BasicValue.FLOAT_VALUE;
expected2 = BasicValue.FLOAT_VALUE;
break;
case LADD:
case LSUB:
case LMUL:
case LDIV:
case LREM:
case LAND:
case LOR:
case LXOR:
case LCMP:
expected1 = BasicValue.LONG_VALUE;
expected2 = BasicValue.LONG_VALUE;
break;
case LSHL:
case LSHR:
case LUSHR:
expected1 = BasicValue.LONG_VALUE;
expected2 = BasicValue.INT_VALUE;
break;
case DADD:
case DSUB:
case DMUL:
case DDIV:
case DREM:
case DCMPL:
case DCMPG:
expected1 = BasicValue.DOUBLE_VALUE;
expected2 = BasicValue.DOUBLE_VALUE;
break;
case IF_ACMPEQ:
case IF_ACMPNE:
expected1 = BasicValue.REFERENCE_VALUE;
expected2 = BasicValue.REFERENCE_VALUE;
break;
case PUTFIELD:
FieldInsnNode fin = (FieldInsnNode) insn;
expected1 = newValue(Type.getObjectType(fin.owner));
expected2 = newValue(Type.getType(fin.desc));
break;
default:
throw new Error("Internal error.");
}
if (!isSubTypeOf(value1, expected1)) {
throw new AnalyzerException(insn, "First argument", expected1,
value1);
} else if (!isSubTypeOf(value2, expected2)) {
throw new AnalyzerException(insn, "Second argument", expected2,
value2);
}
if (insn.getOpcode() == AALOAD) {
return getElementValue(value1);
} else {
return super.binaryOperation(insn, value1, value2);
}
}
@Override
public BasicValue ternaryOperation(final AbstractInsnNode insn,
final BasicValue value1, final BasicValue value2,
final BasicValue value3) throws AnalyzerException {
BasicValue expected1;
BasicValue expected3;
switch (insn.getOpcode()) {
case IASTORE:
expected1 = newValue(Type.getType("[I"));
expected3 = BasicValue.INT_VALUE;
break;
case BASTORE:
if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
expected1 = newValue(Type.getType("[Z"));
} else {
expected1 = newValue(Type.getType("[B"));
}
expected3 = BasicValue.INT_VALUE;
break;
case CASTORE:
expected1 = newValue(Type.getType("[C"));
expected3 = BasicValue.INT_VALUE;
break;
case SASTORE:
expected1 = newValue(Type.getType("[S"));
expected3 = BasicValue.INT_VALUE;
break;
case LASTORE:
expected1 = newValue(Type.getType("[J"));
expected3 = BasicValue.LONG_VALUE;
break;
case FASTORE:
expected1 = newValue(Type.getType("[F"));
expected3 = BasicValue.FLOAT_VALUE;
break;
case DASTORE:
expected1 = newValue(Type.getType("[D"));
expected3 = BasicValue.DOUBLE_VALUE;
break;
case AASTORE:
expected1 = value1;
expected3 = BasicValue.REFERENCE_VALUE;
break;
default:
throw new Error("Internal error.");
}
if (!isSubTypeOf(value1, expected1)) {
throw new AnalyzerException(insn, "First argument", "a "
+ expected1 + " array reference", value1);
} else if (!BasicValue.INT_VALUE.equals(value2)) {
throw new AnalyzerException(insn, "Second argument",
BasicValue.INT_VALUE, value2);
} else if (!isSubTypeOf(value3, expected3)) {
throw new AnalyzerException(insn, "Third argument", expected3,
value3);
}
return null;
}
@Override
public BasicValue naryOperation(final AbstractInsnNode insn,
final List<? extends BasicValue> values) throws AnalyzerException {
int opcode = insn.getOpcode();
if (opcode == MULTIANEWARRAY) {
for (int i = 0; i < values.size(); ++i) {
if (!BasicValue.INT_VALUE.equals(values.get(i))) {
throw new AnalyzerException(insn, null,
BasicValue.INT_VALUE, values.get(i));
}
}
} else {
int i = 0;
int j = 0;
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
if (!isSubTypeOf(values.get(i++), newValue(owner))) {
throw new AnalyzerException(insn, "Method owner",
newValue(owner), values.get(0));
}
}
String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
: ((MethodInsnNode) insn).desc;
Type[] args = Type.getArgumentTypes(desc);
while (i < values.size()) {
BasicValue expected = newValue(args[j++]);
BasicValue encountered = values.get(i++);
if (!isSubTypeOf(encountered, expected)) {
throw new AnalyzerException(insn, "Argument " + j,
expected, encountered);
}
}
}
return super.naryOperation(insn, values);
}
@Override
public void returnOperation(final AbstractInsnNode insn,
final BasicValue value, final BasicValue expected)
throws AnalyzerException {
if (!isSubTypeOf(value, expected)) {
throw new AnalyzerException(insn, "Incompatible return type",
expected, value);
}
}
protected boolean isArrayValue(final BasicValue value) {
return value.isReference();
}
protected BasicValue getElementValue(final BasicValue objectArrayValue)
throws AnalyzerException {
return BasicValue.REFERENCE_VALUE;
}
protected boolean isSubTypeOf(final BasicValue value,
final BasicValue expected) {
return value.equals(expected);
}
}
@@ -0,0 +1,730 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
/**
* A symbolic execution stack frame. A stack frame contains a set of local
* variable slots, and an operand stack. Warning: long and double values are
* represented by <i>two</i> slots in local variables, and by <i>one</i> slot in
* the operand stack.
*
* @param <V>
* type of the Value used for the analysis.
*
* @author Eric Bruneton
*/
public class Frame<V extends Value> {
/**
* The expected return type of the analyzed method, or <tt>null</tt> if the
* method returns void.
*/
private V returnValue;
/**
* The local variables and operand stack of this frame.
*/
private V[] values;
/**
* The number of local variables of this frame.
*/
private int locals;
/**
* The number of elements in the operand stack.
*/
private int top;
/**
* Constructs a new frame with the given size.
*
* @param nLocals
* the maximum number of local variables of the frame.
* @param nStack
* the maximum stack size of the frame.
*/
@SuppressWarnings("unchecked")
public Frame(final int nLocals, final int nStack) {
this.values = (V[]) new Value[nLocals + nStack];
this.locals = nLocals;
}
/**
* Constructs a new frame that is identical to the given frame.
*
* @param src
* a frame.
*/
public Frame(final Frame<? extends V> src) {
this(src.locals, src.values.length - src.locals);
init(src);
}
/**
* Copies the state of the given frame into this frame.
*
* @param src
* a frame.
* @return this frame.
*/
public Frame<V> init(final Frame<? extends V> src) {
returnValue = src.returnValue;
System.arraycopy(src.values, 0, values, 0, values.length);
top = src.top;
return this;
}
/**
* Sets the expected return type of the analyzed method.
*
* @param v
* the expected return type of the analyzed method, or
* <tt>null</tt> if the method returns void.
*/
public void setReturn(final V v) {
returnValue = v;
}
/**
* Returns the maximum number of local variables of this frame.
*
* @return the maximum number of local variables of this frame.
*/
public int getLocals() {
return locals;
}
/**
* Returns the value of the given local variable.
*
* @param i
* a local variable index.
* @return the value of the given local variable.
* @throws IndexOutOfBoundsException
* if the variable does not exist.
*/
public V getLocal(final int i) throws IndexOutOfBoundsException {
if (i >= locals) {
throw new IndexOutOfBoundsException(
"Trying to access an inexistant local variable");
}
return values[i];
}
/**
* Sets the value of the given local variable.
*
* @param i
* a local variable index.
* @param value
* the new value of this local variable.
* @throws IndexOutOfBoundsException
* if the variable does not exist.
*/
public void setLocal(final int i, final V value)
throws IndexOutOfBoundsException {
if (i >= locals) {
throw new IndexOutOfBoundsException(
"Trying to access an inexistant local variable " + i);
}
values[i] = value;
}
/**
* Returns the number of values in the operand stack of this frame. Long and
* double values are treated as single values.
*
* @return the number of values in the operand stack of this frame.
*/
public int getStackSize() {
return top;
}
/**
* Returns the value of the given operand stack slot.
*
* @param i
* the index of an operand stack slot.
* @return the value of the given operand stack slot.
* @throws IndexOutOfBoundsException
* if the operand stack slot does not exist.
*/
public V getStack(final int i) throws IndexOutOfBoundsException {
return values[i + locals];
}
/**
* Clears the operand stack of this frame.
*/
public void clearStack() {
top = 0;
}
/**
* Pops a value from the operand stack of this frame.
*
* @return the value that has been popped from the stack.
* @throws IndexOutOfBoundsException
* if the operand stack is empty.
*/
public V pop() throws IndexOutOfBoundsException {
if (top == 0) {
throw new IndexOutOfBoundsException(
"Cannot pop operand off an empty stack.");
}
return values[--top + locals];
}
/**
* Pushes a value into the operand stack of this frame.
*
* @param value
* the value that must be pushed into the stack.
* @throws IndexOutOfBoundsException
* if the operand stack is full.
*/
public void push(final V value) throws IndexOutOfBoundsException {
if (top + locals >= values.length) {
throw new IndexOutOfBoundsException(
"Insufficient maximum stack size.");
}
values[top++ + locals] = value;
}
public void execute(final AbstractInsnNode insn,
final Interpreter<V> interpreter) throws AnalyzerException {
V value1, value2, value3, value4;
List<V> values;
int var;
switch (insn.getOpcode()) {
case Opcodes.NOP:
break;
case Opcodes.ACONST_NULL:
case Opcodes.ICONST_M1:
case Opcodes.ICONST_0:
case Opcodes.ICONST_1:
case Opcodes.ICONST_2:
case Opcodes.ICONST_3:
case Opcodes.ICONST_4:
case Opcodes.ICONST_5:
case Opcodes.LCONST_0:
case Opcodes.LCONST_1:
case Opcodes.FCONST_0:
case Opcodes.FCONST_1:
case Opcodes.FCONST_2:
case Opcodes.DCONST_0:
case Opcodes.DCONST_1:
case Opcodes.BIPUSH:
case Opcodes.SIPUSH:
case Opcodes.LDC:
push(interpreter.newOperation(insn));
break;
case Opcodes.ILOAD:
case Opcodes.LLOAD:
case Opcodes.FLOAD:
case Opcodes.DLOAD:
case Opcodes.ALOAD:
push(interpreter.copyOperation(insn,
getLocal(((VarInsnNode) insn).var)));
break;
case Opcodes.IALOAD:
case Opcodes.LALOAD:
case Opcodes.FALOAD:
case Opcodes.DALOAD:
case Opcodes.AALOAD:
case Opcodes.BALOAD:
case Opcodes.CALOAD:
case Opcodes.SALOAD:
value2 = pop();
value1 = pop();
push(interpreter.binaryOperation(insn, value1, value2));
break;
case Opcodes.ISTORE:
case Opcodes.LSTORE:
case Opcodes.FSTORE:
case Opcodes.DSTORE:
case Opcodes.ASTORE:
value1 = interpreter.copyOperation(insn, pop());
var = ((VarInsnNode) insn).var;
setLocal(var, value1);
if (value1.getSize() == 2) {
setLocal(var + 1, interpreter.newValue(null));
}
if (var > 0) {
Value local = getLocal(var - 1);
if (local != null && local.getSize() == 2) {
setLocal(var - 1, interpreter.newValue(null));
}
}
break;
case Opcodes.IASTORE:
case Opcodes.LASTORE:
case Opcodes.FASTORE:
case Opcodes.DASTORE:
case Opcodes.AASTORE:
case Opcodes.BASTORE:
case Opcodes.CASTORE:
case Opcodes.SASTORE:
value3 = pop();
value2 = pop();
value1 = pop();
interpreter.ternaryOperation(insn, value1, value2, value3);
break;
case Opcodes.POP:
if (pop().getSize() == 2) {
throw new AnalyzerException(insn, "Illegal use of POP");
}
break;
case Opcodes.POP2:
if (pop().getSize() == 1) {
if (pop().getSize() != 1) {
throw new AnalyzerException(insn, "Illegal use of POP2");
}
}
break;
case Opcodes.DUP:
value1 = pop();
if (value1.getSize() != 1) {
throw new AnalyzerException(insn, "Illegal use of DUP");
}
push(value1);
push(interpreter.copyOperation(insn, value1));
break;
case Opcodes.DUP_X1:
value1 = pop();
value2 = pop();
if (value1.getSize() != 1 || value2.getSize() != 1) {
throw new AnalyzerException(insn, "Illegal use of DUP_X1");
}
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
case Opcodes.DUP_X2:
value1 = pop();
if (value1.getSize() == 1) {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break;
}
} else {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
}
}
throw new AnalyzerException(insn, "Illegal use of DUP_X2");
case Opcodes.DUP2:
value1 = pop();
if (value1.getSize() == 1) {
value2 = pop();
if (value2.getSize() == 1) {
push(value2);
push(value1);
push(interpreter.copyOperation(insn, value2));
push(interpreter.copyOperation(insn, value1));
break;
}
} else {
push(value1);
push(interpreter.copyOperation(insn, value1));
break;
}
throw new AnalyzerException(insn, "Illegal use of DUP2");
case Opcodes.DUP2_X1:
value1 = pop();
if (value1.getSize() == 1) {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value2));
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break;
}
}
} else {
value2 = pop();
if (value2.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
}
}
throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
case Opcodes.DUP2_X2:
value1 = pop();
if (value1.getSize() == 1) {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
value4 = pop();
if (value4.getSize() == 1) {
push(interpreter.copyOperation(insn, value2));
push(interpreter.copyOperation(insn, value1));
push(value4);
push(value3);
push(value2);
push(value1);
break;
}
} else {
push(interpreter.copyOperation(insn, value2));
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break;
}
}
} else {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break;
}
} else {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
}
}
throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
case Opcodes.SWAP:
value2 = pop();
value1 = pop();
if (value1.getSize() != 1 || value2.getSize() != 1) {
throw new AnalyzerException(insn, "Illegal use of SWAP");
}
push(interpreter.copyOperation(insn, value2));
push(interpreter.copyOperation(insn, value1));
break;
case Opcodes.IADD:
case Opcodes.LADD:
case Opcodes.FADD:
case Opcodes.DADD:
case Opcodes.ISUB:
case Opcodes.LSUB:
case Opcodes.FSUB:
case Opcodes.DSUB:
case Opcodes.IMUL:
case Opcodes.LMUL:
case Opcodes.FMUL:
case Opcodes.DMUL:
case Opcodes.IDIV:
case Opcodes.LDIV:
case Opcodes.FDIV:
case Opcodes.DDIV:
case Opcodes.IREM:
case Opcodes.LREM:
case Opcodes.FREM:
case Opcodes.DREM:
value2 = pop();
value1 = pop();
push(interpreter.binaryOperation(insn, value1, value2));
break;
case Opcodes.INEG:
case Opcodes.LNEG:
case Opcodes.FNEG:
case Opcodes.DNEG:
push(interpreter.unaryOperation(insn, pop()));
break;
case Opcodes.ISHL:
case Opcodes.LSHL:
case Opcodes.ISHR:
case Opcodes.LSHR:
case Opcodes.IUSHR:
case Opcodes.LUSHR:
case Opcodes.IAND:
case Opcodes.LAND:
case Opcodes.IOR:
case Opcodes.LOR:
case Opcodes.IXOR:
case Opcodes.LXOR:
value2 = pop();
value1 = pop();
push(interpreter.binaryOperation(insn, value1, value2));
break;
case Opcodes.IINC:
var = ((IincInsnNode) insn).var;
setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
break;
case Opcodes.I2L:
case Opcodes.I2F:
case Opcodes.I2D:
case Opcodes.L2I:
case Opcodes.L2F:
case Opcodes.L2D:
case Opcodes.F2I:
case Opcodes.F2L:
case Opcodes.F2D:
case Opcodes.D2I:
case Opcodes.D2L:
case Opcodes.D2F:
case Opcodes.I2B:
case Opcodes.I2C:
case Opcodes.I2S:
push(interpreter.unaryOperation(insn, pop()));
break;
case Opcodes.LCMP:
case Opcodes.FCMPL:
case Opcodes.FCMPG:
case Opcodes.DCMPL:
case Opcodes.DCMPG:
value2 = pop();
value1 = pop();
push(interpreter.binaryOperation(insn, value1, value2));
break;
case Opcodes.IFEQ:
case Opcodes.IFNE:
case Opcodes.IFLT:
case Opcodes.IFGE:
case Opcodes.IFGT:
case Opcodes.IFLE:
interpreter.unaryOperation(insn, pop());
break;
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPNE:
case Opcodes.IF_ICMPLT:
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ACMPEQ:
case Opcodes.IF_ACMPNE:
value2 = pop();
value1 = pop();
interpreter.binaryOperation(insn, value1, value2);
break;
case Opcodes.GOTO:
break;
case Opcodes.JSR:
push(interpreter.newOperation(insn));
break;
case Opcodes.RET:
break;
case Opcodes.TABLESWITCH:
case Opcodes.LOOKUPSWITCH:
interpreter.unaryOperation(insn, pop());
break;
case Opcodes.IRETURN:
case Opcodes.LRETURN:
case Opcodes.FRETURN:
case Opcodes.DRETURN:
case Opcodes.ARETURN:
value1 = pop();
interpreter.unaryOperation(insn, value1);
interpreter.returnOperation(insn, value1, returnValue);
break;
case Opcodes.RETURN:
if (returnValue != null) {
throw new AnalyzerException(insn, "Incompatible return type");
}
break;
case Opcodes.GETSTATIC:
push(interpreter.newOperation(insn));
break;
case Opcodes.PUTSTATIC:
interpreter.unaryOperation(insn, pop());
break;
case Opcodes.GETFIELD:
push(interpreter.unaryOperation(insn, pop()));
break;
case Opcodes.PUTFIELD:
value2 = pop();
value1 = pop();
interpreter.binaryOperation(insn, value1, value2);
break;
case Opcodes.INVOKEVIRTUAL:
case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEINTERFACE: {
values = new ArrayList<V>();
String desc = ((MethodInsnNode) insn).desc;
for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
values.add(0, pop());
}
if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
values.add(0, pop());
}
if (Type.getReturnType(desc) == Type.VOID_TYPE) {
interpreter.naryOperation(insn, values);
} else {
push(interpreter.naryOperation(insn, values));
}
break;
}
case Opcodes.INVOKEDYNAMIC: {
values = new ArrayList<V>();
String desc = ((InvokeDynamicInsnNode) insn).desc;
for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
values.add(0, pop());
}
if (Type.getReturnType(desc) == Type.VOID_TYPE) {
interpreter.naryOperation(insn, values);
} else {
push(interpreter.naryOperation(insn, values));
}
break;
}
case Opcodes.NEW:
push(interpreter.newOperation(insn));
break;
case Opcodes.NEWARRAY:
case Opcodes.ANEWARRAY:
case Opcodes.ARRAYLENGTH:
push(interpreter.unaryOperation(insn, pop()));
break;
case Opcodes.ATHROW:
interpreter.unaryOperation(insn, pop());
break;
case Opcodes.CHECKCAST:
case Opcodes.INSTANCEOF:
push(interpreter.unaryOperation(insn, pop()));
break;
case Opcodes.MONITORENTER:
case Opcodes.MONITOREXIT:
interpreter.unaryOperation(insn, pop());
break;
case Opcodes.MULTIANEWARRAY:
values = new ArrayList<V>();
for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
values.add(0, pop());
}
push(interpreter.naryOperation(insn, values));
break;
case Opcodes.IFNULL:
case Opcodes.IFNONNULL:
interpreter.unaryOperation(insn, pop());
break;
default:
throw new RuntimeException("Illegal opcode " + insn.getOpcode());
}
}
/**
* Merges this frame with the given frame.
*
* @param frame
* a frame.
* @param interpreter
* the interpreter used to merge values.
* @return <tt>true</tt> if this frame has been changed as a result of the
* merge operation, or <tt>false</tt> otherwise.
* @throws AnalyzerException
* if the frames have incompatible sizes.
*/
public boolean merge(final Frame<? extends V> frame,
final Interpreter<V> interpreter) throws AnalyzerException {
if (top != frame.top) {
throw new AnalyzerException(null, "Incompatible stack heights");
}
boolean changes = false;
for (int i = 0; i < locals + top; ++i) {
V v = interpreter.merge(values[i], frame.values[i]);
if (!v.equals(values[i])) {
values[i] = v;
changes = true;
}
}
return changes;
}
/**
* Merges this frame with the given frame (case of a RET instruction).
*
* @param frame
* a frame
* @param access
* the local variables that have been accessed by the subroutine
* to which the RET instruction corresponds.
* @return <tt>true</tt> if this frame has been changed as a result of the
* merge operation, or <tt>false</tt> otherwise.
*/
public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
boolean changes = false;
for (int i = 0; i < locals; ++i) {
if (!access[i] && !values[i].equals(frame.values[i])) {
values[i] = frame.values[i];
changes = true;
}
}
return changes;
}
/**
* Returns a string representation of this frame.
*
* @return a string representation of this frame.
*/
@Override
public String toString() {
StringBuffer b = new StringBuffer();
for (int i = 0; i < getLocals(); ++i) {
b.append(getLocal(i));
}
b.append(' ');
for (int i = 0; i < getStackSize(); ++i) {
b.append(getStack(i).toString());
}
return b.toString();
}
}
@@ -0,0 +1,226 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.List;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
/**
* A semantic bytecode interpreter. More precisely, this interpreter only
* manages the computation of values from other values: it does not manage the
* transfer of values to or from the stack, and to or from the local variables.
* This separation allows a generic bytecode {@link Analyzer} to work with
* various semantic interpreters, without needing to duplicate the code to
* simulate the transfer of values.
*
* @param <V>
* type of the Value used for the analysis.
*
* @author Eric Bruneton
*/
public abstract class Interpreter<V extends Value> {
protected final int api;
protected Interpreter(final int api) {
this.api = api;
}
/**
* Creates a new value that represents the given type.
*
* Called for method parameters (including <code>this</code>), exception
* handler variable and with <code>null</code> type for variables reserved
* by long and double types.
*
* @param type
* a primitive or reference type, or <tt>null</tt> to represent
* an uninitialized value.
* @return a value that represents the given type. The size of the returned
* value must be equal to the size of the given type.
*/
public abstract V newValue(Type type);
/**
* Interprets a bytecode instruction without arguments. This method is
* called for the following opcodes:
*
* 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, JSR, GETSTATIC, NEW
*
* @param insn
* the bytecode instruction to be interpreted.
* @return the result of the interpretation of the given instruction.
* @throws AnalyzerException
* if an error occured during the interpretation.
*/
public abstract V newOperation(AbstractInsnNode insn)
throws AnalyzerException;
/**
* Interprets a bytecode instruction that moves a value on the stack or to
* or from local variables. This method is called for the following opcodes:
*
* ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
* ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
*
* @param insn
* the bytecode instruction to be interpreted.
* @param value
* the value that must be moved by the instruction.
* @return the result of the interpretation of the given instruction. The
* returned value must be <tt>equal</tt> to the given value.
* @throws AnalyzerException
* if an error occured during the interpretation.
*/
public abstract V copyOperation(AbstractInsnNode insn, V value)
throws AnalyzerException;
/**
* Interprets a bytecode instruction with a single argument. This method is
* called for the following opcodes:
*
* INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L,
* F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
* TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
* PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST,
* INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
*
* @param insn
* the bytecode instruction to be interpreted.
* @param value
* the argument of the instruction to be interpreted.
* @return the result of the interpretation of the given instruction.
* @throws AnalyzerException
* if an error occured during the interpretation.
*/
public abstract V unaryOperation(AbstractInsnNode insn, V value)
throws AnalyzerException;
/**
* Interprets a bytecode instruction with two arguments. This method is
* called for the following opcodes:
*
* IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD,
* LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV,
* LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR,
* LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL,
* DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, PUTFIELD
*
* @param insn
* the bytecode instruction to be interpreted.
* @param value1
* the first argument of the instruction to be interpreted.
* @param value2
* the second argument of the instruction to be interpreted.
* @return the result of the interpretation of the given instruction.
* @throws AnalyzerException
* if an error occured during the interpretation.
*/
public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2)
throws AnalyzerException;
/**
* Interprets a bytecode instruction with three arguments. This method is
* called for the following opcodes:
*
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
*
* @param insn
* the bytecode instruction to be interpreted.
* @param value1
* the first argument of the instruction to be interpreted.
* @param value2
* the second argument of the instruction to be interpreted.
* @param value3
* the third argument of the instruction to be interpreted.
* @return the result of the interpretation of the given instruction.
* @throws AnalyzerException
* if an error occured during the interpretation.
*/
public abstract V ternaryOperation(AbstractInsnNode insn, V value1,
V value2, V value3) throws AnalyzerException;
/**
* Interprets a bytecode instruction with a variable number of arguments.
* This method is called for the following opcodes:
*
* INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE,
* MULTIANEWARRAY and INVOKEDYNAMIC
*
* @param insn
* the bytecode instruction to be interpreted.
* @param values
* the arguments of the instruction to be interpreted.
* @return the result of the interpretation of the given instruction.
* @throws AnalyzerException
* if an error occured during the interpretation.
*/
public abstract V naryOperation(AbstractInsnNode insn,
List<? extends V> values) throws AnalyzerException;
/**
* Interprets a bytecode return instruction. This method is called for the
* following opcodes:
*
* IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
*
* @param insn
* the bytecode instruction to be interpreted.
* @param value
* the argument of the instruction to be interpreted.
* @param expected
* the expected return type of the analyzed method.
* @throws AnalyzerException
* if an error occured during the interpretation.
*/
public abstract void returnOperation(AbstractInsnNode insn, V value,
V expected) throws AnalyzerException;
/**
* Merges two values. The merge operation must return a value that
* represents both values (for instance, if the two values are two types,
* the merged value must be a common super type of the two types. If the two
* values are integer intervals, the merged value must be an interval that
* contains the previous ones. Likewise for other types of values).
*
* @param v
* a value.
* @param w
* another value.
* @return the merged value. If the merged value is equal to <tt>v</tt>,
* this method <i>must</i> return <tt>v</tt>.
*/
public abstract V merge(V v, V w);
}
@@ -0,0 +1,320 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.List;
import org.objectweb.asm.Type;
/**
* An extended {@link BasicVerifier} that performs more precise verifications.
* This verifier computes exact class types, instead of using a single "object
* reference" type (as done in the {@link BasicVerifier}).
*
* @author Eric Bruneton
* @author Bing Ran
*/
public class SimpleVerifier extends BasicVerifier {
/**
* The class that is verified.
*/
private final Type currentClass;
/**
* The super class of the class that is verified.
*/
private final Type currentSuperClass;
/**
* The interfaces implemented by the class that is verified.
*/
private final List<Type> currentClassInterfaces;
/**
* If the class that is verified is an interface.
*/
private final boolean isInterface;
/**
* The loader to use for referenced classes.
*/
private ClassLoader loader = getClass().getClassLoader();
/**
* Constructs a new {@link SimpleVerifier}.
*/
public SimpleVerifier() {
this(null, null, false);
}
/**
* Constructs a new {@link SimpleVerifier} to verify a specific class. This
* class will not be loaded into the JVM since it may be incorrect.
*
* @param currentClass
* the class that is verified.
* @param currentSuperClass
* the super class of the class that is verified.
* @param isInterface
* if the class that is verified is an interface.
*/
public SimpleVerifier(final Type currentClass,
final Type currentSuperClass, final boolean isInterface) {
this(currentClass, currentSuperClass, null, isInterface);
}
/**
* Constructs a new {@link SimpleVerifier} to verify a specific class. This
* class will not be loaded into the JVM since it may be incorrect.
*
* @param currentClass
* the class that is verified.
* @param currentSuperClass
* the super class of the class that is verified.
* @param currentClassInterfaces
* the interfaces implemented by the class that is verified.
* @param isInterface
* if the class that is verified is an interface.
*/
public SimpleVerifier(final Type currentClass,
final Type currentSuperClass,
final List<Type> currentClassInterfaces, final boolean isInterface) {
this(ASM4, currentClass, currentSuperClass, currentClassInterfaces,
isInterface);
}
protected SimpleVerifier(final int api, final Type currentClass,
final Type currentSuperClass,
final List<Type> currentClassInterfaces, final boolean isInterface) {
super(api);
this.currentClass = currentClass;
this.currentSuperClass = currentSuperClass;
this.currentClassInterfaces = currentClassInterfaces;
this.isInterface = isInterface;
}
/**
* Set the <code>ClassLoader</code> which will be used to load referenced
* classes. This is useful if you are verifying multiple interdependent
* classes.
*
* @param loader
* a <code>ClassLoader</code> to use
*/
public void setClassLoader(final ClassLoader loader) {
this.loader = loader;
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
boolean isArray = type.getSort() == Type.ARRAY;
if (isArray) {
switch (type.getElementType().getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
return new BasicValue(type);
}
}
BasicValue v = super.newValue(type);
if (BasicValue.REFERENCE_VALUE.equals(v)) {
if (isArray) {
v = newValue(type.getElementType());
String desc = v.getType().getDescriptor();
for (int i = 0; i < type.getDimensions(); ++i) {
desc = '[' + desc;
}
v = new BasicValue(Type.getType(desc));
} else {
v = new BasicValue(type);
}
}
return v;
}
@Override
protected boolean isArrayValue(final BasicValue value) {
Type t = value.getType();
return t != null
&& ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY);
}
@Override
protected BasicValue getElementValue(final BasicValue objectArrayValue)
throws AnalyzerException {
Type arrayType = objectArrayValue.getType();
if (arrayType != null) {
if (arrayType.getSort() == Type.ARRAY) {
return newValue(Type.getType(arrayType.getDescriptor()
.substring(1)));
} else if ("Lnull;".equals(arrayType.getDescriptor())) {
return objectArrayValue;
}
}
throw new Error("Internal error");
}
@Override
protected boolean isSubTypeOf(final BasicValue value,
final BasicValue expected) {
Type expectedType = expected.getType();
Type type = value.getType();
switch (expectedType.getSort()) {
case Type.INT:
case Type.FLOAT:
case Type.LONG:
case Type.DOUBLE:
return type.equals(expectedType);
case Type.ARRAY:
case Type.OBJECT:
if ("Lnull;".equals(type.getDescriptor())) {
return true;
} else if (type.getSort() == Type.OBJECT
|| type.getSort() == Type.ARRAY) {
return isAssignableFrom(expectedType, type);
} else {
return false;
}
default:
throw new Error("Internal error");
}
}
@Override
public BasicValue merge(final BasicValue v, final BasicValue w) {
if (!v.equals(w)) {
Type t = v.getType();
Type u = w.getType();
if (t != null
&& (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
if (u != null
&& (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
if ("Lnull;".equals(t.getDescriptor())) {
return w;
}
if ("Lnull;".equals(u.getDescriptor())) {
return v;
}
if (isAssignableFrom(t, u)) {
return v;
}
if (isAssignableFrom(u, t)) {
return w;
}
// TODO case of array classes of the same dimension
// TODO should we look also for a common super interface?
// problem: there may be several possible common super
// interfaces
do {
if (t == null || isInterface(t)) {
return BasicValue.REFERENCE_VALUE;
}
t = getSuperClass(t);
if (isAssignableFrom(t, u)) {
return newValue(t);
}
} while (true);
}
}
return BasicValue.UNINITIALIZED_VALUE;
}
return v;
}
protected boolean isInterface(final Type t) {
if (currentClass != null && t.equals(currentClass)) {
return isInterface;
}
return getClass(t).isInterface();
}
protected Type getSuperClass(final Type t) {
if (currentClass != null && t.equals(currentClass)) {
return currentSuperClass;
}
Class<?> c = getClass(t).getSuperclass();
return c == null ? null : Type.getType(c);
}
protected boolean isAssignableFrom(final Type t, final Type u) {
if (t.equals(u)) {
return true;
}
if (currentClass != null && t.equals(currentClass)) {
if (getSuperClass(u) == null) {
return false;
} else {
if (isInterface) {
return u.getSort() == Type.OBJECT
|| u.getSort() == Type.ARRAY;
}
return isAssignableFrom(t, getSuperClass(u));
}
}
if (currentClass != null && u.equals(currentClass)) {
if (isAssignableFrom(t, currentSuperClass)) {
return true;
}
if (currentClassInterfaces != null) {
for (int i = 0; i < currentClassInterfaces.size(); ++i) {
Type v = currentClassInterfaces.get(i);
if (isAssignableFrom(t, v)) {
return true;
}
}
}
return false;
}
Class<?> tc = getClass(t);
if (tc.isInterface()) {
tc = Object.class;
}
return tc.isAssignableFrom(getClass(u));
}
protected Class<?> getClass(final Type t) {
try {
if (t.getSort() == Type.ARRAY) {
return Class.forName(t.getDescriptor().replace('/', '.'),
false, loader);
}
return Class.forName(t.getClassName(), false, loader);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e.toString());
}
}
}
@@ -0,0 +1,134 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.AbstractSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* A set of at most two elements.
*
* @author Eric Bruneton
*/
class SmallSet<E> extends AbstractSet<E> implements Iterator<E> {
// if e1 is null, e2 must be null; otherwise e2 must be different from e1
E e1, e2;
static final <T> Set<T> emptySet() {
return new SmallSet<T>(null, null);
}
SmallSet(final E e1, final E e2) {
this.e1 = e1;
this.e2 = e2;
}
// -------------------------------------------------------------------------
// Implementation of inherited abstract methods
// -------------------------------------------------------------------------
@Override
public Iterator<E> iterator() {
return new SmallSet<E>(e1, e2);
}
@Override
public int size() {
return e1 == null ? 0 : (e2 == null ? 1 : 2);
}
// -------------------------------------------------------------------------
// Implementation of the Iterator interface
// -------------------------------------------------------------------------
public boolean hasNext() {
return e1 != null;
}
public E next() {
if (e1 == null) {
throw new NoSuchElementException();
}
E e = e1;
e1 = e2;
e2 = null;
return e;
}
public void remove() {
}
// -------------------------------------------------------------------------
// Utility methods
// -------------------------------------------------------------------------
Set<E> union(final SmallSet<E> s) {
if ((s.e1 == e1 && s.e2 == e2) || (s.e1 == e2 && s.e2 == e1)) {
return this; // if the two sets are equal, return this
}
if (s.e1 == null) {
return this; // if s is empty, return this
}
if (e1 == null) {
return s; // if this is empty, return s
}
if (s.e2 == null) { // s contains exactly one element
if (e2 == null) {
return new SmallSet<E>(e1, s.e1); // necessarily e1 != s.e1
} else if (s.e1 == e1 || s.e1 == e2) { // s is included in this
return this;
}
}
if (e2 == null) { // this contains exactly one element
// if (s.e2 == null) { // cannot happen
// return new SmallSet(e1, s.e1); // necessarily e1 != s.e1
// } else
if (e1 == s.e1 || e1 == s.e2) { // this in included in s
return s;
}
}
// here we know that there are at least 3 distinct elements
HashSet<E> r = new HashSet<E>(4);
r.add(e1);
if (e2 != null) {
r.add(e2);
}
r.add(s.e1);
if (s.e2 != null) {
r.add(s.e2);
}
return r;
}
}
@@ -0,0 +1,198 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
/**
* An {@link Interpreter} for {@link SourceValue} values.
*
* @author Eric Bruneton
*/
public class SourceInterpreter extends Interpreter<SourceValue> implements
Opcodes {
public SourceInterpreter() {
super(ASM4);
}
protected SourceInterpreter(final int api) {
super(api);
}
@Override
public SourceValue newValue(final Type type) {
if (type == Type.VOID_TYPE) {
return null;
}
return new SourceValue(type == null ? 1 : type.getSize());
}
@Override
public SourceValue newOperation(final AbstractInsnNode insn) {
int size;
switch (insn.getOpcode()) {
case LCONST_0:
case LCONST_1:
case DCONST_0:
case DCONST_1:
size = 2;
break;
case LDC:
Object cst = ((LdcInsnNode) insn).cst;
size = cst instanceof Long || cst instanceof Double ? 2 : 1;
break;
case GETSTATIC:
size = Type.getType(((FieldInsnNode) insn).desc).getSize();
break;
default:
size = 1;
}
return new SourceValue(size, insn);
}
@Override
public SourceValue copyOperation(final AbstractInsnNode insn,
final SourceValue value) {
return new SourceValue(value.getSize(), insn);
}
@Override
public SourceValue unaryOperation(final AbstractInsnNode insn,
final SourceValue value) {
int size;
switch (insn.getOpcode()) {
case LNEG:
case DNEG:
case I2L:
case I2D:
case L2D:
case F2L:
case F2D:
case D2L:
size = 2;
break;
case GETFIELD:
size = Type.getType(((FieldInsnNode) insn).desc).getSize();
break;
default:
size = 1;
}
return new SourceValue(size, insn);
}
@Override
public SourceValue binaryOperation(final AbstractInsnNode insn,
final SourceValue value1, final SourceValue value2) {
int size;
switch (insn.getOpcode()) {
case LALOAD:
case DALOAD:
case LADD:
case DADD:
case LSUB:
case DSUB:
case LMUL:
case DMUL:
case LDIV:
case DDIV:
case LREM:
case DREM:
case LSHL:
case LSHR:
case LUSHR:
case LAND:
case LOR:
case LXOR:
size = 2;
break;
default:
size = 1;
}
return new SourceValue(size, insn);
}
@Override
public SourceValue ternaryOperation(final AbstractInsnNode insn,
final SourceValue value1, final SourceValue value2,
final SourceValue value3) {
return new SourceValue(1, insn);
}
@Override
public SourceValue naryOperation(final AbstractInsnNode insn,
final List<? extends SourceValue> values) {
int size;
int opcode = insn.getOpcode();
if (opcode == MULTIANEWARRAY) {
size = 1;
} else {
String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
: ((MethodInsnNode) insn).desc;
size = Type.getReturnType(desc).getSize();
}
return new SourceValue(size, insn);
}
@Override
public void returnOperation(final AbstractInsnNode insn,
final SourceValue value, final SourceValue expected) {
}
@Override
public SourceValue merge(final SourceValue d, final SourceValue w) {
if (d.insns instanceof SmallSet && w.insns instanceof SmallSet) {
Set<AbstractInsnNode> s = ((SmallSet<AbstractInsnNode>) d.insns)
.union((SmallSet<AbstractInsnNode>) w.insns);
if (s == d.insns && d.size == w.size) {
return d;
} else {
return new SourceValue(Math.min(d.size, w.size), s);
}
}
if (d.size != w.size || !d.insns.containsAll(w.insns)) {
HashSet<AbstractInsnNode> s = new HashSet<AbstractInsnNode>();
s.addAll(d.insns);
s.addAll(w.insns);
return new SourceValue(Math.min(d.size, w.size), s);
}
return d;
}
}
@@ -0,0 +1,97 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.Set;
import org.objectweb.asm.tree.AbstractInsnNode;
/**
* A {@link Value} that is represented by its type in a two types type system.
* This type system distinguishes the ONEWORD and TWOWORDS types.
*
* @author Eric Bruneton
*/
public class SourceValue implements Value {
/**
* The size of this value.
*/
public final int size;
/**
* The instructions that can produce this value. For example, for the Java
* code below, the instructions that can produce the value of <tt>i</tt> at
* line 5 are the txo ISTORE instructions at line 1 and 3:
*
* <pre>
* 1: i = 0;
* 2: if (...) {
* 3: i = 1;
* 4: }
* 5: return i;
* </pre>
*
* This field is a set of {@link AbstractInsnNode} objects.
*/
public final Set<AbstractInsnNode> insns;
public SourceValue(final int size) {
this(size, SmallSet.<AbstractInsnNode> emptySet());
}
public SourceValue(final int size, final AbstractInsnNode insn) {
this.size = size;
this.insns = new SmallSet<AbstractInsnNode>(insn, null);
}
public SourceValue(final int size, final Set<AbstractInsnNode> insns) {
this.size = size;
this.insns = insns;
}
public int getSize() {
return size;
}
@Override
public boolean equals(final Object value) {
if (!(value instanceof SourceValue)) {
return false;
}
SourceValue v = (SourceValue) value;
return size == v.size && insns.equals(v.insns);
}
@Override
public int hashCode() {
return insns.hashCode();
}
}
@@ -0,0 +1,90 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
/**
* A method subroutine (corresponds to a JSR instruction).
*
* @author Eric Bruneton
*/
class Subroutine {
LabelNode start;
boolean[] access;
List<JumpInsnNode> callers;
private Subroutine() {
}
Subroutine(final LabelNode start, final int maxLocals,
final JumpInsnNode caller) {
this.start = start;
this.access = new boolean[maxLocals];
this.callers = new ArrayList<JumpInsnNode>();
callers.add(caller);
}
public Subroutine copy() {
Subroutine result = new Subroutine();
result.start = start;
result.access = new boolean[access.length];
System.arraycopy(access, 0, result.access, 0, access.length);
result.callers = new ArrayList<JumpInsnNode>(callers);
return result;
}
public boolean merge(final Subroutine subroutine) throws AnalyzerException {
boolean changes = false;
for (int i = 0; i < access.length; ++i) {
if (subroutine.access[i] && !access[i]) {
access[i] = true;
changes = true;
}
}
if (subroutine.start == start) {
for (int i = 0; i < subroutine.callers.size(); ++i) {
JumpInsnNode caller = subroutine.callers.get(i);
if (!callers.contains(caller)) {
callers.add(caller);
changes = true;
}
}
}
return changes;
}
}
@@ -0,0 +1,45 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.tree.analysis;
/**
* An immutable symbolic value for semantic interpretation of bytecode.
*
* @author Eric Bruneton
*/
public interface Value {
/**
* Returns the size of this value in words.
*
* @return either 1 or 2.
*/
int getSize();
}
@@ -0,0 +1,67 @@
<html>
<!--
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.
-->
<body>
<p>
Provides a framework for static code analysis based on the asm.tree package.
</p>
<p>
Basic usage:
</p>
<pre>
ClassReader cr = new ClassReader(bytecode);
ClassNode cn = new ClassNode();
cr.accept(cn, ClassReader.SKIP_DEBUG);
List methods = cn.methods;
for (int i = 0; i < methods.size(); ++i) {
MethodNode method = (MethodNode) methods.get(i);
if (method.instructions.size() > 0) {
Analyzer a = new Analyzer(new BasicInterpreter());
a.analyze(cn.name, method);
Frame[] frames = a.getFrames();
// Elements of the frames arrray now contains info for each instruction
// from the analyzed method. BasicInterpreter creates BasicValue, that
// is using simplified type system that distinguishes the UNINITIALZED,
// INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
...
}
}
</pre>
<p>
@since ASM 1.4.3
</p>
</body>
</html>
@@ -0,0 +1,192 @@
<html>
<!--
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 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.
-->
<body>
<p>
Provides an ASM visitor that constructs a tree representation of the
classes it visits. This class adapter can be useful to implement "complex"
class manipulation operations, i.e., operations that would be very hard to
implement without using a tree representation (such as optimizing the number
of local variables used by a method).
</p>
<p>
However, this class adapter has a cost: it makes ASM bigger and slower. Indeed
it requires more than twenty new classes, and multiplies the time needed to
transform a class by almost two (it is almost two times faster to read, "modify"
and write a class with a ClassVisitor than with a ClassNode). This is why
this package is bundled in an optional <tt>asm-tree.jar</tt> library that
is separated from (but requires) the <tt>asm.jar</tt> library, which contains
the core ASM framework. This is also why <i><font color="red">it is recommended
not to use this class adapter when it is possible</font></i>.
</p>
<p>
The root class is the ClassNode, that can be created from existing bytecode. For example:
</p>
<pre>
ClassReader cr = new ClassReader(source);
ClassNode cn = new ClassNode();
cr.accept(cn, true);
</pre>
<p>
Now the content of ClassNode can be modified and then
serialized back into bytecode:
</p>
<pre>
ClassWriter cw = new ClassWriter(true);
cn.accept(cw);
</pre>
<p>
Using a simple ClassVisitor it is possible to create MethodNode instances per-method.
In this example MethodNode is acting as a buffer that is flushed out at visitEnd() call:
</p>
<pre>
ClassReader cr = new ClassReader(source);
ClassWriter cw = new ClassWriter();
ClassVisitor cv = new ClassVisitor(cw) {
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
MethodNode mn = new MethodNode(access, name, desc, signature, exceptions) {
public void visitEnd() {
// transform or analyze method code using tree API
accept(mv);
}
};
}
};
cr.accept(cv, true);
</pre>
<p>
Several strategies can be used to construct method code from scratch. The first
option is to create a MethodNode, and then create XxxInsnNode instances and
add them to the instructions list:
</p>
<pre>
MethodNode m = new MethodNode(...);
m.instructions.add(new VarInsnNode(ALOAD, 0));
...
</pre>
<p>
Alternatively, you can use the fact that MethodNode is a MethodVisitor, and use
that to create the XxxInsnNode and add them to the instructions list through
the standard MethodVisitor methods:
</p>
<pre>
MethodNode m = new MethodNode(...);
m.visitVarInsn(ALOAD, 0);
...
</pre>
<p>
If you cannot generate all the instructions in sequential order, i.e. if you
need to save some pointer in the instruction list and then insert instructions
at that place after other instructions have been generated, you can use InsnList
methods insert() and insertBefore() to insert instructions at a saved pointer.
</p>
<pre>
MethodNode m = new MethodNode(...);
m.visitVarInsn(ALOAD, 0);
AbstractInsnNode ptr = m.instructions.getLast();
m.visitVarInsn(ALOAD, 1);
// inserts an instruction between ALOAD 0 and ALOAD 1
m.instructions.insert(ptr, new VarInsnNode(ALOAD, 0));
...
</pre>
<p>
If you need to insert instructions while iterating over an existing instruction
list, you can also use several strategies. The first one is to use a
ListIterator over the instruction list:
</p>
<pre>
ListIterator it = m.instructions.iterator();
while (it.hasNext()) {
AbstractInsnNode n = (AbstractInsnNode) it.next();
if (...) {
it.add(new VarInsnNode(ALOAD, 0));
}
}
</pre>
<p>
It is also possible to convert an instruction list into an array and iterate trough
array elements:
</p>
<pre>
AbstractInsnNode[] insns = m.instructions.toArray();
for(int i = 0; i&lt;insns.length; i++) {
AbstractInsnNode n = insns[i];
if (...) {
m.instructions.insert(n, new VarInsnNode(ALOAD, 0));
}
}
</pre>
<p>
If you want to insert these instructions through the MethodVisitor methods,
you can use another instance of MethodNode as a MethodVisitor and then
insert instructions collected by that instance into the instruction list.
For example:
</p>
<pre>
AbstractInsnNode[] insns = m.instructions.toArray();
for(int i = 0; i&lt;insns.length; i++) {
AbstractInsnNode n = insns[i];
if (...) {
MethodNode mn = new MethodNode();
mn.visitVarInsn(ALOAD, 0);
mn.visitVarInsn(ALOAD, 1);
m.instructions.insert(n, mn.instructions);
}
}
</pre>
<p>
@since ASM 1.3.3
</p>
</body>
</html>